From e2c5bb025bb4a85f0c2ce598f99ada922ba5e419 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Mon, 16 Aug 2021 16:46:14 -0700 Subject: [PATCH] Small ShadowMapManager refactoring The main changes are: - shadowmap command generation is now done in the framegraph pass itself, which allows it to be culled should the pass be culled. - CameraInfo is created only once instead of twice / shadowmap. It's not super heavy but also not cheap, as several matrices are computed. - simplified code. --- filament/src/ShadowMap.cpp | 14 ++--- filament/src/ShadowMap.h | 15 +++-- filament/src/ShadowMapManager.cpp | 91 ++++++++++++++----------------- filament/src/ShadowMapManager.h | 28 +++++++--- 4 files changed, 75 insertions(+), 73 deletions(-) diff --git a/filament/src/ShadowMap.cpp b/filament/src/ShadowMap.cpp index f0ff8cffef..feea841bed 100644 --- a/filament/src/ShadowMap.cpp +++ b/filament/src/ShadowMap.cpp @@ -69,9 +69,10 @@ ShadowMap::~ShadowMap() { } void ShadowMap::render(FScene const& scene, utils::Range range, + FScene::VisibleMaskType visibilityMask, filament::CameraInfo const& cameraInfo, RenderPass* const pass) noexcept { - filament::CameraInfo cameraInfo(getCamera()); pass->setCamera(cameraInfo); + pass->setVisibilityMask(visibilityMask); pass->setGeometry(scene.getRenderableData(), range, scene.getRenderableUBO()); pass->overridePolygonOffset(&mPolygonOffset); pass->appendCommands(RenderPass::SHADOW); @@ -153,14 +154,13 @@ void ShadowMap::update(const FScene::LightSoa& lightData, size_t index, } } - const CameraInfo cameraInfo = { + const ShadowCameraInfo cameraInfo = { .projection = cullingProjection, .model = camera.model, .view = camera.view, .worldOrigin = camera.worldOrigin, .zn = camera.zn, - .zf = camera.zf, - .frustum = Frustum(cullingProjection * camera.view) + .zf = camera.zf }; // debugging... @@ -193,7 +193,7 @@ void ShadowMap::update(const FScene::LightSoa& lightData, size_t index, } void ShadowMap::computeShadowCameraDirectional( - float3 const& dir, CameraInfo const& camera, + float3 const& dir, ShadowCameraInfo const& camera, FLightManager::ShadowParams const& params, SceneInfo cascadeParams) noexcept { @@ -452,7 +452,7 @@ void ShadowMap::computeShadowCameraDirectional( } void ShadowMap::computeShadowCameraSpot(math::float3 const& position, math::float3 const& dir, - float outerConeAngle, float radius, CameraInfo const& camera, + float outerConeAngle, float radius, ShadowCameraInfo const& camera, FLightManager::ShadowParams const& params) noexcept { // TODO: correctly compute if this spot light has any visible shadows. @@ -506,7 +506,7 @@ void ShadowMap::computeShadowCameraSpot(math::float3 const& position, math::floa } mat4f ShadowMap::applyLISPSM(math::mat4f& Wp, - CameraInfo const& camera, FLightManager::ShadowParams const& params, + ShadowCameraInfo const& camera, FLightManager::ShadowParams const& params, mat4f const& LMpMv, FrustumBoxIntersection const& wsShadowReceiversVolume, size_t vertexCount, float3 const& dir) { diff --git a/filament/src/ShadowMap.h b/filament/src/ShadowMap.h index ae9a4462a0..fb30b1ccf7 100644 --- a/filament/src/ShadowMap.h +++ b/filament/src/ShadowMap.h @@ -98,7 +98,9 @@ public: filament::CameraInfo const& camera, const ShadowMapInfo& shadowMapInfo, const SceneInfo& cascadeParams) noexcept; - void render(FScene const& scene, utils::Range range, RenderPass* pass) noexcept; + void render(FScene const& scene, utils::Range range, + FScene::VisibleMaskType visibilityMask, filament::CameraInfo const& cameraInfo, + RenderPass* pass) noexcept; // Do we have visible shadows. Valid after calling update(). bool hasVisibleShadows() const noexcept { return mHasVisibleShadows; } @@ -119,16 +121,13 @@ public: backend::PolygonOffset getPolygonOffset() const noexcept { return mPolygonOffset; } private: - struct CameraInfo { + struct ShadowCameraInfo { math::mat4f projection; math::mat4f model; math::mat4f view; math::mat4f worldOrigin; float zn = 0; float zf = 0; - Frustum frustum; - float getNear() const noexcept { return zn; } - float getFar() const noexcept { return zf; } math::float3 const& getPosition() const noexcept { return model[3].xyz; } math::float3 getForwardVector() const noexcept { return -normalize(model[2].xyz); // the camera looks towards -z @@ -148,14 +147,14 @@ private: void computeShadowCameraDirectional( math::float3 const& direction, - CameraInfo const& camera, FLightManager::ShadowParams const& params, + ShadowCameraInfo const& camera, FLightManager::ShadowParams const& params, SceneInfo cascadeParams) noexcept; void computeShadowCameraSpot(math::float3 const& position, math::float3 const& dir, - float outerConeAngle, float radius, CameraInfo const& camera, + float outerConeAngle, float radius, ShadowCameraInfo const& camera, FLightManager::ShadowParams const& params) noexcept; static math::mat4f applyLISPSM(math::mat4f& Wp, - CameraInfo const& camera, FLightManager::ShadowParams const& params, + ShadowCameraInfo const& camera, FLightManager::ShadowParams const& params, const math::mat4f& LMpMv, FrustumBoxIntersection const& wsShadowReceiverVolume, size_t vertexCount, const math::float3& dir); diff --git a/filament/src/ShadowMapManager.cpp b/filament/src/ShadowMapManager.cpp index 67054e907a..0b8e345750 100644 --- a/filament/src/ShadowMapManager.cpp +++ b/filament/src/ShadowMapManager.cpp @@ -73,7 +73,7 @@ void ShadowMapManager::setShadowCascades(size_t lightIndex, LightManager::ShadowOptions const* options) noexcept { assert_invariant(options->shadowCascades <= CONFIG_MAX_SHADOW_CASCADES); for (size_t c = 0; c < options->shadowCascades; c++) { - auto shadowMap = std::launder(reinterpret_cast(&mShadowMapCache[c])); + auto* shadowMap = getCascadeShadowMap(c); mCascadeShadowMaps.emplace_back(shadowMap, lightIndex, options); } } @@ -82,7 +82,7 @@ void ShadowMapManager::addSpotShadowMap(size_t lightIndex, LightManager::ShadowOptions const* options) noexcept { const size_t c = mSpotShadowMaps.size(); assert_invariant(c < CONFIG_MAX_SHADOW_CASTING_SPOTS); - auto shadowMap = std::launder(reinterpret_cast(&mShadowMapCache[CONFIG_MAX_SHADOW_CASCADES + c])); + auto* shadowMap = getSpotShadowMap(c); mSpotShadowMaps.emplace_back(shadowMap, lightIndex, options); } @@ -99,11 +99,9 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, backend::DriverAp assert_invariant(textureRequirements.layers <= MAX_SHADOW_LAYERS); struct ShadowPass { - ShadowPass(ShadowMapEntry const* shadowmap, RenderPass const& pass) noexcept - : shadowmap(shadowmap), pass(pass) { - } - ShadowMapEntry const* shadowmap; - RenderPass pass; + ShadowMapEntry const* shadowMapEntry; + utils::Range range; + FScene::VisibleMaskType visibilityMask; }; auto passList = utils::FixedCapacityVector::with_capacity(MAX_SHADOW_LAYERS); @@ -111,43 +109,32 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, backend::DriverAp FScene* scene = view.getScene(); assert_invariant(scene); - // These loops fill render passes with appropriate rendering commands for each shadow map. - // The actual render pass execution is deferred to the frame graph. + // these loops create a list of the shadow maps that need to be rendered (i.e. that have + // visible shadows). + // Directional, cascaded shadowmaps - for (const auto& map : mCascadeShadowMaps) { - auto& range = view.getVisibleDirectionalShadowCasters(); - if (!map.hasVisibleShadows() || range.empty()) { - continue; + auto const directionalShadowCastersRange = view.getVisibleDirectionalShadowCasters(); + if (!directionalShadowCastersRange.empty()) { + for (const auto& map : mCascadeShadowMaps) { + if (map.hasVisibleShadows()) { + passList.push_back({ + &map, directionalShadowCastersRange, VISIBLE_DIR_SHADOW_RENDERABLE }); + } } - - // updatePrimitivesLod must be run before RenderPass::appendCommands. - filament::CameraInfo cameraInfo(map.getShadowMap().getCamera()); - view.updatePrimitivesLod(engine, cameraInfo, scene->getRenderableData(), range); - - auto& entry = passList.emplace_back(&map, pass); - map.getShadowMap().render(*scene, range, &entry.pass); } // Spotlight shadowmaps - for (size_t i = 0, c = mSpotShadowMaps.size(); i < c; i++) { - const auto& map = mSpotShadowMaps[i]; - auto& range = view.getVisibleSpotShadowCasters(); - if (!map.hasVisibleShadows() || range.empty()) { - continue; + auto const spotShadowCastersRange = view.getVisibleSpotShadowCasters(); + if (!spotShadowCastersRange.empty()) { + for (size_t i = 0, c = mSpotShadowMaps.size(); i < c; i++) { + const auto& map = mSpotShadowMaps[i]; + if (map.hasVisibleShadows()) { + passList.push_back({ + &map, spotShadowCastersRange, VISIBLE_SPOT_SHADOW_RENDERABLE_N(i) }); + } } - // updatePrimitivesLod must be run before RenderPass::appendCommands. - filament::CameraInfo cameraInfo(map.getShadowMap().getCamera()); - view.updatePrimitivesLod(engine, cameraInfo, scene->getRenderableData(), range); - - auto& entry = passList.emplace_back(&map, pass); - entry.pass.setVisibilityMask(VISIBLE_SPOT_SHADOW_RENDERABLE_N(i)); - map.getShadowMap().render(*scene, range, &entry.pass); } - const float vsmMoment2 = std::numeric_limits::max(); - const float vsmMoment1 = std::sqrt(vsmMoment2); - const float4 vsmClearColor{ vsmMoment1, vsmMoment2, 0.0f, 0.0f }; - assert_invariant(passList.size() <= textureRequirements.layers); // ------------------------------------------------------------------------------------------- @@ -171,6 +158,10 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, backend::DriverAp // ------------------------------------------------------------------------------------------- + const float vsmMoment2 = std::numeric_limits::max(); + const float vsmMoment1 = std::sqrt(vsmMoment2); + const float4 vsmClearColor{ vsmMoment1, vsmMoment2, 0.0f, 0.0f }; + struct ShadowPassData { FrameGraphId tempBlurSrc; // temporary shadowmap when blurring uint32_t blurRt; @@ -181,13 +172,9 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, backend::DriverAp auto& ppm = engine.getPostProcessManager(); - for (auto& entry : passList) { - if (!entry.shadowmap->hasVisibleShadows()) { - continue; - } - - const auto layer = entry.shadowmap->getLayer(); - const auto* options = entry.shadowmap->getShadowOptions(); + for (auto const& entry : passList) { + const auto layer = entry.shadowMapEntry->getLayer(); + const auto* options = entry.shadowMapEntry->getShadowOptions(); auto& shadowPass = fg.addPass("Shadow Pass", [&](FrameGraph::Builder& builder, auto& data) { @@ -258,17 +245,22 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, backend::DriverAp // finally create the shadowmap render target -- one per layer. data.shadowRt = builder.declareRenderPass("Shadow RT", renderTargetDesc); }, - [=, &view](FrameGraphResources const& resources, + [=, &engine, &view](FrameGraphResources const& resources, auto const& data, DriverApi& driver) { - const auto& executor = entry.pass.getExecutor(); - const auto* options = entry.shadowmap->getShadowOptions(); + ShadowMap& shadowMap = entry.shadowMapEntry->getShadowMap(); + const CameraInfo cameraInfo(shadowMap.getCamera()); + // updatePrimitivesLod must be run before RenderPass::appendCommands. + view.updatePrimitivesLod(engine, cameraInfo, scene->getRenderableData(), entry.range); + + // generate and sort the commands for rendering the shadow map + RenderPass entryPass(pass); + shadowMap.render(*scene, entry.range, entry.visibilityMask, cameraInfo, &entryPass); + + const auto& executor = entryPass.getExecutor(); const bool blur = view.hasVsm() && options->vsm.blurWidth > 0.0f; - // TODO: camera is already set inside 'pass', we could get it from there - FCamera const& camera = entry.shadowmap->getShadowMap().getCamera(); - filament::CameraInfo cameraInfo(camera); view.prepareCamera(cameraInfo); // We set a viewport with a 1-texel border for when we index outside of the @@ -295,7 +287,6 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, backend::DriverAp // render either directly into the shadowmap, or to the temporary texture for // blurring. auto rt = resources.getRenderPassInfo(blur ? data.blurRt : data.shadowRt); - rt.params.viewport = viewport; executor.execute("Shadow Pass", rt.target, rt.params); diff --git a/filament/src/ShadowMapManager.h b/filament/src/ShadowMapManager.h index 8eb8934476..fc07aaeafb 100644 --- a/filament/src/ShadowMapManager.h +++ b/filament/src/ShadowMapManager.h @@ -85,19 +85,31 @@ public: TypedUniformBuffer& shadowUb, FScene::RenderableSoa& renderableData, FScene::LightSoa& lightData) noexcept; - // valid after calling update() above - ShadowMappingUniforms getShadowMappingUniforms() const noexcept { - return mShadowMappingUniforms; - } - // Renders all of the shadow maps. void render(FrameGraph& fg, FEngine& engine, backend::DriverApi& driver, RenderPass const& pass, FView& view) noexcept; - const ShadowMap* getCascadeShadowMap(size_t cascade) const noexcept { + ShadowMap* getCascadeShadowMap(size_t cascade) noexcept { assert_invariant(cascade < CONFIG_MAX_SHADOW_CASCADES); - auto shadowMap = std::launder(reinterpret_cast(&mShadowMapCache[cascade])); - return shadowMap; + return std::launder(reinterpret_cast(&mShadowMapCache[cascade])); + } + + ShadowMap const* getCascadeShadowMap(size_t cascade) const noexcept { + return const_cast(this)->getCascadeShadowMap(cascade); + } + + ShadowMap* getSpotShadowMap(size_t spot) noexcept { + assert_invariant(spot < CONFIG_MAX_SHADOW_CASTING_SPOTS); + return std::launder(reinterpret_cast(&mShadowMapCache[CONFIG_MAX_SHADOW_CASCADES + spot])); + } + + ShadowMap const* getSpotShadowMap(size_t spot) const noexcept { + return const_cast(this)->getSpotShadowMap(spot); + } + + // valid after calling update() above + ShadowMappingUniforms getShadowMappingUniforms() const noexcept { + return mShadowMappingUniforms; } private: