载入中...
搜索中...
未找到
VolumeFluidStateCodec.cpp
浏览该文件的文档.
1#include "fluids/VolumeFluidCodecInternal.inc"
2
3namespace eve::fluids {
6 try {
7 auto migrated = value;
8 const auto* version = value.find("version");
9 if (version && version->isInt64() && version->asInt() == 1) {
10 const auto* source = value.find("colliders");
11 if (!source || !source->isArray() || source->arraySize() > 1024)
12 throw std::runtime_error("fluids.volume/colliders");
13 Value::Array colliders;
14 for (size_t i = 0; i < source->arraySize(); ++i) {
15 auto collider = source->at(i);
16 if (!collider.isObject() || collider.find("rotation") || collider.find("angularVelocity"))
17 throw std::runtime_error("fluids.volume/colliders");
18 collider.set("rotation", pack(glm::vec4(0, 0, 0, 1)));
19 collider.set("angularVelocity", pack(glm::vec3(0.f)));
20 colliders.push_back(std::move(collider));
21 }
22 migrated.set("colliders", Value(std::move(colliders)));
23 migrated.set("version", 2);
24 }
25 const auto* migratedVersion = migrated.find("version");
26 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 2) {
27 if (migrated.find("attachments")) throw std::runtime_error("fluids.volume/attachments");
28 migrated.set("attachments", Value(Value::Array{}));
29 migrated.set("version", 3);
30 }
31 migratedVersion = migrated.find("version");
32 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 3) {
33 const auto* source = migrated.find("particles");
34 if (!source || !source->isArray() || source->arraySize() > 65536)
35 throw std::runtime_error("fluids.volume/particles");
36 Value::Array particles;
37 particles.reserve(source->arraySize());
38 for (size_t i = 0; i < source->arraySize(); ++i) {
39 auto particle = source->at(i);
40 if (!particle.isObject() || particle.find("collisionFilter"))
41 throw std::runtime_error("fluids.volume/particles");
42 particle.set("collisionFilter", int64_t(0xffff0001u));
43 particles.push_back(std::move(particle));
44 }
45 migrated.set("particles", Value(std::move(particles)));
46 migrated.set("version", 4);
47 }
48 migratedVersion = migrated.find("version");
49 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 4) {
50 const auto* source = migrated.find("particles");
51 const auto* settings = migrated.find("settings");
52 const auto* spacing = settings && settings->isObject() ? settings->find("spacing") : nullptr;
53 if (!source || !source->isArray() || source->arraySize() > 65536 || !spacing || !spacing->isNumeric())
54 throw std::runtime_error("fluids.volume/particles");
55 const float radius = float(spacing->isInt64() ? spacing->asInt() : spacing->asDouble()) * .5f;
56 Value::Array particles;
57 particles.reserve(source->arraySize());
58 for (size_t i = 0; i < source->arraySize(); ++i) {
59 auto particle = source->at(i);
60 if (!particle.isObject() || particle.find("radii") || particle.find("orientation"))
61 throw std::runtime_error("fluids.volume/particles");
62 particle.set("radii", pack(glm::vec3(radius)));
63 particle.set("orientation", pack(glm::vec4(0, 0, 0, 1)));
64 particles.push_back(std::move(particle));
65 }
66 migrated.set("particles", Value(std::move(particles)));
67 migrated.set("version", 5);
68 }
69 migratedVersion = migrated.find("version");
70 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 5) {
71 const auto* particles = migrated.find("particles");
72 const auto* colliders = migrated.find("colliders");
73 const auto* source = migrated.find("attachments");
74 if (!particles || !particles->isArray() || !colliders || !colliders->isArray() || !source ||
75 !source->isArray())
76 throw std::runtime_error("fluids.volume/attachments");
77 Value::Array attachments;
78 attachments.reserve(source->arraySize());
79 for (size_t i = 0; i < source->arraySize(); ++i) {
80 auto attachment = source->at(i);
81 if (!attachment.isObject() || attachment.find("localOrientation"))
82 throw std::runtime_error("fluids.volume/attachments");
83 const auto* index = attachment.find("particleIndex");
84 const auto* label = attachment.find("colliderLabel");
85 if (!index || !index->isInt64() || index->asInt() < 0 ||
86 size_t(index->asInt()) >= particles->arraySize() || !label || !label->isInt64())
87 throw std::runtime_error("fluids.volume/attachments");
88 const auto* particleOrientation = particles->at(size_t(index->asInt())).find("orientation");
89 const Value* colliderRotation = nullptr;
90 for (size_t j = 0; j < colliders->arraySize(); ++j) {
91 const auto* candidate = colliders->at(j).find("label");
92 if (candidate && candidate->isInt64() && candidate->asInt() == label->asInt()) {
93 colliderRotation = colliders->at(j).find("rotation");
94 break;
95 }
96 }
97 if (!particleOrientation || !colliderRotation) throw std::runtime_error("fluids.volume/attachments");
98 glm::vec4 particleQ, colliderQ;
99 unpack(*particleOrientation, particleQ, "fluids.volume/particles/orientation");
100 unpack(*colliderRotation, colliderQ, "fluids.volume/colliders/rotation");
101 const auto world = glm::quat(particleQ.w, particleQ.x, particleQ.y, particleQ.z);
102 const auto frame = glm::quat(colliderQ.w, colliderQ.x, colliderQ.y, colliderQ.z);
103 const auto local = glm::normalize(glm::conjugate(frame) * world);
104 attachment.set("localOrientation", pack(glm::vec4(local.x, local.y, local.z, local.w)));
105 attachments.push_back(std::move(attachment));
106 }
107 migrated.set("attachments", Value(std::move(attachments)));
108 migrated.set("version", 6);
109 }
110 migratedVersion = migrated.find("version");
111 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 6) {
112 if (migrated.find("simplexes")) throw std::runtime_error("fluids.volume/simplexes");
113 migrated.set("simplexes", Value(Value::Array{}));
114 migrated.set("version", 7);
115 }
116 migratedVersion = migrated.find("version");
117 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 7) {
118 const auto* source = migrated.find("colliders");
119 if (!source || !source->isArray() || source->arraySize() > 1024)
120 throw std::runtime_error("fluids.volume/colliders");
121 Value::Array colliders;
122 colliders.reserve(source->arraySize());
123 for (size_t i = 0; i < source->arraySize(); ++i) {
124 auto collider = source->at(i);
125 if (!collider.isObject() || collider.find("collisionFilter"))
126 throw std::runtime_error("fluids.volume/colliders");
127 collider.set("collisionFilter", int64_t(0xffff0001u));
128 colliders.push_back(std::move(collider));
129 }
130 migrated.set("colliders", Value(std::move(colliders)));
131 migrated.set("version", 8);
132 }
133 migratedVersion = migrated.find("version");
134 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 8) {
135 const auto* source = migrated.find("particles");
136 if (!source || !source->isArray() || source->arraySize() > 65536)
137 throw std::runtime_error("fluids.volume/particles");
138 Value::Array particles;
139 particles.reserve(source->arraySize());
140 for (size_t i = 0; i < source->arraySize(); ++i) {
141 auto particle = source->at(i);
142 if (!particle.isObject() || particle.find("actorGroup") || particle.find("selfCollide"))
143 throw std::runtime_error("fluids.volume/particles");
144 particle.set("actorGroup", int64_t(0));
145 particle.set("selfCollide", true);
146 particles.push_back(std::move(particle));
147 }
148 migrated.set("particles", Value(std::move(particles)));
149 migrated.set("version", 9);
150 }
151 migratedVersion = migrated.find("version");
152 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 9) {
153 const auto* source = migrated.find("particles");
154 if (!source || !source->isArray() || source->arraySize() > 65536)
155 throw std::runtime_error("fluids.volume/particles");
156 Value::Array particles;
157 particles.reserve(source->arraySize());
158 for (size_t i = 0; i < source->arraySize(); ++i) {
159 auto particle = source->at(i);
160 auto* material = particle.isObject() ? particle.find("material") : nullptr;
161 if (!material || !material->isObject() || material->find("atmosphericPressure"))
162 throw std::runtime_error("fluids.volume/particles/material");
163 material->set("atmosphericPressure", 0.0);
164 particles.push_back(std::move(particle));
165 }
166 migrated.set("particles", Value(std::move(particles)));
167 migrated.set("version", 10);
168 }
169 migratedVersion = migrated.find("version");
170 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 10) {
171 const auto* source = migrated.find("particles");
172 if (!source || !source->isArray() || source->arraySize() > 65536)
173 throw std::runtime_error("fluids.volume/particles");
174 Value::Array particles;
175 particles.reserve(source->arraySize());
176 for (size_t i = 0; i < source->arraySize(); ++i) {
177 auto particle = source->at(i);
178 auto* material = particle.isObject() ? particle.find("material") : nullptr;
179 if (!material || !material->isObject() || material->find("smoothing"))
180 throw std::runtime_error("fluids.volume/particles/material");
181 material->set("smoothing", 2.0);
182 particles.push_back(std::move(particle));
183 }
184 migrated.set("particles", Value(std::move(particles)));
185 migrated.set("version", 11);
186 }
187 migratedVersion = migrated.find("version");
188 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 11) {
189 const auto* source = migrated.find("particles");
190 if (!source || !source->isArray() || source->arraySize() > 65536)
191 throw std::runtime_error("fluids.volume/particles");
192 Value::Array particles;
193 particles.reserve(source->arraySize());
194 for (size_t i = 0; i < source->arraySize(); ++i) {
195 auto particle = source->at(i);
196 auto* material = particle.isObject() ? particle.find("material") : nullptr;
197 if (!material || !material->isObject() || particle.find("angularVelocity") ||
198 material->find("rollingContacts") || material->find("rollingFriction"))
199 throw std::runtime_error("fluids.volume/particles/material");
200 particle.set("angularVelocity", pack(glm::vec3(0.f)));
201 material->set("rollingContacts", false);
202 material->set("rollingFriction", 0.0);
203 particles.push_back(std::move(particle));
204 }
205 migrated.set("particles", Value(std::move(particles)));
206 migrated.set("version", 12);
207 }
208 migratedVersion = migrated.find("version");
209 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 12) {
210 const auto* source = migrated.find("particles");
211 if (!source || !source->isArray() || source->arraySize() > 65536)
212 throw std::runtime_error("fluids.volume/particles");
213 Value::Array particles;
214 particles.reserve(source->arraySize());
215 for (size_t i = 0; i < source->arraySize(); ++i) {
216 auto particle = source->at(i);
217 auto* material = particle.isObject() ? particle.find("material") : nullptr;
218 if (!material || !material->isObject() || material->find("dynamicFriction") ||
219 material->find("staticFriction"))
220 throw std::runtime_error("fluids.volume/particles/material");
221 material->set("dynamicFriction", 0.2);
222 material->set("staticFriction", 0.2);
223 particles.push_back(std::move(particle));
224 }
225 migrated.set("particles", Value(std::move(particles)));
226 migrated.set("version", 13);
227 }
228 migratedVersion = migrated.find("version");
229 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 13) {
230 if (migrated.find("sdfColliders")) throw std::runtime_error("fluids.volume/sdfColliders");
231 migrated.set("sdfColliders", Value(Value::Array{}));
232 migrated.set("version", 14);
233 }
234 migratedVersion = migrated.find("version");
235 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 14) {
236 if (migrated.find("heightFieldColliders")) throw std::runtime_error("fluids.volume/heightFieldColliders");
237 migrated.set("heightFieldColliders", Value(Value::Array{}));
238 migrated.set("version", 15);
239 }
240 migratedVersion = migrated.find("version");
241 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 15) {
242 for (const char* field : {"colliders", "sdfColliders", "heightFieldColliders"}) {
243 const auto* source = migrated.find(field);
244 if (!source || !source->isArray()) throw std::runtime_error(std::string("fluids.volume/") + field);
245 Value::Array colliders;
246 colliders.reserve(source->arraySize());
247 for (size_t i = 0; i < source->arraySize(); ++i) {
248 auto collider = source->at(i);
249 if (!collider.isObject() || collider.find("isTrigger"))
250 throw std::runtime_error(std::string("fluids.volume/") + field + "/isTrigger");
251 collider.set("isTrigger", false);
252 colliders.push_back(std::move(collider));
253 }
254 migrated.set(field, Value(std::move(colliders)));
255 }
256 migrated.set("version", 16);
257 }
258 migratedVersion = migrated.find("version");
259 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 16) {
260 const auto* sourceParticles = migrated.find("particles");
261 if (!sourceParticles || !sourceParticles->isArray()) throw std::runtime_error("fluids.volume/particles");
262 Value::Array particles;
263 particles.reserve(sourceParticles->arraySize());
264 for (size_t i = 0; i < sourceParticles->arraySize(); ++i) {
265 auto particle = sourceParticles->at(i);
266 auto* material = particle.isObject() ? particle.find("material") : nullptr;
267 if (!material || !material->isObject() || material->find("stickiness") ||
268 material->find("stickDistance") || material->find("frictionCombine") ||
269 material->find("stickinessCombine"))
270 throw std::runtime_error("fluids.volume/particles/material");
271 material->set("stickiness", 0.0);
272 material->set("stickDistance", 0.0);
273 material->set("frictionCombine", 0);
274 material->set("stickinessCombine", 0);
275 particles.push_back(std::move(particle));
276 }
277 migrated.set("particles", Value(std::move(particles)));
278 for (const char* field : {"colliders", "sdfColliders", "heightFieldColliders"}) {
279 const auto* source = migrated.find(field);
280 if (!source || !source->isArray()) throw std::runtime_error(std::string("fluids.volume/") + field);
281 Value::Array colliders;
282 colliders.reserve(source->arraySize());
283 for (size_t i = 0; i < source->arraySize(); ++i) {
284 auto collider = source->at(i);
285 if (!collider.isObject() || collider.find("staticFriction") || collider.find("rollingFriction") ||
286 collider.find("stickiness") || collider.find("stickDistance") ||
287 collider.find("frictionCombine") || collider.find("stickinessCombine") ||
288 collider.find("rollingContacts"))
289 throw std::runtime_error(std::string("fluids.volume/") + field + "/material");
290 collider.set("staticFriction", *collider.find("friction"));
291 collider.set("rollingFriction", 0.0);
292 collider.set("stickiness", 0.0);
293 collider.set("stickDistance", 0.0);
294 collider.set("frictionCombine", 0);
295 collider.set("stickinessCombine", 0);
296 collider.set("rollingContacts", false);
297 colliders.push_back(std::move(collider));
298 }
299 migrated.set(field, Value(std::move(colliders)));
300 }
301 migrated.set("version", 17);
302 }
303 migratedVersion = migrated.find("version");
304 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 17) {
305 const auto* source = migrated.find("attachments");
306 if (!source || !source->isArray()) throw std::runtime_error("fluids.volume/attachments");
307 Value::Array attachments;
308 attachments.reserve(source->arraySize());
309 for (size_t i = 0; i < source->arraySize(); ++i) {
310 auto attachment = source->at(i);
311 if (!attachment.isObject() || attachment.find("constrainOrientation"))
312 throw std::runtime_error("fluids.volume/attachments/constrainOrientation");
313 // All pre-v18 native anchors drove orientation, so migration preserves behavior.
314 attachment.set("constrainOrientation", true);
315 attachments.push_back(std::move(attachment));
316 }
317 migrated.set("attachments", Value(std::move(attachments)));
318 migrated.set("version", 18);
319 }
320 migratedVersion = migrated.find("version");
321 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 18) {
322 const auto* source = migrated.find("attachments");
323 if (!source || !source->isArray()) throw std::runtime_error("fluids.volume/attachments");
324 Value::Array attachments;
325 attachments.reserve(source->arraySize());
326 for (size_t i = 0; i < source->arraySize(); ++i) {
327 auto attachment = source->at(i);
328 if (!attachment.isObject() || attachment.find("dynamic") || attachment.find("compliance") ||
329 attachment.find("breakThreshold"))
330 throw std::runtime_error("fluids.volume/attachments/dynamic");
331 attachment.set("dynamic", false);
332 attachment.set("compliance", 0.0);
333 attachment.set("breakThreshold", 1e12);
334 attachments.push_back(std::move(attachment));
335 }
336 migrated.set("attachments", Value(std::move(attachments)));
337 migrated.set("version", 19);
338 }
339 migratedVersion = migrated.find("version");
340 if (migratedVersion && migratedVersion->isInt64() && migratedVersion->asInt() == 19) {
341 if (migrated.find("stitches")) throw std::runtime_error("fluids.volume/stitches");
342 migrated.set("stitches", Value(Value::Array{}));
343 migrated.set("version", 20);
344 }
345 unpack(migrated, decoded, "fluids.volume");
346 } catch (const std::runtime_error& error) {
348 DiagnosticCode::InvalidArgument, "Invalid, missing or unknown volume-fluid field", error.what()));
349 }
350 auto solver = VolumeFluid::create(decoded.settings);
351 if (!solver) return Result<VolumeFluidSnapshot>::failure(solver.status());
352 auto valid = solver.value()->restore(decoded);
353 if (!valid) return Result<VolumeFluidSnapshot>::failure(valid.status());
354 return Result<VolumeFluidSnapshot>::success(std::move(decoded));
355}
356
357} // namespace eve::fluids
double value
std::string label
std::string local
bool valid
std::string error
Definition Package.cpp:60
World3D * world
float radius
Material * material
TerrainThermalSettings settings
int spacing
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
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
std::vector< Value > Array
Definition Value.h:33
Value & at(std::size_t index)
Return a bounds-checked array element.
Definition Value.cpp:106
Value * find(const std::string &key) noexcept
Return an object member, or nullptr when absent.
Definition Value.cpp:124
static Result< std::unique_ptr< VolumeFluid > > create(const VolumeFluidSettings &settings)
Validates settings before allocating an owning solver; errors publish no state.
GLSL compute kernels for the GPU surface-flow solver.
Definition FluidTarget.h:12
EVENGINE_API_DOMAINS Result< VolumeFluidSnapshot > decodeVolumeFluid(const Value &value)
Strict owning decode; unknown/missing fields, unsupported versions and invalid state are rejected.
Canonical version-20 owning state; older codecs migrate collider, attachment, stitch,...