diff --git a/filament/src/PostProcessManager.cpp b/filament/src/PostProcessManager.cpp index b735c671cb..93167eee46 100644 --- a/filament/src/PostProcessManager.cpp +++ b/filament/src/PostProcessManager.cpp @@ -602,10 +602,11 @@ FrameGraphId PostProcessManager::screenSpaceAmbientOclusion( FrameGraphId PostProcessManager::structure(FrameGraph& fg, const RenderPass& pass, uint32_t width, uint32_t height, float scale) noexcept { - // structure pass -- automatically culled if not used - // used for SSAO currently. It consists of a mipmapped depth path - // mipmapping is tunned for SSAO - struct DepthPassData { + // structure pass -- automatically culled if not used, currently used by: + // - ssao + // - contact shadows + // It consists of a mipmapped depth pass, tuned for SSAO + struct StructurePassData { FrameGraphId depth; FrameGraphRenderTargetHandle rt; }; @@ -618,8 +619,8 @@ FrameGraphId PostProcessManager::structure(FrameGraph& fg, const size_t levelCount = FTexture::maxLevelCount(width, height) - 5; assert(levelCount >= 1); - // SSAO generates its own depth pass at the requested resolution - auto& ssaoDepthPass = fg.addPass("SSAO Depth Pass", + // generate depth pass at the requested resolution + auto& structurePass = fg.addPass("Structure Pass", [&](FrameGraph::Builder& builder, auto& data) { data.depth = builder.createTexture("Depth Buffer", { .width = width, .height = height, @@ -628,7 +629,7 @@ FrameGraphId PostProcessManager::structure(FrameGraph& fg, data.depth = builder.write(builder.read(data.depth)); - data.rt = builder.createRenderTarget("SSAO Depth Target", { + data.rt = builder.createRenderTarget("Structure Target", { .attachments = {{}, data.depth }, .clearFlags = TargetBufferFlags::DEPTH }); @@ -638,7 +639,7 @@ FrameGraphId PostProcessManager::structure(FrameGraph& fg, pass.execute(resources.getPassName(), out.target, out.params); }); - auto depth = ssaoDepthPass.getData().depth; + auto depth = structurePass.getData().depth; /* * create depth mipmap chain diff --git a/filament/src/Renderer.cpp b/filament/src/Renderer.cpp index 22d3e4544a..a958ce96b8 100644 --- a/filament/src/Renderer.cpp +++ b/filament/src/Renderer.cpp @@ -315,7 +315,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { // -------------------------------------------------------------------------------------------- // structure pass -- automatically culled if not used // Currently it consists of a simple depth pass. - // This is normally used by SSAO + // This is normally used by SSAO and contact-shadows // TODO: this should be a FrameGraph pass to participate to automatic culling pass.newCommandBuffer(); @@ -348,7 +348,8 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) { .hdrFormat = hdrFormat, .msaa = msaa, .clearFlags = clearFlags, - .clearColor = clearColor + .clearColor = clearColor, + .hasContactShadows = scene.hasContactShadows() }; // We use a framegraph pass to wait for froxelization to finish (so it can be done @@ -576,7 +577,8 @@ FrameGraphId FRenderer::colorPass(FrameGraph& fg, const char* data.color = blackboard.get("color"); data.structure = blackboard.get("structure"); - if (data.structure.isValid()) { + if (config.hasContactShadows) { + assert(data.structure.isValid()); data.structure = builder.sample(data.structure); } diff --git a/filament/src/Scene.cpp b/filament/src/Scene.cpp index 30af83ec96..e0a8ba4d76 100644 --- a/filament/src/Scene.cpp +++ b/filament/src/Scene.cpp @@ -178,6 +178,7 @@ void FScene::updateUBOs(utils::Range visibleRenderables, backend::Hand // allocate space into the command stream directly void* const buffer = driver.allocate(size); + bool hasContactShadows = false; auto& sceneData = mRenderableData; for (uint32_t i : visibleRenderables) { mat4f const& model = sceneData.elementAt(i); @@ -206,20 +207,27 @@ void FScene::updateUBOs(utils::Range visibleRenderables, backend::Hand // Note that we cast bools to uint32. Booleans are byte-sized in C++, but we need to // initialize all 32 bits in the UBO field. - UniformBuffer::setUniform(buffer, offset + offsetof(PerRenderableUib, skinningEnabled), - uint32_t(sceneData.elementAt(i).skinning)); - - UniformBuffer::setUniform(buffer, offset + offsetof(PerRenderableUib, morphingEnabled), - uint32_t(sceneData.elementAt(i).morphing)); - - UniformBuffer::setUniform(buffer, offset + offsetof(PerRenderableUib, screenSpaceContactShadows), - uint32_t(sceneData.elementAt(i).screenSpaceContactShadows)); + FRenderableManager::Visibility visibility = sceneData.elementAt(i); + hasContactShadows = hasContactShadows || visibility.screenSpaceContactShadows; + UniformBuffer::setUniform(buffer, + offset + offsetof(PerRenderableUib, skinningEnabled), + uint32_t(visibility.skinning)); UniformBuffer::setUniform(buffer, - offset + offsetof(PerRenderableUib, morphWeights), sceneData.elementAt(i)); + offset + offsetof(PerRenderableUib, morphingEnabled), + uint32_t(visibility.morphing)); + + UniformBuffer::setUniform(buffer, + offset + offsetof(PerRenderableUib, screenSpaceContactShadows), + uint32_t(visibility.screenSpaceContactShadows)); + + UniformBuffer::setUniform(buffer, + offset + offsetof(PerRenderableUib, morphWeights), + sceneData.elementAt(i)); } // TODO: handle static objects separately + mHasContactShadows = hasContactShadows; mRenderableViewUbh = renderableUbh; driver.loadUniformBuffer(renderableUbh, { buffer, size }); } @@ -390,6 +398,17 @@ void FScene::setSkybox(FSkybox const* skybox) noexcept { } } +bool FScene::hasContactShadows() const noexcept { + bool hasContactShadows = mHasContactShadows; + auto& lcm = mEngine.getLightManager(); + FLightManager::Instance directionalLight = mLightData.elementAt(0); + if (directionalLight.isValid()) { + auto const& shadowOoptions = lcm.getShadowOptions(directionalLight); + hasContactShadows = hasContactShadows && shadowOoptions.screenSpaceContactShadows; + } + return hasContactShadows; +} + } // namespace details // ------------------------------------------------------------------------------------------------ diff --git a/filament/src/details/Renderer.h b/filament/src/details/Renderer.h index 14d6143c54..5454b3cbc0 100644 --- a/filament/src/details/Renderer.h +++ b/filament/src/details/Renderer.h @@ -109,6 +109,7 @@ private: backend::TargetBufferFlags clearFlags; math::float4 clearColor = {}; float refractionLodOffset; + bool hasContactShadows; }; FrameGraphId colorPass(FrameGraph& fg, const char* name, diff --git a/filament/src/details/Scene.h b/filament/src/details/Scene.h index c33e321ec4..f7d516fa91 100644 --- a/filament/src/details/Scene.h +++ b/filament/src/details/Scene.h @@ -194,6 +194,8 @@ public: void updateUBOs(utils::Range visibleRenderables, backend::Handle renderableUbh) noexcept; + bool hasContactShadows() const noexcept; + private: static inline void computeLightRanges(math::float2* zrange, CameraInfo const& camera, const math::float4* spheres, size_t count) noexcept; @@ -215,13 +217,14 @@ private: /* * The data below is valid only during a view pass. i.e. if a scene is used in multiple - * views, the data below is update for each view. + * views, the data below is updated for each view. * In essence, this data should be owned by View, but it's so scene-specific, that for now * we store it here. */ RenderableSoa mRenderableData; LightSoa mLightData; backend::Handle mRenderableViewUbh; // This is actually owned by the view. + bool mHasContactShadows = false; }; FILAMENT_UPCAST(Scene)