feat(graphics): 体积光 + Ray March + 体积雾 (#19)

* feat(graphics): 屏幕空间体积光(尘雾 God Rays)

在 graphics 模块增加 Volumetric API:径向模糊光柱 + 尘/雾,
质量档 low/medium/high;Drawable.castOcclusion 对齐阴影语义的遮挡绘制。

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* feat(graphics): 体积光 Ray March 二期 + 扩展测试

合并 main;新增 raymarch 模式(线性深度积分 + 屏空间遮挡近似 CSM),
补充 mode/质量/drawOccluders2D/ray march 等测试(11 用例)。

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* feat(graphics): 体积雾(高度/距离 Beer-Lambert)

新增 setMode("fog") / applyFog:线性深度上积分高度指数雾与距离 ramp,
输出非预乘 RGB+alpha 以适配 SrcAlpha 混合。合并 main(gpgpu ECS)后补齐
cmake 源扫描,并扩展 volumetric 单测(15/15)。

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

* fix(test): GraphicsSmoke missing-texture 不再竞态 setupWriteDirectory

Mac CI 并行跑 clearAndPresentWindow 时共用 Filesystem identity,
ThrowsOnMissing 里多余的 bootstrap 会失败。缺文件抛错只需 PhysFS open,
并给写目录 bootstrap 使用独立 identity。

Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
西风逍遥游andCursor Agent authored and GitHub committed 2026-08-10 23:15:51 +08:00
1 parent cdd5e78efe
commit 8aa8e35d34
28 files changed
+3102 -17

No files matched your search

+10 -9
View File
@@ -6,7 +6,6 @@
#include <cstdint>
#include <cstring>
#include <memory>
#include <stdexcept>
#include <cmath>
#include "common/Exception.h"
@@ -90,12 +89,12 @@ static std::vector<uint8_t> makeStripeRGBA(int w, int h, int band) {
return px;
}
static eve::filesystem::Filesystem *bootstrapFilesystemForSaveIO() {
static eve::filesystem::Filesystem *bootstrapFilesystemForSaveIO(const char *identity) {
auto *fs = eve::filesystem::Filesystem::create();
fs->setIdentity("evengine_gfx_smoke", true);
if (!fs->setupWriteDirectory()) {
throw std::runtime_error("setupWriteDirectory failed");
}
// Unique identity per caller: CTest runs GraphicsSmoke.* in parallel and the
// Filesystem module is a process-wide singleton — shared write dirs race on macOS.
REQUIRE(fs->setIdentity(identity, true));
REQUIRE(fs->setupWriteDirectory());
return fs;
}
@@ -117,7 +116,7 @@ TEST_CASE("GraphicsSmoke.clearAndPresentWindow") {
gfx->setBackgroundColor(Color(0.12f, 0.14f, 0.22f, 1.0f));
auto *fs = bootstrapFilesystemForSaveIO();
auto *fs = bootstrapFilesystemForSaveIO("evengine_gfx_smoke_clear");
eve::image::Image::create();
auto checkerPx = makeCheckerRGBA(64, 64, 8, 255, 220, 60, 40, 40, 180);
@@ -204,11 +203,13 @@ TEST_CASE("GraphicsSmoke.newTextureFromFileThrowsOnMissing") {
s.centered = true;
REQUIRE(win->setWindowSettings(s));
bootstrapFilesystemForSaveIO();
// No write-dir bootstrap: missing-file should throw from PhysFS open alone.
// (Parallel GraphicsSmoke.clearAndPresentWindow used to race the same identity.)
eve::filesystem::Filesystem::create();
bool threw = false;
try {
gfx->newTextureFromFile("definitely_missing_evengine_xyz.png");
} catch (const eve::Exception&) {
} catch (const eve::Exception &) {
threw = true;
}
CHECK(threw);