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.
This commit is contained in:
Mathias Agopian
2021-08-17 10:54:01 -07:00
committed by Mathias Agopian
parent a86077e9fe
commit e2c5bb025b
4 changed files with 75 additions and 73 deletions
+7 -7
View File
@@ -69,9 +69,10 @@ ShadowMap::~ShadowMap() {
}
void ShadowMap::render(FScene const& scene, utils::Range<uint32_t> 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) {
+7 -8
View File
@@ -98,7 +98,9 @@ public:
filament::CameraInfo const& camera,
const ShadowMapInfo& shadowMapInfo, const SceneInfo& cascadeParams) noexcept;
void render(FScene const& scene, utils::Range<uint32_t> range, RenderPass* pass) noexcept;
void render(FScene const& scene, utils::Range<uint32_t> 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);
+41 -50
View File
@@ -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<ShadowMap*>(&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<ShadowMap*>(&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<uint32_t> range;
FScene::VisibleMaskType visibilityMask;
};
auto passList = utils::FixedCapacityVector<ShadowPass>::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<half>::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<half>::max();
const float vsmMoment1 = std::sqrt(vsmMoment2);
const float4 vsmClearColor{ vsmMoment1, vsmMoment2, 0.0f, 0.0f };
struct ShadowPassData {
FrameGraphId<FrameGraphTexture> 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<ShadowPassData>("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);
+20 -8
View File
@@ -85,19 +85,31 @@ public:
TypedUniformBuffer<ShadowUib>& 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<ShadowMap const*>(&mShadowMapCache[cascade]));
return shadowMap;
return std::launder(reinterpret_cast<ShadowMap*>(&mShadowMapCache[cascade]));
}
ShadowMap const* getCascadeShadowMap(size_t cascade) const noexcept {
return const_cast<ShadowMapManager*>(this)->getCascadeShadowMap(cascade);
}
ShadowMap* getSpotShadowMap(size_t spot) noexcept {
assert_invariant(spot < CONFIG_MAX_SHADOW_CASTING_SPOTS);
return std::launder(reinterpret_cast<ShadowMap*>(&mShadowMapCache[CONFIG_MAX_SHADOW_CASCADES + spot]));
}
ShadowMap const* getSpotShadowMap(size_t spot) const noexcept {
return const_cast<ShadowMapManager*>(this)->getSpotShadowMap(spot);
}
// valid after calling update() above
ShadowMappingUniforms getShadowMappingUniforms() const noexcept {
return mShadowMappingUniforms;
}
private: