diff --git a/src/modules/graphics/RenderControl.cpp b/src/modules/graphics/RenderControl.cpp index 5ef450de..4a0e442a 100644 --- a/src/modules/graphics/RenderControl.cpp +++ b/src/modules/graphics/RenderControl.cpp @@ -5,7 +5,8 @@ namespace { const char *kKnownFeatures[] = {"depthTest", "shadow", "gbuffer", "gbufferAlbedo", "forward", "hair", "clustered", "ao", "gi", "aa", "msaa", - "outline", "gpuDriven", "visResolve", "frustumCull", "decal"}; + "outline", "gpuDriven", "visResolve", "frustumCull", "decal", + "atmosphere", "volumetricFog", "fogLocalVolumes", "fogTemporal"}; bool isKnownFeature(const std::string &feature) { for (const char *f : kKnownFeatures) { @@ -32,6 +33,10 @@ RenderControl::RenderControl() { features_["gpuDriven"] = false; // stage 1 opt-in; off until runtime-verified features_["visResolve"] = false; // stage 3 opt-in; visibility-buffer resolve features_["frustumCull"] = false; // opt-in: conservative sphere culling in frame prep + features_["atmosphere"] = true; + features_["volumetricFog"] = false; + features_["fogLocalVolumes"] = false; + features_["fogTemporal"] = false; dirty_ = true; compiled_ = false; } @@ -55,6 +60,16 @@ void RenderControl::setFeature(const std::string &feature, bool enabled) { if (feature == "decal" && enabled) features_["gbuffer"] = true; // Stage 2 GPU cull needs the GBuffer depth as its HZB source. if (feature == "gpuDriven" && enabled) features_["gbuffer"] = true; + if ((feature == "volumetricFog" || feature == "fogLocalVolumes" || + feature == "fogTemporal") && enabled) { + features_["atmosphere"] = true; + features_["volumetricFog"] = true; + features_["gbuffer"] = true; + } + if (feature == "volumetricFog" && !enabled) { + features_["fogLocalVolumes"] = false; + features_["fogTemporal"] = false; + } if (feature == "gi" && enabled) { features_["gbuffer"] = true; features_["gbufferAlbedo"] = true; @@ -85,6 +100,14 @@ void RenderControl::compile() { passes_.push_back("gbuffer"); if (isEnabled("decal")) passes_.push_back("decal"); if (isEnabled("forward")) passes_.push_back("forward"); + if (isEnabled("atmosphere")) passes_.push_back("atmosphere"); + if (isEnabled("volumetricFog")) { + passes_.push_back("fogMedia"); + passes_.push_back("fogLighting"); + if (isEnabled("fogTemporal")) passes_.push_back("fogTemporal"); + passes_.push_back("fogIntegrate"); + passes_.push_back("fogComposite"); + } if (isEnabled("hair")) passes_.push_back("hair"); dirty_ = false; compiled_ = true; diff --git a/src/modules/graphics/RenderControl.h b/src/modules/graphics/RenderControl.h index 68c21d70..68a7b0d6 100644 --- a/src/modules/graphics/RenderControl.h +++ b/src/modules/graphics/RenderControl.h @@ -35,6 +35,10 @@ class Graphics; * Graphics.setMsaaSamples, default 4, clamped to device support) * "decal" — screen-space decal layer pass between gbuffer and forward * (implies gbuffer; default off) + * "atmosphere" — analytic sky/aerial-perspective pass (default on) + * "volumetricFog" — froxel media, lighting, integration and composite passes + * "fogLocalVolumes" — local volume injection (implies volumetricFog) + * "fogTemporal" — history filtering (implies volumetricFog) * * 3D draws into a sampleable scene color target (not the swapchain). Present * resolves that target (FXAA when "aa" is on), then composites AO/HUD. @@ -64,7 +68,7 @@ public: bool isDirty() const { return dirty_; } int getPassCount() const { return int(passes_.size()); } - /** @brief Pass names: "shadow" | "gbuffer" | "forward" | "hair" */ + /** @brief Return the compiled pass name at index, or an empty string. */ std::string getPassName(int index) const; bool hasPass(const std::string &name) const; diff --git a/test/MaterialRenderControl.cpp b/test/MaterialRenderControl.cpp index 3b945e2a..5508f15b 100644 --- a/test/MaterialRenderControl.cpp +++ b/test/MaterialRenderControl.cpp @@ -94,6 +94,25 @@ TEST_CASE("renderControl.compileFeaturesToPasses") { CHECK(!rc.isEnabled("gbufferAlbedo")); } +TEST_CASE("renderControl.atmospherePassDependencies") { + RenderControl rc; + CHECK(rc.supports("atmosphere")); + CHECK(rc.supports("volumetricFog")); + rc.enable("fogTemporal"); + rc.compile(); + CHECK(rc.isEnabled("gbuffer")); + CHECK(rc.isEnabled("atmosphere")); + CHECK(rc.isEnabled("volumetricFog")); + CHECK(rc.hasPass("atmosphere")); + CHECK(rc.hasPass("fogMedia")); + CHECK(rc.hasPass("fogLighting")); + CHECK(rc.hasPass("fogTemporal")); + CHECK(rc.hasPass("fogIntegrate")); + CHECK(rc.hasPass("fogComposite")); + rc.disable("volumetricFog"); + CHECK(!rc.isEnabled("fogTemporal")); +} + TEST_CASE("renderable3d.materialAndParts") { auto *ent = Renderable3D::create(); REQUIRE(ent != nullptr);