载入中...
搜索中...
未找到
Weather.cpp
浏览该文件的文档.
1#include "weather/Weather.h"
4
6#include "common/Capability.h"
7
8#include "graphics/Graphics.h"
9#include "graphics/Material.h"
10#include "graphics/Mesh.h"
11#include "graphics/Shader.h"
13
14#include <cmath>
15#include <cstdint>
16#include <cstring>
17#include <string>
18#include <vector>
19
20#include <simplesquirrel/simplesquirrel.hpp>
21
22#include "weather/shaders/weather_vert_spv.inc"
23#include "weather/shaders/weather_frag_spv.inc"
24#include "weather/shaders/bolt_vert_spv.inc"
25#include "weather/shaders/bolt_frag_spv.inc"
26
27namespace eve::weather {
28
29namespace {
30
31// ---- tiny deterministic RNG (no dependency on <random>) ----
32struct Lcg {
33 uint32_t s = 0x9e3779b9u;
34 uint32_t next() {
35 s = s * 1664525u + 1013904223u;
36 return s;
37 }
38 float unit() { return float(next() % 10000u) / 9999.f; } // [0,1]
39 float range(float a, float b) { return a + (b - a) * unit(); }
40};
41
42constexpr int kRainCount = 1600;
43constexpr int kSnowCount = 1400;
44constexpr int kBoltCount = 4;
45
46constexpr float kBoxXZ = 26.f; // half extent on X/Z
47constexpr float kBoxY = 20.f; // fall band height
48
49// Push-constant slots are fixed and must match the shaders and
50// declareWeatherParams(): 0=time 1=windX 2=windZ 3=speed 4=length 5=width
51// 6=intensity 7..9=fog rgb 10=fogDensity 11=flash.
52
53// ---------------------------------------------------------------------------
54// Texture generation
55// ---------------------------------------------------------------------------
56
57// Vertical rain streak: bright core, alpha falloff toward the edges/ends.
58void genRainTexture(std::vector<uint8_t> &rgba) {
59 const int w = 8, h = 32;
60 rgba.resize(size_t(w) * h * 4);
61 for (int y = 0; y < h; ++y) {
62 const float v = (float(y) + 0.5f) / float(h); // 0 top -> 1 bottom
63 const float endFade = 1.f - 2.f * std::fabs(v - 0.5f); // 0 at ends, 1 center
64 for (int x = 0; x < w; ++x) {
65 const float u = (float(x) + 0.5f) / float(w);
66 const float edge = 1.f - 2.f * std::fabs(u - 0.5f); // 0 at sides
67 const float alpha = std::pow(edge, 2.f) * std::pow(endFade, 2.5f);
68 const int i = (y * w + x) * 4;
69 rgba[i + 0] = 255;
70 rgba[i + 1] = 250;
71 rgba[i + 2] = 255;
72 rgba[i + 3] = uint8_t(std::min(255.f, alpha * 255.f));
73 }
74 }
75}
76
77// Soft round snowflake.
78void genSnowTexture(std::vector<uint8_t> &rgba) {
79 const int w = 16, h = 16;
80 rgba.resize(size_t(w) * h * 4);
81 const float cx = (float(w) - 1.f) * 0.5f;
82 const float cy = (float(h) - 1.f) * 0.5f;
83 for (int y = 0; y < h; ++y) {
84 for (int x = 0; x < w; ++x) {
85 const float dx = (float(x) - cx) / cx;
86 const float dy = (float(y) - cy) / cy;
87 const float r = std::sqrt(dx * dx + dy * dy);
88 float alpha = 1.f - r;
89 if (alpha < 0.f) alpha = 0.f;
90 alpha = std::pow(alpha, 2.2f);
91 const int i = (y * w + x) * 4;
92 rgba[i + 0] = 255;
93 rgba[i + 1] = 255;
94 rgba[i + 2] = 255;
95 rgba[i + 3] = uint8_t(std::min(255.f, alpha * 255.f));
96 }
97 }
98}
99
100// ---------------------------------------------------------------------------
101// Mesh builders
102// ---------------------------------------------------------------------------
103
104// A field of billboarded quads. Each quad shares an anchor in inPos; inUV
105// encodes the local offset. `count` quads, `len` = quad height, `width` = width.
106graphics::Mesh *buildFieldMesh(graphics::Graphics *gfx, Lcg &rng, int count, float len,
107 float width) {
108 (void)len;
109 (void)width;
110 const int vertCount = count * 4;
111 const int idxCount = count * 6;
112 std::vector<float> pos(vertCount * 3);
113 std::vector<float> nrm(vertCount * 3, 0.f);
114 std::vector<float> uv(vertCount * 2);
115 std::vector<uint32_t> idx(idxCount);
116
117 for (int i = 0; i < count; ++i) {
118 const float ax = rng.range(-kBoxXZ, kBoxXZ);
119 const float ay = rng.range(0.f, kBoxY);
120 const float az = rng.range(-kBoxXZ, kBoxXZ);
121 const int v0 = i * 4;
122 const int b = v0 * 3, t = v0 * 2;
123
124 // bottom-left / top-left / top-right / bottom-right (uv-driven billboard).
125 pos[b + 0] = ax; pos[b + 1] = ay; pos[b + 2] = az;
126 pos[b + 3] = ax; pos[b + 4] = ay; pos[b + 5] = az;
127 pos[b + 6] = ax; pos[b + 7] = ay; pos[b + 8] = az;
128 pos[b + 9] = ax; pos[b + 10] = ay; pos[b + 11] = az;
129
130 // Pack per-particle variation in the otherwise unused normal.
131 const float lengthScale = rng.range(0.55f, 1.45f);
132 const float widthScale = rng.range(0.65f, 1.25f);
133 const float speedScale = rng.range(0.82f, 1.18f);
134 for (int j = 0; j < 4; ++j) {
135 nrm[b + j * 3 + 0] = lengthScale;
136 nrm[b + j * 3 + 1] = widthScale;
137 nrm[b + j * 3 + 2] = speedScale;
138 }
139
140 // uv.x = horizontal offset, uv.y = vertical offset (in [0,1]).
141 uv[t + 0] = -0.5f; uv[t + 1] = 0.f;
142 uv[t + 2] = -0.5f; uv[t + 3] = 1.f;
143 uv[t + 4] = 0.5f; uv[t + 5] = 1.f;
144 uv[t + 6] = 0.5f; uv[t + 7] = 0.f;
145
146 const uint32_t base = uint32_t(v0);
147 idx[i * 6 + 0] = base + 0;
148 idx[i * 6 + 1] = base + 1;
149 idx[i * 6 + 2] = base + 2;
150 idx[i * 6 + 3] = base + 0;
151 idx[i * 6 + 4] = base + 2;
152 idx[i * 6 + 5] = base + 3;
153 }
154
155 return gfx->newMeshFromArrays(pos.data(), nrm.data(), uv.data(), vertCount, idx.data(),
156 idxCount);
157}
158
159struct Pt {
160 float x = 0, y = 0, z = 0;
161};
162
163void displacePath(std::vector<Pt> &path, Lcg &rng, float amount) {
164 std::vector<Pt> refined;
165 refined.reserve(path.size() * 2 - 1);
166 for (size_t i = 0; i + 1 < path.size(); ++i) {
167 const Pt &a = path[i];
168 const Pt &b = path[i + 1];
169 refined.push_back(a);
170 refined.push_back({(a.x + b.x) * 0.5f + rng.range(-amount, amount),
171 (a.y + b.y) * 0.5f,
172 (a.z + b.z) * 0.5f + rng.range(-amount, amount)});
173 }
174 refined.push_back(path.back());
175 path.swap(refined);
176}
177
178// Fractal midpoint displacement is the classic inexpensive lightning model.
179// Crossed tapered ribbons keep the channel visible from every camera angle.
180graphics::Mesh *buildBoltMesh(graphics::Graphics *gfx, Lcg &rng, Pt top, Pt ground) {
181 std::vector<Pt> pts{top, ground};
182 float displacement = 3.2f;
183 for (int level = 0; level < 5; ++level) {
184 displacePath(pts, rng, displacement);
185 displacement *= 0.48f;
186 }
187
188 std::vector<std::vector<Pt>> paths{pts};
189 const int branchStarts[] = {7, 12, 18, 23};
190 for (int start : branchStarts) {
191 if (start >= int(pts.size()) - 2) continue;
192 const Pt origin = pts[start];
193 const float side = (rng.unit() < 0.5f) ? -1.f : 1.f;
194 Pt tip{origin.x + side * rng.range(2.5f, 5.0f),
195 origin.y - rng.range(2.5f, 5.5f),
196 origin.z + rng.range(-3.5f, 3.5f)};
197 if (tip.y < 0.5f) tip.y = 0.5f;
198 std::vector<Pt> branch{origin, tip};
199 float branchDisp = 1.1f;
200 for (int level = 0; level < 3; ++level) {
201 displacePath(branch, rng, branchDisp);
202 branchDisp *= 0.45f;
203 }
204 paths.push_back(branch);
205 }
206
207 std::vector<Pt> all;
208 std::vector<float> allUv;
209 auto emitStrip = [&](const std::vector<Pt> &path, float wTop, float wBottom, int plane) {
210 const int n = int(path.size()) - 1;
211 for (int i = 0; i < n; ++i) {
212 Pt a = path[i], b = path[i + 1];
213 float sx = plane == 0 ? 1.f : 0.f;
214 float sz = plane == 0 ? 0.f : 1.f;
215 float w = wBottom + (wTop - wBottom) * (float(i) / float(n));
216 Pt p0 = {a.x + sx * w, a.y, a.z + sz * w};
217 Pt p1 = {a.x - sx * w, a.y, a.z - sz * w};
218 Pt p2 = {b.x - sx * w, b.y, b.z - sz * w};
219 Pt p3 = {b.x + sx * w, b.y, b.z + sz * w};
220 all.push_back(p0);
221 all.push_back(p1);
222 all.push_back(p2);
223 all.push_back(p3);
224 allUv.insert(allUv.end(), {-1.f, float(i) / n, 1.f, float(i) / n,
225 1.f, float(i + 1) / n, -1.f, float(i + 1) / n});
226 }
227 };
228
229 const float wMain = 0.20f;
230 for (size_t p = 0; p < paths.size(); ++p) {
231 const float scale = p == 0 ? 1.f : 0.55f;
232 emitStrip(paths[p], wMain * scale, wMain * 0.10f * scale, 0);
233 emitStrip(paths[p], wMain * scale, wMain * 0.10f * scale, 1);
234 }
235
236 const int vertCount = int(all.size());
237 const int idxCount = vertCount / 4 * 6;
238 std::vector<float> pos(vertCount * 3);
239 std::vector<float> nrm(vertCount * 3, 0.f);
240 std::vector<float> uv(vertCount * 2, 0.f);
241 std::vector<uint32_t> idx(idxCount);
242
243 for (int i = 0; i < vertCount; ++i) {
244 pos[i * 3 + 0] = all[i].x;
245 pos[i * 3 + 1] = all[i].y;
246 pos[i * 3 + 2] = all[i].z;
247 nrm[i * 3 + 1] = 1.f;
248 uv[i * 2 + 0] = allUv[i * 2 + 0];
249 uv[i * 2 + 1] = allUv[i * 2 + 1];
250 }
251 for (int q = 0; q < vertCount / 4; ++q) {
252 const uint32_t base = uint32_t(q * 4);
253 idx[q * 6 + 0] = base + 0;
254 idx[q * 6 + 1] = base + 1;
255 idx[q * 6 + 2] = base + 2;
256 idx[q * 6 + 3] = base + 0;
257 idx[q * 6 + 4] = base + 2;
258 idx[q * 6 + 5] = base + 3;
259 }
260
261 return gfx->newMeshFromArrays(pos.data(), nrm.data(), uv.data(), vertCount, idx.data(),
262 idxCount);
263}
264
265} // namespace
266
267// ---------------------------------------------------------------------------
268
271 bool built = false;
272 float time = 0.f;
273 float windOffsetX = 0.f;
274 float windOffsetZ = 0.f;
275
276 // state
277 int preset = 0; // index into kPresetNames
278 float intensity = 0.f; // 0..1
279 float intensityCur = 0.f;
280 float windSpeed = 0.f;
281 float windDirDeg = 0.f;
282 bool snowWindOverride = false;
283 float snowWindX = 0.f, snowWindY = -1.15f, snowWindZ = 0.f;
284 bool lightningEnabled = true;
285 float flash = 0.f;
286 float flashTimer = 0.f;
287 float nextStrike = 4.f;
289 bool pcgMode = false, pcgWeatherEnabled = false, pcgRain = false, pcgSnow = false, pcgWindOverride = false;
290 bool interiorWeather = false;
295
296 // mood
297 float skyR = 0.45f, skyG = 0.53f, skyB = 0.62f;
298 float sunIntensity = 1.f;
299 float fogR = 0.55f, fogG = 0.58f, fogB = 0.62f;
300 float fogDensity = 0.004f;
301
302 // renderables
305 std::vector<graphics::Renderable3D *> bolts;
308 std::vector<graphics::Material *> boltMats;
309 int activeBolt = -1;
310 float boltLife = 0.f;
311 bool boltOnceFired = false;
312
313 Lcg rng;
314};
315
316const char *const Weather::kPresetNames[] = {"clear", "drizzle", "rain", "storm", "snow", "fog", "wind", "blizzard"};
317const int Weather::kPresetCount = 8;
318
319Weather::Weather() : impl_(new Impl()) { cap::addListener<IPhotoModeFieldSink>(this); }
320
321Weather::~Weather() { cap::removeListener<IPhotoModeFieldSink>(this); delete impl_; }
322
323// ---------------------------------------------------------------------------
324// Private setup
325// ---------------------------------------------------------------------------
326
327namespace {
328void pushWeatherParams(graphics::Material *mat, float time, float windX, float windZ,
329 float speed, float length, float width, float intensity,
330 float fogR, float fogG, float fogB, float fogDensity, float flash) {
331 mat->setFloat("uTime", time);
332 mat->setFloat("uWindX", windX);
333 mat->setFloat("uWindZ", windZ);
334 mat->setFloat("uSpeed", speed);
335 mat->setFloat("uLength", length);
336 mat->setFloat("uWidth", width);
337 mat->setFloat("uIntensity", intensity);
338 mat->setFloat("uFogR", fogR);
339 mat->setFloat("uFogG", fogG);
340 mat->setFloat("uFogB", fogB);
341 mat->setFloat("uFogDensity", fogDensity);
342 mat->setFloat("uFlash", flash);
343}
344
345// Declare the push-constant slots on a shader in the exact order above.
346void declareWeatherParams(graphics::Shader *shader) {
347 shader->declareFloat("uTime");
348 shader->declareFloat("uWindX");
349 shader->declareFloat("uWindZ");
350 shader->declareFloat("uSpeed");
351 shader->declareFloat("uLength");
352 shader->declareFloat("uWidth");
353 shader->declareFloat("uIntensity");
354 shader->declareFloat("uFogR");
355 shader->declareFloat("uFogG");
356 shader->declareFloat("uFogB");
357 shader->declareFloat("uFogDensity");
358 shader->declareFloat("uFlash");
359 shader->declareFloat("uKind");
360 shader->declareFloat("uWindOffsetX");
361 shader->declareFloat("uWindOffsetZ");
362}
363} // namespace
364
366 if (impl_->built) return;
367 impl_->built = true;
368 impl_->gfx = gfx;
369 if (!gfx) return;
370
371 // ---- textures ----
372 std::vector<uint8_t> rainRgba, snowRgba;
373 genRainTexture(rainRgba);
374 genSnowTexture(snowRgba);
375 graphics::Texture *rainTex = gfx->newTexture(8, 32, rainRgba.data(), true, true);
376 graphics::Texture *snowTex = gfx->newTexture(16, 16, snowRgba.data(), true, true);
377
378 // ---- shaders (precompiled SPIR-V; runtime GLSL compile is not available on Windows) ----
379 std::vector<uint32_t> wv(weather_vert_spv, weather_vert_spv + weather_vert_spv_count);
380 std::vector<uint32_t> wf(weather_frag_spv, weather_frag_spv + weather_frag_spv_count);
381 std::vector<uint32_t> bv(bolt_vert_spv, bolt_vert_spv + bolt_vert_spv_count);
382 std::vector<uint32_t> bf(bolt_frag_spv, bolt_frag_spv + bolt_frag_spv_count);
383 graphics::Shader *weatherVert = nullptr;
384 graphics::Shader *boltShader = nullptr;
385 if (gfx->getBackendName() == "webgpu") {
390 } else {
391 weatherVert = gfx->newMeshShaderFromSpv(wv, wf);
392 boltShader = gfx->newMeshShaderFromSpv(bv, bf);
393 }
394 declareWeatherParams(weatherVert);
395 declareWeatherParams(boltShader);
396
397 // ---- rain ----
398 graphics::Mesh *rainMesh = buildFieldMesh(gfx, impl_->rng, kRainCount, 0.82f, 0.024f);
399 impl_->rain = graphics::Renderable3D::create();
400 impl_->rain->setMesh(rainMesh);
401 impl_->rainMat = gfx->newMaterial();
402 impl_->rainMat->setAlbedoTexture(rainTex);
403 impl_->rainMat->setShadingModel("unlit");
404 impl_->rainMat->setReceiveLight(false);
405 impl_->rainMat->setReceiveShadow(false);
406 impl_->rainMat->setCastShadow(false);
407 impl_->rainMat->setCastOcclusion(false);
408 impl_->rainMat->setTint(0.72f, 0.80f, 0.88f, 1.0f);
409 impl_->rainMat->setShader(weatherVert);
410 impl_->rain->setMaterial(impl_->rainMat);
411 impl_->rain->setVisible(false);
412
413 // ---- snow ----
414 graphics::Mesh *snowMesh = buildFieldMesh(gfx, impl_->rng, kSnowCount, 0.22f, 0.10f);
415 impl_->snow = graphics::Renderable3D::create();
416 impl_->snow->setMesh(snowMesh);
417 impl_->snowMat = gfx->newMaterial();
418 impl_->snowMat->setAlbedoTexture(snowTex);
419 impl_->snowMat->setShadingModel("unlit");
420 impl_->snowMat->setReceiveLight(false);
421 impl_->snowMat->setReceiveShadow(false);
422 impl_->snowMat->setCastShadow(false);
423 impl_->snowMat->setCastOcclusion(false);
424 impl_->snowMat->setTint(1.0f, 1.0f, 1.0f, 1.0f);
425 impl_->snowMat->setShader(weatherVert);
426 impl_->snow->setMaterial(impl_->snowMat);
427 impl_->snow->setVisible(false);
428
429 // ---- lightning bolts ----
430 for (int i = 0; i < kBoltCount; ++i) {
431 Pt top{impl_->rng.range(-4.f, 4.f), kBoxY, impl_->rng.range(-4.f, 4.f)};
432 Pt ground{impl_->rng.range(-3.f, 3.f), 0.f, impl_->rng.range(-3.f, 3.f)};
433 graphics::Mesh *m = buildBoltMesh(gfx, impl_->rng, top, ground);
434 graphics::Renderable3D *b = graphics::Renderable3D::create();
435 b->setMesh(m);
436 graphics::Material *mm = gfx->newMaterial();
437 mm->setShadingModel("unlit");
438 mm->setReceiveLight(false);
439 mm->setReceiveShadow(false);
440 mm->setCastShadow(false);
441 mm->setTint(1.0f, 1.0f, 1.0f, 1.0f);
442 mm->setShader(boltShader);
443 b->setMaterial(mm);
444 b->setVisible(false);
445 impl_->bolts.push_back(b);
446 impl_->boltMats.push_back(mm);
447 }
448
449 pushWeatherParams(impl_->rainMat, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
450 pushWeatherParams(impl_->snowMat, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f);
451}
452
453// ---------------------------------------------------------------------------
454// Public API
455// ---------------------------------------------------------------------------
456
462 "invalid Pcg weather photo-mode assignment",a.field,{},"weather.photoMode"));};
463 if(a.domain!=PhotoModeDomain::Weather)return bad();
464 if(a.field=="m_pcgWeatherEnabled"){auto*v=std::get_if<bool>(&a.value);if(!v)return bad();impl_->pcgWeatherEnabled=*v;}
465 else if(a.field=="m_pcgWeatherRain"){auto*v=std::get_if<bool>(&a.value);if(!v)return bad();impl_->pcgRain=*v;}
466 else if(a.field=="m_pcgWeatherSnow"){auto*v=std::get_if<bool>(&a.value);if(!v)return bad();impl_->pcgSnow=*v;}
467 else if(a.field=="m_pcgWindSettingsOverride"){auto*v=std::get_if<bool>(&a.value);if(!v)return bad();impl_->pcgWindOverride=*v;}
468 else if(a.field=="m_pcgWindDirection"){auto*v=std::get_if<float>(&a.value);if(!v||!std::isfinite(*v))return bad();impl_->windDirDeg=*v;}
469 else if(a.field=="m_pcgWindSpeed"){auto*v=std::get_if<float>(&a.value);if(!v||!std::isfinite(*v)||*v<0)return bad();impl_->windSpeed=*v;}
470 else return bad();
471 impl_->pcgMode=true;return Result<void>::success();
472}
474bool Weather::getPcgRainEnabled()const{return impl_->pcgRain;}
475bool Weather::getPcgSnowEnabled()const{return impl_->pcgSnow;}
477void Weather::setPreset(const std::string &name) {
478 for (int i = 0; i < kPresetCount; ++i) {
479 if (name == kPresetNames[i]) {
480 impl_->preset = i;
481 impl_->pcgMode = false;
482 return;
483 }
484 }
485}
486
487std::string Weather::getPreset() const { return kPresetNames[impl_->preset]; }
488
490 impl_->intensity = v < 0.f ? 0.f : (v > 1.f ? 1.f : v);
491}
492float Weather::getIntensity() const { return impl_->intensity; }
493
494void Weather::setWindSpeed(float v) { impl_->windSpeed = v < 0.f ? 0.f : v; }
495float Weather::getWindSpeed() const { return impl_->windSpeed; }
496
497void Weather::setWindDirection(float deg) { impl_->windDirDeg = deg; }
498float Weather::getWindDirection() const { return impl_->windDirDeg; }
500 if(!std::isfinite(x)||!std::isfinite(y)||!std::isfinite(z))
502 "Snow wind must be finite","weather.snowWind"));
503 impl_->snowWindOverride=true; impl_->snowWindX=x; impl_->snowWindY=y; impl_->snowWindZ=z;
504 return Result<void>::success();
505}
507bool Weather::hasSnowWind()const{return impl_->snowWindOverride;}
508float Weather::getSnowWindX()const{return impl_->snowWindX;}
509float Weather::getSnowWindY()const{return impl_->snowWindY;}
510float Weather::getSnowWindZ()const{return impl_->snowWindZ;}
511
524
526 const PcgInteriorWeatherVolume& volume, float x, float y, float z) {
527 if (!std::isfinite(x) || !std::isfinite(y) || !std::isfinite(z))
529 DiagnosticCode::InvalidArgument, "sample position must be finite", "weather.interiorVolume"));
530 return setInteriorVolumeState(volume, volume.contains(x, y, z));
531}
532
534 impl_->interiorWeather = false;
536}
542
543void Weather::setLightningEnabled(bool on) { impl_->lightningEnabled = on; }
544bool Weather::isLightningEnabled() const { return impl_->lightningEnabled; }
545
547 if (!impl_->built || impl_->bolts.empty()) return;
548 impl_->activeBolt = impl_->rng.next() % int(impl_->bolts.size());
549 impl_->boltLife = 0.0f;
550 impl_->boltOnceFired = false;
551 impl_->flash = 1.0f;
552 impl_->flashTimer = 0.12f;
553 impl_->nextStrike = 3.0f + impl_->rng.unit() * 6.0f;
554}
555
556float Weather::getFlash() const { return impl_->flash; }
557
558void Weather::setSkyColor(float r, float g, float b) {
559 impl_->skyR = r; impl_->skyG = g; impl_->skyB = b;
560}
561float Weather::getSkyColorR() const { return impl_->skyR; }
562float Weather::getSkyColorG() const { return impl_->skyG; }
563float Weather::getSkyColorB() const { return impl_->skyB; }
564
565void Weather::setSunIntensity(float v) { impl_->sunIntensity = std::clamp(v, 0.f, 1.f); }
566float Weather::getSunIntensity() const { return impl_->sunIntensity; }
567
568void Weather::setFogColor(float r, float g, float b) {
569 impl_->fogR = r; impl_->fogG = g; impl_->fogB = b;
570}
571float Weather::getFogColorR() const { return impl_->fogR; }
572float Weather::getFogColorG() const { return impl_->fogG; }
573float Weather::getFogColorB() const { return impl_->fogB; }
574
575void Weather::setFogDensity(float v) { impl_->fogDensity = v < 0.f ? 0.f : v; }
576float Weather::getFogDensity() const { return impl_->fogDensity; }
577
580
582 const float cloudiness = (impl_->preset >= 1 && impl_->preset <= 3) ? impl_->intensityCur : 0.f;
583 return 0.35f + (1.f - cloudiness) * 0.55f;
584}
585
586// ---------------------------------------------------------------------------
587// Update
588// ---------------------------------------------------------------------------
589
591 if (!impl_->built) init(gfx);
592 if (!impl_->gfx) return;
593 impl_->time += dt;
594
595 // Smooth intensity toward target.
596 const bool pcgPrecipitation=impl_->pcgMode&&impl_->pcgWeatherEnabled&&(impl_->pcgRain||impl_->pcgSnow);
597 const float target = pcgPrecipitation?1.f:impl_->intensity;
598 impl_->intensityCur += (target - impl_->intensityCur) * std::min(1.f, dt * 3.f);
599 if (std::fabs(target - impl_->intensityCur) < 0.002f) impl_->intensityCur = target;
600
601 // Wind vector in world space (dirDeg 0 -> +Z, 90 -> -X).
602 const float rad = impl_->windDirDeg * 0.0174532925f;
603 const float windX = -std::sin(rad) * impl_->windSpeed;
604 const float windZ = std::cos(rad) * impl_->windSpeed;
605
606 // Integrate drift rather than multiplying the current wind by elapsed
607 // time: changing a slider must not teleport the whole particle field.
608 impl_->windOffsetX = std::fmod(impl_->windOffsetX + windX * dt, 52.f);
609 impl_->windOffsetZ = std::fmod(impl_->windOffsetZ + windZ * dt, 52.f);
610 for (auto *mat : {impl_->rainMat, impl_->snowMat}) {
611 mat->setFloat("uWindOffsetX", impl_->windOffsetX);
612 mat->setFloat("uWindOffsetZ", impl_->windOffsetZ);
613 }
614 const float time = impl_->time;
615 const float fogR = impl_->fogR, fogG = impl_->fogG, fogB = impl_->fogB;
616 const float fogD = impl_->fogDensity;
617 const float intensity = impl_->intensityCur;
618
619 // Rain visible for drizzle/rain/storm.
620 const bool windOn = impl_->preset == 6;
621 const bool rainOn = impl_->pcgMode ? (impl_->pcgWeatherEnabled && impl_->pcgRain) :
622 ((impl_->preset >= 1 && impl_->preset <= 3) || windOn);
623 const bool suppressRain = impl_->interiorWeather;
624 impl_->rain->setVisible(rainOn && intensity > 0.01f && !suppressRain);
625 if (rainOn) {
626 const float speed = windOn ? 0.15f : 18.f;
627 impl_->rainMat->setFloat("uKind", windOn ? 2.f : 0.f);
628 pushWeatherParams(impl_->rainMat, time, windX, windZ, speed, windOn ? 9.0f : 0.65f, windOn ? 1.1f : 0.045f,
629 windOn ? intensity * std::min(1.f, impl_->windSpeed / 8.f) * 0.22f : intensity, fogR, fogG,
630 fogB, fogD, 0.f);
631 }
632
633 // Snow.
634 const bool snowOn = impl_->pcgMode ? (impl_->pcgWeatherEnabled && impl_->pcgSnow) :
635 (impl_->preset == 4 || impl_->preset == 7);
636 const bool suppressSnow = impl_->interiorWeather &&
638 impl_->snow->setVisible(snowOn && intensity > 0.01f && !suppressSnow);
639 if (snowOn) {
640 impl_->snowMat->setFloat("uKind", 1.f);
641 pushWeatherParams(impl_->snowMat, time, impl_->snowWindOverride?impl_->snowWindX:windX,
642 impl_->snowWindOverride?impl_->snowWindZ:windZ,
643 impl_->snowWindOverride?-impl_->snowWindY:1.15f, 0.22f, 0.22f, intensity, fogR, fogG, fogB, fogD,
644 0.f);
645 }
646
647 // Lightning during storm.
648 const bool storm = !impl_->pcgMode && impl_->preset == 3;
649 if (storm && impl_->lightningEnabled) {
650 impl_->nextStrike -= dt;
651 if (impl_->nextStrike <= 0.f && impl_->activeBolt < 0) strike();
652 }
653
654 // Drive the active bolt's flash decay.
655 if (impl_->activeBolt >= 0) {
656 impl_->boltLife += dt;
657 impl_->flashTimer -= dt;
658 // Return-stroke profile: bright leader, dark gap, weaker second pulse.
659 float f;
660 if (impl_->boltLife < 0.055f) {
661 f = 1.f - impl_->boltLife * 4.f;
662 } else if (impl_->boltLife < 0.095f) {
663 f = 0.06f;
664 } else if (impl_->boltLife < 0.19f) {
665 f = 0.72f * (1.f - (impl_->boltLife - 0.095f) / 0.095f);
666 } else {
667 f = std::max(0.f, 0.22f * (1.f - (impl_->boltLife - 0.19f) / 0.31f));
668 }
669 impl_->flash = std::clamp(f, 0.f, 1.f);
670
671 const int bi = impl_->activeBolt;
672 impl_->bolts[bi]->setVisible(impl_->flash > 0.02f);
673 pushWeatherParams(impl_->boltMats[bi], time, windX, windZ, 0.f, 0.f, 0.f, 1.f, fogR, fogG,
674 fogB, fogD, impl_->flash);
675
676 if (impl_->boltLife > 0.50f) {
677 impl_->bolts[bi]->setVisible(false);
678 impl_->activeBolt = -1;
679 impl_->flash = 0.f;
680 }
681 } else {
682 impl_->flash *= std::max(0.f, 1.f - dt * 8.f);
683 }
684
685 // Push ambient/sky mood onto the graphics state each frame.
686 if (gfx && impl_->environmentEnabled) {
687 const float cloudiness = (impl_->preset >= 1 && impl_->preset <= 3) ? impl_->intensityCur : 0.f;
688 const float dark = 1.f - 0.35f * cloudiness;
689 const float skyFlash = impl_->flash * 0.55f;
691 std::min(1.f, impl_->skyR * dark + skyFlash * 0.68f),
692 std::min(1.f, impl_->skyG * dark + skyFlash * 0.78f),
693 std::min(1.f, impl_->skyB * dark + skyFlash), 1.f);
694 const float flashLight = impl_->flash * 1.35f;
695 gfx->setDirectionalLight(-0.4f, 0.75f, 0.5f,
696 impl_->sunIntensity * (1.f - 0.35f * cloudiness) + flashLight * 0.72f,
697 impl_->sunIntensity * (1.f - 0.35f * cloudiness) * 0.95f + flashLight * 0.84f,
698 impl_->sunIntensity * (1.f - 0.35f * cloudiness) * 0.88f + flashLight);
699 }
700}
701
702// ---------------------------------------------------------------------------
703// Script binding
704// ---------------------------------------------------------------------------
705
706void Weather::expose(ssq::Table &table) {
707 auto cls = table.addClass(name, Weather::create, false);
708 expose(cls);
709 auto interior = table.addClass("PcgInteriorWeatherVolume", ssq::Class::Ctor<PcgInteriorWeatherVolume()>());
710 interior.addFunc("configureBox", [vm=table.getHandle()](PcgInteriorWeatherVolume* self,
711 float x,float y,float z,float sx,float sy,float sz,int mode,int insideReverb,int outsideReverb) {
712 return eve::script::projectResult(vm,self->configureBox(x,y,z,sx,sy,sz,mode,insideReverb,outsideReverb));
713 });
714 interior.addFunc("configureSphere", [vm=table.getHandle()](PcgInteriorWeatherVolume* self,
715 float x,float y,float z,float radius,int mode,int insideReverb,int outsideReverb) {
716 return eve::script::projectResult(vm,self->configureSphere(x,y,z,radius,mode,insideReverb,outsideReverb));
717 });
718 interior.addFunc("contains", [](PcgInteriorWeatherVolume* self,float x,float y,float z) {
719 return self && self->contains(x,y,z);
720 });
721 auto settings = table.addClass("ThunderStrikeSettings", ssq::Class::Ctor<ThunderStrikeSettings()>());
722 settings.addVar("intensity", &ThunderStrikeSettings::intensity);
723 settings.addVar("radius", &ThunderStrikeSettings::radius);
724 settings.addVar("volume", &ThunderStrikeSettings::volume);
725 settings.addVar("audioClipCount", &ThunderStrikeSettings::audioClipCount);
726 auto state = table.addClass("ThunderStrikeState", ssq::Class::Ctor<ThunderStrikeState()>());
727 state.addVar("playing", &ThunderStrikeState::playing);
728 state.addVar("intensity", &ThunderStrikeState::intensity);
729 table.addFunc("triggerThunderStrike", [vm=table.getHandle()](ThunderStrikeState* state,
730 const ThunderStrikeSettings* settings, float x, float y, float z, std::uint32_t seed) {
731 auto result=state&&settings?triggerThunderStrike(*state,*settings,x,y,z,seed)
732 :Result<ThunderStrikeReceipt>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"state and settings required"));
733 return eve::script::projectResult(vm,std::move(result),[](const ThunderStrikeReceipt& value) {
734 return Value::Object{{"x",value.x},{"y",value.y},{"z",value.z},{"intensity",value.intensity},
735 {"radius",value.radius},{"volume",value.volume},{"audioClipIndex",value.audioClipIndex}};
736 });
737 });
738 table.addFunc("advanceThunderStrike", [vm=table.getHandle()](ThunderStrikeState* state,float dt) {
739 auto result=state?advanceThunderStrike(*state,dt)
740 :Result<void>::failure(Diagnostic::error(DiagnosticCode::InvalidArgument,"state required"));
741 return eve::script::projectResult(vm,std::move(result));
742 });
743}
744
745void Weather::expose(ssq::Class &cls) {
746 cls.addFunc("getName", &Weather::getName);
747 cls.addFunc("init", &Weather::init);
748 cls.addFunc("update", &Weather::update);
749 cls.addFunc("setPreset", &Weather::setPreset);
750 cls.addFunc("getPreset", &Weather::getPreset);
751 cls.addFunc("setIntensity", &Weather::setIntensity);
752 cls.addFunc("getIntensity", &Weather::getIntensity);
753 cls.addFunc("setWindSpeed", &Weather::setWindSpeed);
754 cls.addFunc("getWindSpeed", &Weather::getWindSpeed);
755 cls.addFunc("setWindDirection", &Weather::setWindDirection);
756 cls.addFunc("getWindDirection", &Weather::getWindDirection);
757 cls.addFunc("setSnowWind",[vm=cls.getHandle()](Weather* self,float x,float y,float z){
758 return eve::script::projectResult(vm,self->setSnowWind(x,y,z));
759 });
760 cls.addFunc("clearSnowWind",&Weather::clearSnowWind);
761 cls.addFunc("hasSnowWind",&Weather::hasSnowWind);
762 cls.addFunc("getSnowWindX",&Weather::getSnowWindX);
763 cls.addFunc("getSnowWindY",&Weather::getSnowWindY);
764 cls.addFunc("getSnowWindZ",&Weather::getSnowWindZ);
765 cls.addFunc("applyInteriorVolume", [vm=cls.getHandle()](Weather* self,
766 const PcgInteriorWeatherVolume* volume,float x,float y,float z) {
767 auto result = volume ? self->applyInteriorVolume(*volume,x,y,z) :
768 Result<PcgInteriorWeatherTransition>::failure(Diagnostic::error(
769 DiagnosticCode::InvalidArgument,"interior volume required","weather.interiorVolume"));
770 return eve::script::projectResult(vm,std::move(result),[](PcgInteriorWeatherTransition value) {
771 return static_cast<int>(value);
772 });
773 });
774 cls.addFunc("setInteriorVolumeState", [vm=cls.getHandle()](Weather* self,
775 const PcgInteriorWeatherVolume* volume,bool inside) {
776 auto result = volume ? self->setInteriorVolumeState(*volume,inside) :
778 DiagnosticCode::InvalidArgument,"interior volume required","weather.interiorVolume"));
779 return eve::script::projectResult(vm,std::move(result),[](PcgInteriorWeatherTransition value) {
780 return static_cast<int>(value);
781 });
782 });
783 cls.addFunc("clearInteriorWeather",&Weather::clearInteriorWeather);
784 cls.addFunc("isInsideInteriorWeather",&Weather::isInsideInteriorWeather);
785 cls.addFunc("isInteriorWeatherCollisionRequested",&Weather::isInteriorWeatherCollisionRequested);
786 cls.addFunc("getCurrentWeatherReverbPreset",&Weather::getCurrentWeatherReverbPreset);
787 cls.addFunc("setLightningEnabled", &Weather::setLightningEnabled);
788 cls.addFunc("isLightningEnabled", &Weather::isLightningEnabled);
789 cls.addFunc("strike", &Weather::strike);
790 cls.addFunc("getFlash", &Weather::getFlash);
791 cls.addFunc("setSkyColor", &Weather::setSkyColor);
792 cls.addFunc("getSkyColorR", &Weather::getSkyColorR);
793 cls.addFunc("getSkyColorG", &Weather::getSkyColorG);
794 cls.addFunc("getSkyColorB", &Weather::getSkyColorB);
795 cls.addFunc("setSunIntensity", &Weather::setSunIntensity);
796 cls.addFunc("getSunIntensity", &Weather::getSunIntensity);
797 cls.addFunc("setFogColor", &Weather::setFogColor);
798 cls.addFunc("getFogColorR", &Weather::getFogColorR);
799 cls.addFunc("getFogColorG", &Weather::getFogColorG);
800 cls.addFunc("getFogColorB", &Weather::getFogColorB);
801 cls.addFunc("setFogDensity", &Weather::setFogDensity);
802 cls.addFunc("getFogDensity", &Weather::getFogDensity);
803 cls.addFunc("setEnvironmentEnabled", &Weather::setEnvironmentEnabled);
804 cls.addFunc("isEnvironmentEnabled", &Weather::isEnvironmentEnabled);
805 cls.addFunc("getAmbientBrightness", &Weather::getAmbientBrightness);
806}
807
809
810} // namespace eve::weather
LogicalId target
double value
Duration start
SQInteger top
float w
Definition AnimClip.cpp:738
float y
Definition AnimClip.cpp:738
float x
Definition AnimClip.cpp:738
float z
Definition AnimClip.cpp:738
int tip
Definition AnimSmr.cpp:121
double volume
const std::string & s
float cx
Definition CardTypes.cpp:33
float cy
Definition CardTypes.cpp:34
float uv
int ax
Definition CaveMesh.cpp:113
int ay
Definition CaveMesh.cpp:113
float length
Definition CaveMesh.cpp:94
int az
Definition CaveMesh.cpp:113
glm::vec4 p[6]
HSQUIRRELVM vm
Definition ECS.cpp:20
HSQOBJECT cls
Definition ECS.cpp:21
tensor::Graph g
Definition GpuGraph.cpp:7
float u
Definition Grass.cpp:233
glm::vec3 n
Definition Grass.cpp:63
std::array< double, 10 > q
double r
float v
int h
std::uint32_t width
Range range
std::array< float, 3 > scale
std::string name
MeleePoint3 b
Definition MeleeHit.cpp:41
MeleePoint3 a
Definition MeleeHit.cpp:40
int level
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:26
std::string error
Definition Package.cpp:60
int idx
float f
float radius
std::string path
Definition PlayHost.cpp:110
std::uint32_t seed
Definition PointSet.cpp:807
float t
Shader * shader
V3 origin
Definition RoadBake.cpp:138
const RoadEdge * edge
float dy
float dx
std::uint32_t count
The single Squirrel projection for common Result, Status and Value.
TacticalUnit * unit
ecs::EntityHandle side
TerrainThermalSettings settings
std::map< std::string, std::string > paths
std::vector< char > inside
float m[16]
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
virtual std::string getBackendName() const =0
Renderer backend id used by sibling modules (e.g. Gpgpu).
virtual void setDirectionalLight(float dx, float dy, float dz, float r=1.f, float g=1.f, float b=1.f)
Sets the directional light.
Definition Graphics.cpp:248
virtual Shader * newMeshShaderFromSpv(const std::vector< uint32_t > &vertSpv, const std::vector< uint32_t > &fragSpv)=0
Create a Mesh3D custom shader (MeshVertex + Frame UBO + albedo). Empty vert → default mesh3d....
virtual void setBackgroundColorRGBA(float r, float g, float b, float a=1.f)
Sets the background color rgba.
virtual Texture * newTexture(int width, int height, const uint8_t *rgba, bool repeatU=false, bool repeatV=false)=0
Creates a texture. @ownership Caller deletes unless documented otherwise.
Material * newMaterial()
Create a Material asset (shading model + textures + PBR knobs). Caller owns Material*; not tracked by...
Definition Graphics.cpp:252
virtual Shader * newMeshShaderFromWgsl(const std::string &vertWgsl, const std::string &fragWgsl)=0
Create a Mesh3D custom shader from WGSL source (WebGPU backend). The WGSL must declare the engine's F...
Packages shading method + surface parameters into one attachable asset.
Definition Material.h:35
void setAlbedoTexture(Texture *texture)
Set the borrowed material texture. @ownership Graphics factory owns the resource. @lifetime Keep aliv...
Definition Material.h:112
void setCastShadow(bool cast)
Sets the cast shadow.
Definition Material.h:213
void setCastOcclusion(bool cast)
Sets the cast occlusion.
Definition Material.h:223
void setReceiveShadow(bool receive)
Sets the receive shadow.
Definition Material.h:218
void setReceiveLight(bool receive)
Sets the receive light.
Definition Material.h:208
void setShadingModel(const std::string &model)
"pbr" | "unlit" | "hair" | "custom" (unknown → pbr).
Definition Material.cpp:49
void setTint(float r, float g, float b, float a=1.f)
Sets the tint.
Definition Material.cpp:67
void setFloat(const std::string &name, float value)
Sets the float.
Definition Material.cpp:150
void setShader(Shader *shader)
Set an optional Mesh3D / hair shader; nullptr selects the built-in shading path.
Definition Material.h:163
GPU mesh handle (+ optional CPU morph targets).
Definition Mesh.h:25
EVENGINE_API_BACKENDS public API.
void setMaterial(Material *material)
Attach a Material that packages shading method + surface params.
void setVisible(bool visible)
Custom GPU program.
Definition Shader.h:39
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:18
Caller-owned, immutable-after-configuration Pcg interior-weather volume. @ownership This value owns a...
bool contains(float x, float y, float z) const noexcept
Return whether a finite world-space position lies inside, including the boundary.
Weather module — real-time precipitation / lightning / wind system.
Definition Weather.h:36
static const char *const kPresetNames[]
Definition Weather.h:55
void setSunIntensity(float v)
Sets the sun intensity.
Definition Weather.cpp:565
float getFogColorB() const
Returns the fog color b.
Definition Weather.cpp:573
void clearInteriorWeather()
Clear interior state and restore the last sampled exterior reverb preset.
Definition Weather.cpp:533
static const int kPresetCount
Definition Weather.h:56
float getFogDensity() const
Returns the fog density.
Definition Weather.cpp:576
void setWindSpeed(float v)
Sets the wind speed.
Definition Weather.cpp:494
float getSnowWindY() const
Returns the snow wind y.
Definition Weather.cpp:509
void init(graphics::Graphics *gfx)
Idempotent; builds meshes/shaders on first call.
Definition Weather.cpp:365
Result< void > setSnowWind(float x, float y, float z)
Override snow world velocity exactly as Pcg SnowWindDir.
Definition Weather.cpp:499
void setLightningEnabled(bool on)
Sets the lightning enabled.
Definition Weather.cpp:543
void setIntensity(float v)
Sets the intensity.
Definition Weather.cpp:489
bool getPcgWindOverride() const
Return whether photo mode overrides the captured wind.
Definition Weather.cpp:476
float getFogColorG() const
Returns the fog color g.
Definition Weather.cpp:572
void strike()
Force a bolt strike this frame (useful for manual testing).
Definition Weather.cpp:546
void setSkyColor(float r, float g, float b)
Sets the sky color.
Definition Weather.cpp:558
float getWindDirection() const
Returns the wind direction.
Definition Weather.cpp:498
void clearSnowWind()
Return to horizontal wind plus the native default fall speed.
Definition Weather.cpp:506
bool getPcgSnowEnabled() const
Return Pcg's independent snow playback state.
Definition Weather.cpp:475
Result< PcgInteriorWeatherTransition > setInteriorVolumeState(const PcgInteriorWeatherVolume &volume, bool inside)
Apply a trigger-driven enter/exit event without retaining the volume.
Definition Weather.cpp:512
void setFogDensity(float v)
Sets the fog density.
Definition Weather.cpp:575
std::string getPreset() const
Returns the preset.
Definition Weather.cpp:487
void setEnvironmentEnabled(bool enabled)
Enable legacy weather-owned sky and directional lighting.
Definition Weather.cpp:578
float getFogColorR() const
Returns the fog color r.
Definition Weather.cpp:571
int getCurrentWeatherReverbPreset() const
Returns the current weather reverb preset.
Definition Weather.cpp:541
float getSunIntensity() const
Returns the sun intensity.
Definition Weather.cpp:566
float getSkyColorG() const
Returns the sky color g.
Definition Weather.cpp:562
float getSkyColorB() const
Returns the sky color b.
Definition Weather.cpp:563
float getSnowWindZ() const
Returns the snow wind z.
Definition Weather.cpp:510
Result< PcgInteriorWeatherTransition > applyInteriorVolume(const PcgInteriorWeatherVolume &volume, float x, float y, float z)
Sample a bounds-driven interior volume and atomically apply an enter/exit transition.
Definition Weather.cpp:525
bool isInteriorWeatherCollisionRequested() const
True when interior weather collision requested.
Definition Weather.cpp:538
float getSnowWindX() const
Returns the snow wind x.
Definition Weather.cpp:508
void setPreset(const std::string &name)
Sets the preset.
Definition Weather.cpp:477
bool isLightningEnabled() const
True when lightning enabled.
Definition Weather.cpp:544
float getWindSpeed() const
Returns the wind speed.
Definition Weather.cpp:495
float getFlash() const
How bright the current flash is (0..1), sampled by the scene for a key light.
Definition Weather.cpp:556
float getAmbientBrightness() const
Ambient multiplier that the example should feed into camera.setAmbient().
Definition Weather.cpp:581
PhotoModeFieldAcceptance acceptsPhotoModeField(const PhotoModeAssignment &assignment) const noexcept override
Return whether this module owns a Pcg weather photo-mode field.
Definition Weather.cpp:457
void update(float dt, graphics::Graphics *gfx)
Advance sim + push per-frame uniforms; must run before gfx.render3D().
Definition Weather.cpp:590
void setFogColor(float r, float g, float b)
Sets the fog color.
Definition Weather.cpp:568
bool hasSnowWind() const
Return whether a Pcg snow velocity override is active.
Definition Weather.cpp:507
float getIntensity() const
Returns the intensity.
Definition Weather.cpp:492
void setWindDirection(float degrees)
Wind direction in degrees; 0 = toward +Z, 90 = toward -X.
Definition Weather.cpp:497
bool isInsideInteriorWeather() const
True when inside interior weather.
Definition Weather.cpp:537
float getSkyColorR() const
Returns the sky color r.
Definition Weather.cpp:561
bool isEnvironmentEnabled() const
True when environment enabled.
Definition Weather.cpp:579
bool getPcgRainEnabled() const
Return Pcg's independent rain playback state.
Definition Weather.cpp:474
bool getPcgWeatherEnabled() const
Return Pcg's master weather-enabled state.
Definition Weather.cpp:473
~Weather() override
Weather.
Definition Weather.cpp:321
Result< void > applyPhotoModeField(const PhotoModeAssignment &assignment) override
Atomically apply one Pcg weather field to this authoritative weather state.
Definition Weather.cpp:460
constexpr HexDirection next(HexDirection d) noexcept
The next direction clockwise (NW wraps to NE).
Definition HexMetrics.h:76
ssq::Table projectResult(HSQUIRRELVM vm, Result< void > &&result)
Consume and project a void native Result using the common schema.
constexpr const char * kWeatherFragWgsl
Definition WeatherWgsl.h:54
constexpr const char * kWeatherVertWgsl
Definition WeatherWgsl.h:5
constexpr const char * kBoltFragWgsl
Definition WeatherWgsl.h:86
constexpr const char * kBoltVertWgsl
Definition WeatherWgsl.h:82
PcgInteriorWeatherMode
Interior precipitation policy mirrored from Pcg.
Result< void > advanceThunderStrike(ThunderStrikeState &state, float dt)
Apply Pcg's clamped Lerp(intensity,0,dt*2) decay and 0.15 stop threshold.
DiagnosticCode
Stable machine-readable diagnostic codes.
Definition Diagnostic.h:47
PhotoModeFieldAcceptance
Capability implemented by the composition root that routes assignments to domain owners.
bool enabled
One reversible field assignment in a photo-mode transaction.
graphics::Renderable3D * rain
Definition Weather.cpp:303
graphics::Renderable3D * snow
Definition Weather.cpp:304
graphics::Material * rainMat
Definition Weather.cpp:306
PcgInteriorWeatherMode interiorMode
Definition Weather.cpp:291
graphics::Graphics * gfx
Definition Weather.cpp:270
std::vector< graphics::Renderable3D * > bolts
Definition Weather.cpp:305
std::vector< graphics::Material * > boltMats
Definition Weather.cpp:308
graphics::Material * snowMat
Definition Weather.cpp:307