载入中...
搜索中...
未找到
DiffuseLightProbeRegistry.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <cmath>
5#include <glm/common.hpp>
6#include <glm/geometric.hpp>
7
8namespace eve::graphics {
9
10namespace {
11
12constexpr float kGridEpsilon = 1e-4f;
13
14bool sameCoordinate(float a, float b) { return std::abs(a - b) <= kGridEpsilon; }
15
16void appendCoordinate(std::vector<float>& values, float value) {
17 if (std::none_of(values.begin(), values.end(), [value](float existing) {
18 return sameCoordinate(existing, value);
19 }))
20 values.push_back(value);
21}
22
23void writeProbe(DiffuseLightProbeVolumeSample& volume, int index, const eve::ProcgenProbeDesc& probe) {
24 volume.positions[static_cast<size_t>(index)] = glm::vec4(probe.x, probe.y, probe.z, 1.f);
25 volume.extents[static_cast<size_t>(index)] = glm::vec4(probe.extentX, probe.extentY, probe.extentZ, 0.f);
26 if (probe.hasSphericalHarmonics) {
27 for (int coefficient = 0; coefficient < 9; ++coefficient) {
28 const size_t source = static_cast<size_t>(coefficient * 3);
29 volume.coefficients[static_cast<size_t>(index * 9 + coefficient)] = glm::vec4(
31 probe.sphericalHarmonics[source + 2], 0.f);
32 }
33 } else {
34 constexpr float kY00 = 0.2820947918f;
35 volume.coefficients[static_cast<size_t>(index * 9)] = glm::vec4(
36 probe.irradianceR / kY00, probe.irradianceG / kY00, probe.irradianceB / kY00, 0.f);
37 }
38}
39
40bool bracketAxis(const std::vector<float>& sorted, float position, float singletonExtent,
41 std::array<float, 2>& bounds, int& count) {
42 if (sorted.empty()) return false;
43 if (sorted.size() == 1) {
44 if (std::abs(position - sorted.front()) > singletonExtent + kGridEpsilon) return false;
45 bounds[0] = sorted.front();
46 count = 1;
47 return true;
48 }
49 auto upper = std::lower_bound(sorted.begin(), sorted.end(), position - kGridEpsilon);
50 if (upper == sorted.end()) return false;
51 if (sameCoordinate(*upper, position)) {
52 bounds[0] = *upper;
53 count = 1;
54 return true;
55 }
56 if (upper == sorted.begin()) return false;
57 bounds[0] = *(upper - 1);
58 bounds[1] = *upper;
59 count = 2;
60 return true;
61}
62
63} // namespace
64
69
70void DiffuseLightProbeRegistry::replaceBatch(const std::string& batchId,
71 const std::vector<eve::ProcgenProbeDesc>& probes) {
72 batches_.insert_or_assign(batchId, probes);
73}
74
75void DiffuseLightProbeRegistry::removeBatch(const std::string& batchId) { batches_.erase(batchId); }
76
78 struct Candidate {
79 float weight;
81 };
82 std::vector<Candidate> candidates;
83 for (const auto& [_, probes] : batches_) {
84 for (const auto& probe : probes) {
85 const glm::vec3 extent(probe.extentX, probe.extentY, probe.extentZ);
86 const glm::vec3 delta = glm::abs(position - glm::vec3(probe.x, probe.y, probe.z));
87 if (delta.x > extent.x || delta.y > extent.y || delta.z > extent.z) continue;
88 const float normalized = glm::length(delta / extent);
89 Candidate candidate{1.f / std::max(0.01f, normalized), {}};
90 if (probe.hasSphericalHarmonics) {
91 for (size_t coefficient = 0; coefficient < 9; ++coefficient) {
92 const size_t base = coefficient * 3;
93 candidate.sample.coefficients[coefficient] = glm::vec4(
94 probe.sphericalHarmonics[base], probe.sphericalHarmonics[base + 1],
95 probe.sphericalHarmonics[base + 2], 0.f);
96 }
97 } else {
98 constexpr float kY00 = 0.2820947918f;
99 candidate.sample.coefficients[0] = glm::vec4(
100 probe.irradianceR / kY00, probe.irradianceG / kY00, probe.irradianceB / kY00, 0.f);
101 }
102 candidates.push_back(candidate);
103 }
104 }
105 if (candidates.empty())
107 DiagnosticCode::NotFound, "no diffuse light probe influences the sample position", "graphics.lightProbe"));
108 std::stable_sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {
109 return a.weight > b.weight;
110 });
111 const size_t count = std::min(candidates.size(), static_cast<size_t>(std::max(1, maxSamples)));
113 float weightSum = 0.f;
114 for (size_t i = 0; i < count; ++i) {
115 for (size_t coefficient = 0; coefficient < blended.coefficients.size(); ++coefficient)
116 blended.coefficients[coefficient] +=
117 candidates[i].sample.coefficients[coefficient] * candidates[i].weight;
118 weightSum += candidates[i].weight;
119 }
120 for (auto& coefficient : blended.coefficients) coefficient /= weightSum;
122}
123
125 struct GridCandidate {
126 float distanceSquared = 0.f;
128 };
129 std::vector<GridCandidate> grids;
130 for (const auto& [_, probes] : batches_) {
131 if (probes.empty()) continue;
132 std::array<std::vector<float>, 3> axes;
133 glm::vec3 singletonExtent(0.f);
134 for (const auto& probe : probes) {
135 appendCoordinate(axes[0], probe.x);
136 appendCoordinate(axes[1], probe.y);
137 appendCoordinate(axes[2], probe.z);
138 singletonExtent = glm::max(singletonExtent, glm::vec3(probe.extentX, probe.extentY, probe.extentZ));
139 }
140 for (auto& axis : axes) std::sort(axis.begin(), axis.end());
141 std::array<std::array<float, 2>, 3> bounds{};
142 std::array<int, 3> axisCounts{};
143 bool bracketed = true;
144 for (int axis = 0; axis < 3; ++axis)
145 bracketed = bracketed && bracketAxis(axes[axis], position[axis], singletonExtent[axis],
146 bounds[axis], axisCounts[axis]);
147 if (!bracketed) continue;
148
150 bool complete = true;
151 for (int z = 0; z < axisCounts[2] && complete; ++z)
152 for (int y = 0; y < axisCounts[1] && complete; ++y)
153 for (int x = 0; x < axisCounts[0] && complete; ++x) {
154 const auto found = std::find_if(probes.begin(), probes.end(), [&](const auto& probe) {
155 return sameCoordinate(probe.x, bounds[0][x]) &&
156 sameCoordinate(probe.y, bounds[1][y]) &&
157 sameCoordinate(probe.z, bounds[2][z]);
158 });
159 if (found == probes.end()) {
160 complete = false;
161 break;
162 }
163 writeProbe(cell, cell.count++, *found);
164 }
165 if (!complete || cell.count < 2) continue;
166 cell.trilinearCell = true;
167 glm::vec3 center;
168 for (int axis = 0; axis < 3; ++axis)
169 center[axis] = axisCounts[axis] == 2 ? (bounds[axis][0] + bounds[axis][1]) * 0.5f : bounds[axis][0];
170 grids.push_back({glm::dot(position - center, position - center), cell});
171 }
172 if (!grids.empty()) {
173 const auto selected = std::min_element(grids.begin(), grids.end(), [](const auto& a, const auto& b) {
174 return a.distanceSquared < b.distanceSquared;
175 });
176 return Result<DiffuseLightProbeVolumeSample>::success(selected->volume);
177 }
178
179 struct Candidate {
180 float distanceSquared;
181 const eve::ProcgenProbeDesc* probe;
182 };
183 std::vector<Candidate> candidates;
184 for (const auto& [_, probes] : batches_) {
185 for (const auto& probe : probes) {
186 const glm::vec3 extent(probe.extentX, probe.extentY, probe.extentZ);
187 const glm::vec3 probePosition(probe.x, probe.y, probe.z);
188 const glm::vec3 delta = glm::abs(position - probePosition);
189 if (delta.x <= extent.x && delta.y <= extent.y && delta.z <= extent.z)
190 candidates.push_back({glm::dot(delta, delta), &probe});
191 }
192 }
193 if (candidates.empty())
195 DiagnosticCode::NotFound, "no diffuse light probe volume contains the object", "graphics.lightProbe"));
196 std::stable_sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {
197 return a.distanceSquared < b.distanceSquared;
198 });
200 volume.count = static_cast<int>(std::min(candidates.size(), static_cast<size_t>(volume.kMaxProbes)));
201 for (int index = 0; index < volume.count; ++index) {
202 writeProbe(volume, index, *candidates[static_cast<size_t>(index)].probe);
203 }
205}
206
207} // namespace eve::graphics
double value
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
double volume
std::map< std::string, Var > values
std::array< float, 3 > position
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
bool found
std::uint32_t count
Cell cell
uint32_t index
const UnitySourceAsset & source
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Owns generated diffuse probes and samples their baked L0 irradiance.
void removeBatch(const std::string &batchId)
Remove every diffuse probe owned by one generated batch.
void replaceBatch(const std::string &batchId, const std::vector< eve::ProcgenProbeDesc > &probes)
Atomically replace the diffuse probes owned by one generated batch.
static DiffuseLightProbeRegistry & instance()
Return the process-wide graphics-owned registry.
Result< DiffuseLightProbeVolumeSample > selectVolume(const glm::vec3 &position) const
Select an object-local proxy volume; fragment shading performs the spatial interpolation.
Result< DiffuseLightProbeSample > sample(const glm::vec3 &position, int maxSamples) const
Blend up to maxSamples probes whose influence volumes contain position.
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
Definition Animation.h:25
Engine-neutral description of one generated reflection or light probe.
std::array< float, 27 > sphericalHarmonics
DiffuseLightProbeSample public API.
DiffuseLightProbeVolumeSample public API.
glm::vec4 bounds