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:
committed by
Mathias Agopian
parent
a86077e9fe
commit
e2c5bb025b
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user