载入中...
搜索中...
未找到
Volumetric.cpp
浏览该文件的文档.
2
3#include "common/Exception.h"
4#include "graphics/Canvas.h"
6#include "graphics/Drawable.h"
7#include "graphics/Graphics.h"
9#include "graphics/Shader.h"
10#include "graphics/Texture.h"
11#include "graphics/shaders/volumetric_post_frag_spv.inc"
12#include "graphics/shaders/volumetric_raymarch_frag_spv.inc"
13#include "graphics/shaders/volumetric_fog_frag_spv.inc"
14
15#include <algorithm>
16#include <cmath>
17#include <cstdint>
18#include <optional>
19#include <vector>
20
21#include <glm/gtc/matrix_transform.hpp>
22#include <glm/gtc/type_ptr.hpp>
23
24namespace eve::graphics {
25namespace {
26
27Shader *createScreenspaceShader(Graphics *gfx) {
28 if (!gfx) throw eve::Exception("Volumetric: null graphics");
29 std::vector<uint32_t> frag(volumetric_post_frag_spv,
30 volumetric_post_frag_spv + volumetric_post_frag_spv_count);
31 std::vector<uint32_t> vert;
32 Shader *sh = gfx->newShaderFromSpv(vert, frag);
33 sh->declareFloat("lightX");
34 sh->declareFloat("lightY");
35 sh->declareFloat("exposure");
36 sh->declareFloat("decay");
37 sh->declareFloat("density");
38 sh->declareFloat("weight");
39 sh->declareFloat("sampleCount");
40 sh->declareFloat("dustAmount");
41 sh->declareFloat("fogAmount");
42 sh->declareFloat("fogR");
43 sh->declareFloat("fogG");
44 sh->declareFloat("fogB");
45 sh->declareFloat("shaftR");
46 sh->declareFloat("shaftG");
47 sh->declareFloat("shaftB");
48 sh->declareFloat("time");
49 sh->declareFloat("compositeMode");
50 sh->declareFloat("intensity");
51
52 sh->sendFloat("lightX", 0.5f);
53 sh->sendFloat("lightY", 0.35f);
54 sh->sendFloat("exposure", 0.35f);
55 sh->sendFloat("decay", 0.96f);
56 sh->sendFloat("density", 0.85f);
57 sh->sendFloat("weight", 0.55f);
58 sh->sendFloat("sampleCount", 48.f);
59 sh->sendFloat("dustAmount", 0.25f);
60 sh->sendFloat("fogAmount", 0.18f);
61 sh->sendFloat("fogR", 0.55f);
62 sh->sendFloat("fogG", 0.62f);
63 sh->sendFloat("fogB", 0.75f);
64 sh->sendFloat("shaftR", 1.f);
65 sh->sendFloat("shaftG", 0.95f);
66 sh->sendFloat("shaftB", 0.85f);
67 sh->sendFloat("time", 0.f);
68 sh->sendFloat("compositeMode", 0.f);
69 sh->sendFloat("intensity", 1.f);
70 return sh;
71}
72
73Shader *createRayMarchShader(Graphics *gfx) {
74 if (!gfx) throw eve::Exception("Volumetric: null graphics");
75 std::vector<uint32_t> frag(volumetric_raymarch_frag_spv,
76 volumetric_raymarch_frag_spv + volumetric_raymarch_frag_spv_count);
77 std::vector<uint32_t> vert;
78 Shader *sh = gfx->newShaderFromSpv(vert, frag);
79 sh->declareMatrix("invViewProj");
80 sh->declareFloat("lightDx");
81 sh->declareFloat("lightDy");
82 sh->declareFloat("lightDz");
83 sh->declareFloat("density");
84 sh->declareFloat("shaftR");
85 sh->declareFloat("shaftG");
86 sh->declareFloat("shaftB");
87 sh->declareFloat("intensity");
88 sh->declareFloat("nearZ");
89 sh->declareFloat("farZ");
90 sh->declareFloat("sampleCount");
91 sh->declareFloat("dustAmount");
92 sh->declareFloat("fogAmount");
93 sh->declareFloat("shadowSteps");
94 sh->declareFloat("lightU");
95 sh->declareFloat("lightV");
96
97 sh->sendMatrix("invViewProj", glm::mat4(1.f));
98 sh->sendFloat("lightDx", 0.4f);
99 sh->sendFloat("lightDy", 1.f);
100 sh->sendFloat("lightDz", 0.3f);
101 sh->sendFloat("density", 0.35f);
102 sh->sendFloat("shaftR", 1.f);
103 sh->sendFloat("shaftG", 0.95f);
104 sh->sendFloat("shaftB", 0.85f);
105 sh->sendFloat("intensity", 1.f);
106 sh->sendFloat("nearZ", 0.1f);
107 sh->sendFloat("farZ", 100.f);
108 sh->sendFloat("sampleCount", 24.f);
109 sh->sendFloat("dustAmount", 0.25f);
110 sh->sendFloat("fogAmount", 0.2f);
111 sh->sendFloat("shadowSteps", 8.f);
112 sh->sendFloat("lightU", 0.7f);
113 sh->sendFloat("lightV", 0.2f);
114 return sh;
115}
116
117Shader *createFogShader(Graphics *gfx) {
118 if (!gfx) throw eve::Exception("Volumetric: null graphics");
119 std::vector<uint32_t> frag(volumetric_fog_frag_spv,
120 volumetric_fog_frag_spv + volumetric_fog_frag_spv_count);
121 std::vector<uint32_t> vert;
122 Shader *sh = gfx->newShaderFromSpv(vert, frag);
123 sh->declareMatrix("invViewProj");
124 sh->declareFloat("lightDx");
125 sh->declareFloat("lightDy");
126 sh->declareFloat("lightDz");
127 sh->declareFloat("density");
128 sh->declareFloat("fogR");
129 sh->declareFloat("fogG");
130 sh->declareFloat("fogB");
131 sh->declareFloat("intensity");
132 sh->declareFloat("nearZ");
133 sh->declareFloat("farZ");
134 sh->declareFloat("sampleCount");
135 sh->declareFloat("fogHeight");
136 sh->declareFloat("heightFalloff");
137 sh->declareFloat("fogStart");
138 sh->declareFloat("fogEnd");
139 sh->declareFloat("noiseAmount");
140
141 sh->sendMatrix("invViewProj", glm::mat4(1.f));
142 sh->sendFloat("lightDx", 0.4f);
143 sh->sendFloat("lightDy", 1.f);
144 sh->sendFloat("lightDz", 0.3f);
145 sh->sendFloat("density", 0.25f);
146 sh->sendFloat("fogR", 0.55f);
147 sh->sendFloat("fogG", 0.62f);
148 sh->sendFloat("fogB", 0.75f);
149 sh->sendFloat("intensity", 1.f);
150 sh->sendFloat("nearZ", 0.1f);
151 sh->sendFloat("farZ", 100.f);
152 sh->sendFloat("sampleCount", 24.f);
153 sh->sendFloat("fogHeight", 0.f);
154 sh->sendFloat("heightFalloff", 0.15f);
155 sh->sendFloat("fogStart", 2.f);
156 sh->sendFloat("fogEnd", 40.f);
157 sh->sendFloat("noiseAmount", 0.35f);
158 return sh;
159}
160
161} // namespace
162
164 shader_ = createScreenspaceShader(gfx);
165 rayShader_ = createRayMarchShader(gfx);
166 fogShader_ = createFogShader(gfx);
167 applyQualityDefaults();
168}
169
170Volumetric::~Volumetric() = default;
171
172void Volumetric::applyQualityDefaults() {
173 if (quality_ == "low") {
174 downscale_ = 4.f;
175 if (mode_ == "raymarch") {
176 rayShader_->sendFloat("sampleCount", 8.f);
177 rayShader_->sendFloat("shadowSteps", 4.f);
178 rayShader_->sendFloat("dustAmount", 0.12f);
179 rayShader_->sendFloat("fogAmount", 0.12f);
180 } else if (mode_ == "fog") {
181 fogShader_->sendFloat("sampleCount", 8.f);
182 fogShader_->sendFloat("noiseAmount", 0.15f);
183 fogShader_->sendFloat("density", 0.18f);
184 } else {
185 setFloat("sampleCount", 16.f);
186 setFloat("dustAmount", 0.12f);
187 setFloat("fogAmount", 0.10f);
188 setFloat("exposure", 0.40f);
189 }
190 } else if (quality_ == "high") {
191 downscale_ = 1.f;
192 if (mode_ == "raymarch") {
193 rayShader_->sendFloat("sampleCount", 48.f);
194 rayShader_->sendFloat("shadowSteps", 16.f);
195 rayShader_->sendFloat("dustAmount", 0.35f);
196 rayShader_->sendFloat("fogAmount", 0.25f);
197 } else if (mode_ == "fog") {
198 fogShader_->sendFloat("sampleCount", 48.f);
199 fogShader_->sendFloat("noiseAmount", 0.45f);
200 fogShader_->sendFloat("density", 0.32f);
201 } else {
202 setFloat("sampleCount", 96.f);
203 setFloat("dustAmount", 0.35f);
204 setFloat("fogAmount", 0.22f);
205 setFloat("exposure", 0.32f);
206 }
207 } else {
208 quality_ = "medium";
209 downscale_ = 2.f;
210 if (mode_ == "raymarch") {
211 rayShader_->sendFloat("sampleCount", 24.f);
212 rayShader_->sendFloat("shadowSteps", 8.f);
213 rayShader_->sendFloat("dustAmount", 0.25f);
214 rayShader_->sendFloat("fogAmount", 0.2f);
215 } else if (mode_ == "fog") {
216 fogShader_->sendFloat("sampleCount", 24.f);
217 fogShader_->sendFloat("noiseAmount", 0.35f);
218 fogShader_->sendFloat("density", 0.25f);
219 } else {
220 setFloat("sampleCount", 48.f);
221 setFloat("dustAmount", 0.25f);
222 setFloat("fogAmount", 0.18f);
223 setFloat("exposure", 0.35f);
224 }
225 }
226}
227
228void Volumetric::setQuality(const std::string &quality) {
229 quality_ = quality;
230 applyQualityDefaults();
231}
232
233void Volumetric::setMode(const std::string &mode) {
234 if (mode == "raymarch")
235 mode_ = "raymarch";
236 else if (mode == "fog")
237 mode_ = "fog";
238 else
239 mode_ = "screenspace";
240 applyQualityDefaults();
241}
242
243void Volumetric::setLightScreenUV(float u, float v) {
244 setFloat("lightX", u);
245 setFloat("lightY", v);
246 rayShader_->sendFloat("lightU", u);
247 rayShader_->sendFloat("lightV", v);
248}
249
250float Volumetric::getLightScreenU() const { return getFloat("lightX"); }
251float Volumetric::getLightScreenV() const { return getFloat("lightY"); }
252
253void Volumetric::setLightScreenPos(float x, float y, float width, float height) {
254 if (width < 1.f) width = 1.f;
255 if (height < 1.f) height = 1.f;
257}
258
259void Volumetric::setLightDirection(float dx, float dy, float dz) {
260 glm::vec3 d(dx, dy, dz);
261 if (glm::length(d) < 1e-6f) d = glm::vec3(0.f, 1.f, 0.f);
262 else d = glm::normalize(d);
263 lightDir_ = d;
264 rayShader_->sendFloat("lightDx", d.x);
265 rayShader_->sendFloat("lightDy", d.y);
266 rayShader_->sendFloat("lightDz", d.z);
267 fogShader_->sendFloat("lightDx", d.x);
268 fogShader_->sendFloat("lightDy", d.y);
269 fogShader_->sendFloat("lightDz", d.z);
270}
271
272void Volumetric::setInvViewProj(const glm::mat4 &invViewProj) {
273 invViewProj_ = invViewProj;
274 rayShader_->sendMatrix("invViewProj", invViewProj_);
275 fogShader_->sendMatrix("invViewProj", invViewProj_);
276}
277
278void Volumetric::setCamera(float eyeX, float eyeY, float eyeZ, float targetX, float targetY,
279 float targetZ, float upX, float upY, float upZ, float fovYDeg,
280 float aspect, float nearZ, float farZ) {
281 nearZ_ = nearZ > 1e-4f ? nearZ : 0.1f;
282 farZ_ = farZ > nearZ_ ? farZ : nearZ_ + 1.f;
283 const float aspectSafe = aspect > 1e-4f ? aspect : 1.f;
284 const float fovRad = fovYDeg * 0.017453292519943295f;
285 const glm::mat4 view =
286 glm::lookAtRH(glm::vec3(eyeX, eyeY, eyeZ), glm::vec3(targetX, targetY, targetZ),
287 glm::vec3(upX, upY, upZ));
288 const glm::mat4 proj = perspectiveVulkanRH_ZO(fovRad, aspectSafe, nearZ_, farZ_);
289 setInvViewProj(glm::inverse(proj * view));
290 rayShader_->sendFloat("nearZ", nearZ_);
291 rayShader_->sendFloat("farZ", farZ_);
292 fogShader_->sendFloat("nearZ", nearZ_);
293 fogShader_->sendFloat("farZ", farZ_);
294}
295
296void Volumetric::setShaftColor(float r, float g, float b) {
297 setFloat("shaftR", r);
298 setFloat("shaftG", g);
299 setFloat("shaftB", b);
300 rayShader_->sendFloat("shaftR", r);
301 rayShader_->sendFloat("shaftG", g);
302 rayShader_->sendFloat("shaftB", b);
303}
304
305void Volumetric::setFogColor(float r, float g, float b) {
306 setFloat("fogR", r);
307 setFloat("fogG", g);
308 setFloat("fogB", b);
309 fogShader_->sendFloat("fogR", r);
310 fogShader_->sendFloat("fogG", g);
311 fogShader_->sendFloat("fogB", b);
312}
313
314void Volumetric::setIntensity(float intensity) {
315 setFloat("intensity", intensity);
316 rayShader_->sendFloat("intensity", intensity);
317 fogShader_->sendFloat("intensity", intensity);
318}
319
320void Volumetric::setTime(float seconds) { setFloat("time", seconds); }
321
322void Volumetric::setDensity(float density) {
323 setFloat("density", density);
324 rayShader_->sendFloat("density", density);
325 fogShader_->sendFloat("density", density);
326}
327
328void Volumetric::setFogHeight(float worldY) {
329 fogHeight_ = worldY;
330 fogShader_->sendFloat("fogHeight", fogHeight_);
331}
332
334 fogHeightFalloff_ = falloff < 0.f ? 0.f : falloff;
335 fogShader_->sendFloat("heightFalloff", fogHeightFalloff_);
336}
337
338void Volumetric::setFogStart(float startDistance) {
339 fogStart_ = startDistance < 0.f ? 0.f : startDistance;
340 fogShader_->sendFloat("fogStart", fogStart_);
341}
342
343void Volumetric::setFogEnd(float endDistance) {
344 fogEnd_ = endDistance <= fogStart_ ? fogStart_ + 1.f : endDistance;
345 fogShader_->sendFloat("fogEnd", fogEnd_);
346}
347
348void Volumetric::setFogNoise(float amount) {
349 fogNoise_ = amount < 0.f ? 0.f : amount;
350 fogShader_->sendFloat("noiseAmount", fogNoise_);
351}
352
353bool Volumetric::hasParam(const std::string &name) const {
354 return (shader_ && shader_->hasUniform(name)) || (rayShader_ && rayShader_->hasUniform(name)) ||
355 (fogShader_ && fogShader_->hasUniform(name));
356}
357
358void Volumetric::setFloat(const std::string &name, float value) {
359 if (!shader_) throw eve::Exception("Volumetric.setFloat: null shader");
360 if (shader_->hasUniform(name)) shader_->sendFloat(name, value);
361 if (rayShader_ && rayShader_->hasUniform(name)) rayShader_->sendFloat(name, value);
362 if (fogShader_ && fogShader_->hasUniform(name)) fogShader_->sendFloat(name, value);
363}
364
365float Volumetric::getFloat(const std::string &name) const {
366 // Prefer the active mode's shader so quality/sample queries match setMode.
367 if (mode_ == "raymarch" && rayShader_ && rayShader_->hasUniform(name)) {
368 float v = 0.f;
369 if (rayShader_->getFromVar(name, &v, sizeof(v)) == int(sizeof(v))) return v;
370 }
371 if (mode_ == "fog" && fogShader_ && fogShader_->hasUniform(name)) {
372 float v = 0.f;
373 if (fogShader_->getFromVar(name, &v, sizeof(v)) == int(sizeof(v))) return v;
374 }
375 if (shader_ && shader_->hasUniform(name)) {
376 float v = 0.f;
377 if (shader_->getFromVar(name, &v, sizeof(v)) == int(sizeof(v))) return v;
378 }
379 if (rayShader_ && rayShader_->hasUniform(name)) {
380 float v = 0.f;
381 if (rayShader_->getFromVar(name, &v, sizeof(v)) == int(sizeof(v))) return v;
382 }
383 if (fogShader_ && fogShader_->hasUniform(name)) {
384 float v = 0.f;
385 if (fogShader_->getFromVar(name, &v, sizeof(v)) == int(sizeof(v))) return v;
386 }
387 throw eve::Exception("Volumetric.getFloat: missing param '%s'", name.c_str());
388}
389
390int Volumetric::getSampleCount() const { return int(std::lround(getFloat("sampleCount"))); }
391
392int Volumetric::resolutionFor(int fullSize) const {
393 if (fullSize < 1) return 1;
394 const float ds = std::max(downscale_, 1.f);
395 return std::max(1, int(std::floor(float(fullSize) / ds)));
396}
397
398void Volumetric::uploadCommon(bool compositeFromScene) {
399 setFloat("compositeMode", compositeFromScene ? 1.f : 0.f);
400}
401
402void Volumetric::uploadRayMarchCommon() {
403 rayShader_->sendMatrix("invViewProj", invViewProj_);
404 rayShader_->sendFloat("lightDx", lightDir_.x);
405 rayShader_->sendFloat("lightDy", lightDir_.y);
406 rayShader_->sendFloat("lightDz", lightDir_.z);
407 rayShader_->sendFloat("nearZ", nearZ_);
408 rayShader_->sendFloat("farZ", farZ_);
409}
410
411void Volumetric::uploadFogCommon() {
412 fogShader_->sendMatrix("invViewProj", invViewProj_);
413 fogShader_->sendFloat("lightDx", lightDir_.x);
414 fogShader_->sendFloat("lightDy", lightDir_.y);
415 fogShader_->sendFloat("lightDz", lightDir_.z);
416 fogShader_->sendFloat("nearZ", nearZ_);
417 fogShader_->sendFloat("farZ", farZ_);
418 fogShader_->sendFloat("fogHeight", fogHeight_);
419 fogShader_->sendFloat("heightFalloff", fogHeightFalloff_);
420 fogShader_->sendFloat("fogStart", fogStart_);
421 fogShader_->sendFloat("fogEnd", fogEnd_);
422 fogShader_->sendFloat("noiseAmount", fogNoise_);
423}
424
425void Volumetric::drawFullscreen(Graphics *gfx, Texture *source, Shader *shader) {
426 if (!gfx) throw eve::Exception("Volumetric: null graphics");
427 if (!source) throw eve::Exception("Volumetric: null source texture");
428 if (!shader) throw eve::Exception("Volumetric: null shader");
429
430 const float dw = gfx->getCanvas() ? float(gfx->getCanvas()->getWidth()) : float(gfx->getWidth());
431 const float dh =
432 gfx->getCanvas() ? float(gfx->getCanvas()->getHeight()) : float(gfx->getHeight());
433 gfx->drawTexturedRectShader(source, shader, 0.f, 0.f, dw, dh, Color(1.f, 1.f, 1.f, 1.f));
434}
435
436void Volumetric::beginOcclusionMap(Graphics *gfx, float lightPixelX, float lightPixelY,
437 float lightRadiusPixels) {
438 if (!gfx) throw eve::Exception("Volumetric.beginOcclusionMap: null graphics");
439 gfx->clear(Color(0.f, 0.f, 0.f, 1.f), std::nullopt, std::nullopt);
440 const float r = std::max(lightRadiusPixels, 1.f);
441 gfx->drawSolidRect(lightPixelX - r, lightPixelY - r, r * 2.f, r * 2.f,
442 Color(1.f, 1.f, 1.f, 1.f));
443 const float w = gfx->getCanvas() ? float(gfx->getCanvas()->getWidth()) : float(gfx->getWidth());
444 const float h = gfx->getCanvas() ? float(gfx->getCanvas()->getHeight()) : float(gfx->getHeight());
445 setLightScreenPos(lightPixelX, lightPixelY, w, h);
446}
447
448void Volumetric::drawOccluder(Graphics *gfx, Drawable *drawable, const glm::mat4 &matrix) {
449 if (!gfx || !drawable) return;
450 gfx->drawOcclusion(drawable, matrix);
451}
452
453void Volumetric::drawOccluderSolid(Graphics *gfx, float x, float y, float w, float h) {
454 if (!gfx) return;
455 gfx->drawOcclusionSolid(x, y, w, h);
456}
457
458void Volumetric::drawOccluderTexture(Graphics *gfx, Texture *texture, float x, float y, float w,
459 float h) {
460 if (!gfx) return;
461 gfx->drawOcclusionTexture(texture, x, y, w, h);
462}
463
465 if (!gfx) return;
466 if (ecs::current()->getManager<Renderable2D>() == nullptr) return;
467 auto view = ecs::View<Renderable2D, Renderable2D::Transform2D, Renderable2D::Sprite>();
468 for (auto it = view.begin(); it != view.end(); ++it) {
469 auto [xf, sp] = *it;
470 if (!sp->visible || !sp->castOcclusion) continue;
471 const float w = sp->width * (xf->sx == 0.f ? 1.f : xf->sx);
472 const float h = sp->height * (xf->sy == 0.f ? 1.f : xf->sy);
473 if (sp->texture)
474 gfx->drawOcclusionTexture(sp->texture, xf->x, xf->y, w, h);
475 else
476 gfx->drawOcclusionSolid(xf->x, xf->y, w, h);
477 }
478}
479
480void Volumetric::scatter(Graphics *gfx, Texture *occlusion) {
481 uploadCommon(false);
482 drawFullscreen(gfx, occlusion, shader_);
483}
484
485void Volumetric::scatterTo(Graphics *gfx, Texture *occlusion, Canvas *dest) {
486 if (!gfx) throw eve::Exception("Volumetric.scatterTo: null graphics");
487 if (!dest) throw eve::Exception("Volumetric.scatterTo: null dest");
488 Canvas *prev = gfx->getCanvas();
489 gfx->setCanvas(dest);
490 scatter(gfx, occlusion);
491 gfx->setCanvas(prev == gfx ? nullptr : prev);
492}
493
495 uploadCommon(true);
496 drawFullscreen(gfx, scene, shader_);
497}
498
500 if (!gfx) throw eve::Exception("Volumetric.applyFromSceneTo: null graphics");
501 if (!dest) throw eve::Exception("Volumetric.applyFromSceneTo: null dest");
502 Canvas *prev = gfx->getCanvas();
503 gfx->setCanvas(dest);
504 applyFromScene(gfx, scene);
505 gfx->setCanvas(prev == gfx ? nullptr : prev);
506}
507
508void Volumetric::rayMarch(Graphics *gfx, Texture *linearDepth) {
509 uploadRayMarchCommon();
510 drawFullscreen(gfx, linearDepth, rayShader_);
511}
512
513void Volumetric::rayMarchTo(Graphics *gfx, Texture *linearDepth, Canvas *dest) {
514 if (!gfx) throw eve::Exception("Volumetric.rayMarchTo: null graphics");
515 if (!dest) throw eve::Exception("Volumetric.rayMarchTo: null dest");
516 Canvas *prev = gfx->getCanvas();
517 gfx->setCanvas(dest);
518 rayMarch(gfx, linearDepth);
519 gfx->setCanvas(prev == gfx ? nullptr : prev);
520}
521
522void Volumetric::applyFog(Graphics *gfx, Texture *linearDepth) {
523 uploadFogCommon();
524 drawFullscreen(gfx, linearDepth, fogShader_);
525}
526
527void Volumetric::applyFogTo(Graphics *gfx, Texture *linearDepth, Canvas *dest) {
528 if (!gfx) throw eve::Exception("Volumetric.applyFogTo: null graphics");
529 if (!dest) throw eve::Exception("Volumetric.applyFogTo: null dest");
530 Canvas *prev = gfx->getCanvas();
531 gfx->setCanvas(dest);
532 applyFog(gfx, linearDepth);
533 gfx->setCanvas(prev == gfx ? nullptr : prev);
534}
535
537 float (*depth01)(int x, int y, void *userdata),
538 void *userdata) {
539 if (!gfx) throw eve::Exception("Volumetric.newLinearDepthTexture: null graphics");
540 if (width < 1 || height < 1)
541 throw eve::Exception("Volumetric.newLinearDepthTexture: invalid size");
542 if (!depth01) throw eve::Exception("Volumetric.newLinearDepthTexture: null depth fn");
543 std::vector<uint8_t> rgba(size_t(width) * size_t(height) * 4);
544 for (int y = 0; y < height; ++y) {
545 for (int x = 0; x < width; ++x) {
546 float d = depth01(x, y, userdata);
547 if (d < 0.f) d = 0.f;
548 if (d > 1.f) d = 1.f;
549 const uint8_t b = uint8_t(std::lround(d * 255.f));
550 const size_t i = size_t(y * width + x) * 4;
551 rgba[i + 0] = b;
552 rgba[i + 1] = b;
553 rgba[i + 2] = b;
554 rgba[i + 3] = 255;
555 }
556 }
557 return gfx->newTexture(width, height, rgba.data());
558}
559
560} // namespace eve::graphics
std::string value
vk::ShaderModule vert
vk::ShaderModule frag
int y
Definition Grass.cpp:135
float height
Definition Grass.cpp:235
float u
Definition Grass.cpp:234
int x
Definition Grass.cpp:135
int h
int w
uint32_t b
int width
float fovRad
Shader * shader
glm::mat4 view
glm::mat4 proj
const char * name
Definition RockMesh.cpp:21
int d
int v
virtual int getWidth() const =0
virtual void clear(std::optional< Color > color, std::optional< int > stencil, std::optional< double > depth)=0
virtual int getHeight() const =0
Drawable base (textures, meshes, canvases).
Definition Drawable.h:17
virtual void drawOcclusionTexture(Texture *texture, float x, float y, float w, float h)
Definition Graphics.cpp:860
virtual Canvas * getCanvas() const =0
virtual Texture * newTexture(int width, int height, const uint8_t *rgba, bool repeatU=false, bool repeatV=false)=0
virtual void setCanvas(Canvas *canvas)=0
nullptr or this → screen. Switching flushes pending draws to the previous target.
virtual void drawOcclusionSolid(float x, float y, float w, float h)
Definition Graphics.cpp:856
virtual void drawOcclusion(Drawable *drawable, const glm::mat4 &m)
Volumetric occlusion helpers (shadow-pass analogue for light shafts). drawOcclusion skips drawables w...
Definition Graphics.cpp:852
virtual void drawSolidRect(float x, float y, float w, float h, const Color &color, BlendMode blend=BlendMode::Alpha)=0
Internal immediate-mode helper used by RenderSystem / Batcher.
int getHeight() const
Definition Graphics.h:118
bool hasUniform(const std::string &name) const
Definition Shader.cpp:46
void sendFloat(const std::string &name, float x)
Definition Shader.cpp:82
void sendMatrix(const std::string &name, const glm::mat4 &m)
Definition Shader.cpp:99
int getFromVar(const std::string &name, void *data, size_t size) const
Definition Shader.cpp:71
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:17
void scatter(Graphics *gfx, Texture *occlusion)
Scatter-only: occlusion → shafts with alpha (draw over a prior scene). Writes to the currently bound ...
void scatterTo(Graphics *gfx, Texture *occlusion, Canvas *dest)
Same as scatter but into an explicit destination.
float getFloat(const std::string &name) const
void setFogNoise(float amount)
void drawOccluder(Graphics *gfx, Drawable *drawable, const glm::mat4 &matrix)
Drawable occlusion (respects Drawable::getCastOcclusion).
void setMode(const std::string &mode)
"screenspace" | "raymarch" | "fog" — selects which shader params quality tweaks.
void setLightScreenPos(float x, float y, float width, float height)
Pixel-space helper (converts with width/height).
void setFogEnd(float endDistance)
void beginOcclusionMap(Graphics *gfx, float lightPixelX, float lightPixelY, float lightRadiusPixels=24.f)
Clear the current canvas to black and draw a bright light disc (start of an occlusion map)....
void applyFromScene(Graphics *gfx, Texture *scene)
Single-pass: treat source as the scene (bright regions ≈ light), add shafts + dust/fog onto it....
void drawOccluders2D(Graphics *gfx)
Draw all visible Renderable2D with castOcclusion into the current canvas as black silhouettes (shadow...
void rayMarchTo(Graphics *gfx, Texture *linearDepth, Canvas *dest)
void setFogHeightFalloff(float falloff)
void setLightScreenUV(float u, float v)
Light position in UV (0..1), origin top-left to match 2D UVs.
void rayMarch(Graphics *gfx, Texture *linearDepth)
Ray march participating media using a linear-depth texture (R channel, 0=near .. 1=far)....
void setCamera(float eyeX, float eyeY, float eyeZ, float targetX, float targetY, float targetZ, float upX, float upY, float upZ, float fovYDeg, float aspect, float nearZ, float farZ)
Camera for ray march reconstruction (RH + ZO). Builds inv(viewProj) and near/far used by rayMarch*.
void setInvViewProj(const glm::mat4 &invViewProj)
Raw inverse view-projection (column-major, matching glm).
void setIntensity(float intensity)
bool hasParam(const std::string &name) const
float getLightScreenU() const
void setLightDirection(float dx, float dy, float dz)
World-space direction toward the lit surface (ray march / phase).
void setTime(float seconds)
void setFloat(const std::string &name, float value)
void setShaftColor(float r, float g, float b)
void setQuality(const std::string &quality)
"low" | "medium" | "high" (unknown → medium).
Texture * newLinearDepthTexture(Graphics *gfx, int width, int height, float(*depth01)(int x, int y, void *userdata), void *userdata)
Build an RGBA8 texture with linear depth in R (G=B=R, A=255). depth01(x,y) should return values in [0...
void setFogHeight(float worldY)
Height fog: denser near world Y = fogHeight; falloff is 1/meters scale.
void applyFromSceneTo(Graphics *gfx, Texture *scene, Canvas *dest)
float getLightScreenV() const
void applyFogTo(Graphics *gfx, Texture *linearDepth, Canvas *dest)
void setDensity(float density)
void drawOccluderTexture(Graphics *gfx, Texture *texture, float x, float y, float w, float h)
void setFogStart(float startDistance)
View-distance ramp where fog appears (world units along the ray).
void applyFog(Graphics *gfx, Texture *linearDepth)
Volumetric height/distance fog from a linear-depth texture. Writes fog RGB with alpha = 1-transmittan...
void drawOccluderSolid(Graphics *gfx, float x, float y, float w, float h)
Convenience 2D black silhouette (solid or textured alpha).
int resolutionFor(int fullSize) const
Downscale helper: returns floor(dim / downscale), at least 1. Callers create occlusion / scatter canv...
void setFogColor(float r, float g, float b)
卡牌游戏 UI 工具模块:工厂 + 脚本绑定入口。 功能参考 ycarowr/UiCard:扇形手牌布局、抽牌/洗牌、悬浮放大、拖拽到落牌区、 敌方手牌(背面/偷看)、费用不足置灰,以及可实时调节的布局...
Definition AnimTrail.h:6
glm::mat4 perspectiveVulkanRH_ZO(float fovyRad, float aspect, float zNear, float zFar)
Right-handed, zero-to-one depth perspective for Vulkan swapchains.
Definition ClipSpace.h:20
glm::vec4 Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
Definition Color.h:13