Each shadowmap now manages its own UBO
Instead of constantly reusing the View's UBO, each shadowmap now manages it own. All UBOs for all shadow maps are updated together, then later during rendering, we're simply binding the correct UBO. This change will be needed later so that we can update several shadow maps in a single texture. There are two main changes to achieve this: 1. ShadowMap now has PerViewUniforms object 2. For point lights, each face now has a ShadowMap object One consequence is that ShadowMap is now very large (over 2KB). This will be addressed later.
This commit is contained in:
committed by
Mathias Agopian
parent
83a82ae10e
commit
c393ee4591
@@ -91,14 +91,9 @@ void PerViewUniforms::prepareCamera(const CameraInfo& camera) noexcept {
|
||||
s.clipControl = mClipControl;
|
||||
}
|
||||
|
||||
void PerViewUniforms::prepareUpscaler(math::float2 scale,
|
||||
DynamicResolutionOptions const& options) noexcept {
|
||||
void PerViewUniforms::prepareLodBias(float bias) noexcept {
|
||||
auto& s = mUniforms.edit();
|
||||
if (options.quality >= QualityLevel::HIGH) {
|
||||
s.lodBias = std::log2(std::min(scale.x, scale.y));
|
||||
} else {
|
||||
s.lodBias = 0.0f;
|
||||
}
|
||||
s.lodBias = bias;
|
||||
}
|
||||
|
||||
void PerViewUniforms::prepareExposure(float ev100) noexcept {
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
void terminate(backend::DriverApi& driver);
|
||||
|
||||
void prepareCamera(const CameraInfo& camera) noexcept;
|
||||
void prepareUpscaler(math::float2 scale, DynamicResolutionOptions const& options) noexcept;
|
||||
void prepareLodBias(float bias) noexcept;
|
||||
|
||||
/*
|
||||
* @param viewport viewport (should be same as RenderPassParams::viewport)
|
||||
|
||||
@@ -173,7 +173,7 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
|
||||
view.prepareSSAO(data.ssao ?
|
||||
resources.getTexture(data.ssao) : engine.getOneTextureArray());
|
||||
|
||||
view.prepareShadowMap(view.getVsmShadowOptions().highPrecision);
|
||||
view.prepareShadowMapping(view.getVsmShadowOptions().highPrecision);
|
||||
|
||||
// set shadow sampler
|
||||
view.prepareShadow(data.shadows ?
|
||||
@@ -200,6 +200,7 @@ FrameGraphId<FrameGraphTexture> RendererUtils::colorPass(
|
||||
|
||||
view.prepareViewport(static_cast<filament::Viewport&>(out.params.viewport),
|
||||
config.xoffset, config.yoffset);
|
||||
|
||||
view.commitUniforms(driver);
|
||||
|
||||
out.params.clearColor = data.clearColor;
|
||||
|
||||
@@ -41,8 +41,10 @@ using namespace backend;
|
||||
static constexpr bool USE_DEPTH_CLAMP = false;
|
||||
|
||||
ShadowMap::ShadowMap(FEngine& engine) noexcept
|
||||
: mShadowType(ShadowType::DIRECTIONAL),
|
||||
mHasVisibleShadows(false) {
|
||||
: mPerViewUniforms(engine),
|
||||
mShadowType(ShadowType::DIRECTIONAL),
|
||||
mHasVisibleShadows(false),
|
||||
mFace(0) {
|
||||
Entity entities[2];
|
||||
engine.getEntityManager().create(2, entities);
|
||||
mCamera = engine.createCamera(entities[0]);
|
||||
@@ -64,12 +66,14 @@ void ShadowMap::terminate(FEngine& engine) {
|
||||
|
||||
ShadowMap::~ShadowMap() = default;
|
||||
|
||||
void ShadowMap::initialize(size_t lightIndex, ShadowType shadowType, uint16_t shadowIndex,
|
||||
void ShadowMap::initialize(size_t lightIndex, ShadowType shadowType,
|
||||
uint16_t shadowIndex, uint8_t face,
|
||||
LightManager::ShadowOptions const* options) {
|
||||
mLightIndex = lightIndex;
|
||||
mShadowIndex = shadowIndex;
|
||||
mOptions = options;
|
||||
mShadowType = shadowType;
|
||||
mFace = face;
|
||||
}
|
||||
|
||||
mat4f ShadowMap::getDirectionalLightViewMatrix(float3 direction, float3 position) noexcept {
|
||||
@@ -1238,4 +1242,56 @@ void ShadowMap::updateSceneInfoSpot(mat4f const& Mv, FScene const& scene,
|
||||
);
|
||||
}
|
||||
|
||||
filament::Viewport ShadowMap::getViewport() const noexcept {
|
||||
// We set a viewport with a 1-texel border for when we index outside the
|
||||
// texture.
|
||||
// DON'T CHANGE this unless ShadowMap::getTextureCoordsMapping() is updated too.
|
||||
// see: ShadowMap::getTextureCoordsMapping()
|
||||
//
|
||||
// For floating-point depth textures, the 1-texel border could be set to
|
||||
// FLOAT_MAX to avoid clamping in the shadow shader (see sampleDepth inside
|
||||
// shadowing.fs). Unfortunately, the APIs don't seem let us clear depth
|
||||
// attachments to anything greater than 1.0, so we'd need a way to do this other
|
||||
// than clearing.
|
||||
const uint32_t dim = mOptions->mapSize;
|
||||
if (isPointShadow()) {
|
||||
// for point-light we don't have a border
|
||||
return { 0, 0, dim, dim };
|
||||
} else {
|
||||
return { 1, 1, dim - 2, dim - 2 };
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
void ShadowMap::prepareCamera(const CameraInfo& cameraInfo) noexcept {
|
||||
mPerViewUniforms.prepareCamera(cameraInfo);
|
||||
mPerViewUniforms.prepareLodBias(0.0f);
|
||||
}
|
||||
|
||||
void ShadowMap::prepareViewport(const filament::Viewport& viewport) noexcept {
|
||||
mPerViewUniforms.prepareViewport(viewport, 0, 0);
|
||||
}
|
||||
|
||||
void ShadowMap::prepareTime(math::float4 const& userTime) noexcept {
|
||||
mPerViewUniforms.prepareTime(userTime);
|
||||
}
|
||||
|
||||
void ShadowMap::prepareDirectionalLight(math::float3 const& sceneSpaceDirection,
|
||||
LightManager::Instance instance) noexcept {
|
||||
mPerViewUniforms.prepareDirectionalLight(1.0f, sceneSpaceDirection, instance);
|
||||
}
|
||||
|
||||
void ShadowMap::prepareShadowMapping(bool highPrecision) noexcept {
|
||||
mPerViewUniforms.prepareShadowMapping(highPrecision);
|
||||
}
|
||||
|
||||
void ShadowMap::commitUniforms(backend::DriverApi& driver) const noexcept {
|
||||
mPerViewUniforms.commit(driver);
|
||||
}
|
||||
|
||||
void ShadowMap::bindPerViewUniformsAndSamplers(backend::DriverApi& driver) const noexcept {
|
||||
mPerViewUniforms.bind(driver);
|
||||
}
|
||||
|
||||
} // namespace filament
|
||||
|
||||
@@ -19,12 +19,14 @@
|
||||
|
||||
#include "components/LightManager.h"
|
||||
|
||||
#include "PerViewUniforms.h"
|
||||
|
||||
#include "details/Camera.h"
|
||||
#include "details/Scene.h"
|
||||
|
||||
#include "backend/DriverApiForward.h"
|
||||
#include "private/backend/SamplerGroup.h"
|
||||
#include "math/mat4.h"
|
||||
#include "private/backend/DriverApi.h"
|
||||
|
||||
#include <filament/Viewport.h>
|
||||
|
||||
#include <math/mat4.h>
|
||||
#include <math/vec4.h>
|
||||
@@ -122,7 +124,7 @@ public:
|
||||
static math::mat4f getPointLightViewMatrix(backend::TextureCubemapFace face,
|
||||
math::float3 position) noexcept;
|
||||
|
||||
void initialize(size_t lightIndex, ShadowType shadowType, uint16_t shadowIndex,
|
||||
void initialize(size_t lightIndex, ShadowType shadowType, uint16_t shadowIndex, uint8_t face,
|
||||
LightManager::ShadowOptions const* options);
|
||||
|
||||
struct ShaderParameters {
|
||||
@@ -172,6 +174,8 @@ public:
|
||||
static void updateSceneInfoSpot(const math::mat4f& Mv, FScene const& scene,
|
||||
SceneInfo& sceneInfo);
|
||||
|
||||
filament::Viewport getViewport() const noexcept;
|
||||
|
||||
LightManager::ShadowOptions const* getShadowOptions() const noexcept { return mOptions; }
|
||||
size_t getLightIndex() const { return mLightIndex; }
|
||||
uint16_t getShadowIndex() const { return mShadowIndex; }
|
||||
@@ -181,6 +185,16 @@ public:
|
||||
bool isSpotShadow() const noexcept { return mShadowType == ShadowType::SPOT; }
|
||||
bool isPointShadow() const noexcept { return mShadowType == ShadowType::POINT; }
|
||||
ShadowType getShadowType() const noexcept { return mShadowType; }
|
||||
uint8_t getFace() const noexcept { return mFace; }
|
||||
|
||||
void prepareCamera(const CameraInfo& cameraInfo) noexcept;
|
||||
void prepareViewport(const filament::Viewport& viewport) noexcept;
|
||||
void prepareTime(math::float4 const& userTime) noexcept;
|
||||
void prepareDirectionalLight(math::float3 const& sceneSpaceDirection,
|
||||
LightManager::Instance instance) noexcept;
|
||||
void prepareShadowMapping(bool highPrecision) noexcept;
|
||||
void commitUniforms(backend::DriverApi& driver) const noexcept;
|
||||
void bindPerViewUniformsAndSamplers(backend::DriverApi& driver) const noexcept;
|
||||
|
||||
private:
|
||||
struct Segment {
|
||||
@@ -278,6 +292,8 @@ private:
|
||||
{ 2, 6, 7, 3 }, // top
|
||||
};
|
||||
|
||||
mutable PerViewUniforms mPerViewUniforms; // 64 + 2048
|
||||
|
||||
FCamera* mCamera = nullptr; // 8
|
||||
FCamera* mDebugCamera = nullptr; // 8
|
||||
|
||||
@@ -287,10 +303,13 @@ private:
|
||||
uint32_t mLightIndex = 0; // which light are we shadowing // 4
|
||||
uint16_t mShadowIndex = 0; // our index in the shadowMap vector // 2
|
||||
uint8_t mLayer = 0; // our layer in the shadowMap texture // 1
|
||||
ShadowType mShadowType : 2;
|
||||
bool mHasVisibleShadows : 2;
|
||||
ShadowType mShadowType : 2; // :2
|
||||
bool mHasVisibleShadows : 2; // :2
|
||||
uint8_t mFace : 3; // :3
|
||||
};
|
||||
|
||||
static_assert(sizeof(ShadowMap) == 32 + 2048 + 64);
|
||||
|
||||
} // namespace filament
|
||||
|
||||
#endif // TNT_FILAMENT_DETAILS_SHADOWMAP_H
|
||||
|
||||
@@ -98,22 +98,34 @@ void ShadowMapManager::setDirectionalShadowMap(size_t lightIndex,
|
||||
assert_invariant(options->shadowCascades <= CONFIG_MAX_SHADOW_CASCADES);
|
||||
for (size_t c = 0; c < options->shadowCascades; c++) {
|
||||
auto* pShadowMap = getCascadeShadowMap(c);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::DIRECTIONAL, c, options);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::DIRECTIONAL, c, 0, options);
|
||||
mCascadeShadowMaps.push_back(pShadowMap);
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowMapManager::addShadowMap(size_t lightIndex, bool spotlight,
|
||||
LightManager::ShadowOptions const* options) noexcept {
|
||||
const size_t c = mSpotShadowMaps.size();
|
||||
assert_invariant(c < CONFIG_MAX_SHADOWMAP_PUNCTUAL);
|
||||
auto* pShadowMap = getPointOrSpotShadowMap(c);
|
||||
pShadowMap->initialize(lightIndex, spotlight ? ShadowType::SPOT : ShadowType::POINT, c, options);
|
||||
mSpotShadowMaps.push_back(pShadowMap);
|
||||
if (spotlight) {
|
||||
const size_t c = mSpotShadowMaps.size();
|
||||
assert_invariant(c < CONFIG_MAX_SHADOWMAP_PUNCTUAL);
|
||||
auto* pShadowMap = getPointOrSpotShadowMap(c);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::SPOT, c, 0, options);
|
||||
mSpotShadowMaps.push_back(pShadowMap);
|
||||
} else {
|
||||
// point-light
|
||||
for (size_t face = 0; face < 6; face++) {
|
||||
const size_t c = mSpotShadowMaps.size();
|
||||
assert_invariant(c < CONFIG_MAX_SHADOWMAP_PUNCTUAL);
|
||||
auto* pShadowMap = getPointOrSpotShadowMap(c);
|
||||
pShadowMap->initialize(lightIndex, ShadowType::POINT, c, face, options);
|
||||
mSpotShadowMaps.push_back(pShadowMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine& engine,
|
||||
RenderPass const& pass, FView& view, CameraInfo const& mainCameraInfo) noexcept {
|
||||
FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FEngine& engine, FrameGraph& fg,
|
||||
RenderPass const& pass, FView& view, CameraInfo const& mainCameraInfo,
|
||||
float4 const& userTime) noexcept {
|
||||
|
||||
const float moment2 = std::numeric_limits<half>::max();
|
||||
const float moment1 = std::sqrt(moment2);
|
||||
@@ -133,11 +145,9 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine
|
||||
struct PrepareShadowPassData {
|
||||
struct ShadowPass {
|
||||
mutable RenderPass::Executor executor;
|
||||
mutable CameraInfo cameraInfo;
|
||||
ShadowMap* shadowMap;
|
||||
utils::Range<uint32_t> range;
|
||||
FScene::VisibleMaskType visibilityMask;
|
||||
uint8_t face = 0;
|
||||
};
|
||||
// the actual shadow map atlas (currently a 2D texture array)
|
||||
FrameGraphId<FrameGraphTexture> shadows;
|
||||
@@ -166,7 +176,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine
|
||||
// for the directional light, we already know if it has visible shadows.
|
||||
if (pShadowMap->hasVisibleShadows()) {
|
||||
passList.push_back({
|
||||
{}, {}, pShadowMap, directionalShadowCastersRange,
|
||||
{}, pShadowMap, directionalShadowCastersRange,
|
||||
VISIBLE_DIR_SHADOW_RENDERABLE });
|
||||
}
|
||||
}
|
||||
@@ -178,16 +188,8 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine
|
||||
for (auto* pShadowMap : mSpotShadowMaps) {
|
||||
assert_invariant(!pShadowMap->isDirectionalShadow());
|
||||
passList.push_back({
|
||||
{}, {}, pShadowMap, spotShadowCastersRange,
|
||||
{}, pShadowMap, spotShadowCastersRange,
|
||||
VISIBLE_DYN_SHADOW_RENDERABLE });
|
||||
if (pShadowMap->isPointShadow()) {
|
||||
// add the 5 extra faces
|
||||
for (uint8_t face = 1; face < 6; face++) {
|
||||
passList.push_back({
|
||||
{}, {}, pShadowMap, spotShadowCastersRange,
|
||||
VISIBLE_DYN_SHADOW_RENDERABLE, face });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,10 +199,8 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine
|
||||
// "read" from one of its resource (only writes), so the FrameGraph culls it.
|
||||
builder.sideEffect();
|
||||
},
|
||||
[this, &engine, &view, scene, &mainCameraInfo, &passTemplate = pass](
|
||||
[this, &engine, &view, scene, mainCameraInfo, userTime, passTemplate = pass](
|
||||
FrameGraphResources const& resources, auto const& data, DriverApi& driver) {
|
||||
// set uniforms needed to render this ShadowMap
|
||||
view.prepareShadowMap(view.getVsmShadowOptions().highPrecision);
|
||||
|
||||
// Note: we could almost parallel_for the loop below, the problem currently is
|
||||
// that updatePrimitivesLod() updates temporary global state.
|
||||
@@ -215,7 +215,9 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine
|
||||
// for spot shadow map, we need to do the culling
|
||||
switch (shadowMap.getShadowType()) {
|
||||
case ShadowType::DIRECTIONAL:
|
||||
// nothing to do, it's been done already
|
||||
shadowMap.prepareDirectionalLight(
|
||||
scene->getLightData().elementAt<FScene::DIRECTION>(0),
|
||||
scene->getLightData().elementAt<FScene::LIGHT_INSTANCE>(0));
|
||||
break;
|
||||
case ShadowType::SPOT:
|
||||
prepareSpotShadowMap(shadowMap, engine, view, mainCameraInfo,
|
||||
@@ -225,7 +227,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine
|
||||
case ShadowType::POINT:
|
||||
preparePointShadowMap(shadowMap, engine, view, mainCameraInfo,
|
||||
scene->getRenderableData(), entry.range,
|
||||
scene->getLightData(), entry.face, mSceneInfo);
|
||||
scene->getLightData(), mSceneInfo);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -243,6 +245,12 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine
|
||||
// cameraInfo only valid after calling update
|
||||
const CameraInfo cameraInfo{ shadowMap.getCamera() };
|
||||
|
||||
shadowMap.prepareCamera(cameraInfo);
|
||||
shadowMap.prepareViewport(shadowMap.getViewport());
|
||||
shadowMap.prepareTime(userTime);
|
||||
shadowMap.prepareShadowMapping(view.getVsmShadowOptions().highPrecision);
|
||||
shadowMap.commitUniforms(driver);
|
||||
|
||||
// updatePrimitivesLod must be run before RenderPass::appendCommands.
|
||||
view.updatePrimitivesLod(engine,
|
||||
cameraInfo, scene->getRenderableData(), entry.range);
|
||||
@@ -256,7 +264,24 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine
|
||||
pass.sortCommands(engine);
|
||||
|
||||
entry.executor = pass.getExecutor();
|
||||
entry.cameraInfo = cameraInfo;
|
||||
|
||||
if (!view.hasVSM()) {
|
||||
auto li = scene->getLightData().elementAt<FScene::LIGHT_INSTANCE>(
|
||||
entry.shadowMap->getLightIndex());
|
||||
|
||||
auto const& params = engine.getLightManager().getShadowParams(li);
|
||||
|
||||
const PolygonOffset polygonOffset = { // handle reversed Z
|
||||
.slope = -params.options.polygonOffsetSlope,
|
||||
.constant = -params.options.polygonOffsetConstant
|
||||
};
|
||||
entry.executor.overridePolygonOffset(&polygonOffset);
|
||||
}
|
||||
|
||||
constexpr const backend::Viewport disabledScissor{ 0, 0,
|
||||
(uint32_t)std::numeric_limits<int32_t>::max(),
|
||||
(uint32_t)std::numeric_limits<int32_t>::max() };
|
||||
entry.executor.overrideScissor(&disabledScissor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -274,8 +299,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine
|
||||
struct ShadowPassData {
|
||||
FrameGraphId<FrameGraphTexture> tempBlurSrc{}; // temporary shadowmap when blurring
|
||||
FrameGraphId<FrameGraphTexture> output;
|
||||
uint32_t blurRt{};
|
||||
uint32_t shadowRt{};
|
||||
uint32_t rt{};
|
||||
};
|
||||
|
||||
auto const& passList = prepareShadowPass.getData().passList;
|
||||
@@ -284,7 +308,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint8_t layer = entry.shadowMap->getLayer() + entry.face;
|
||||
const uint8_t layer = entry.shadowMap->getLayer();
|
||||
const auto* options = entry.shadowMap->getShadowOptions();
|
||||
|
||||
auto& shadowPass = fg.addPass<ShadowPassData>("Shadow Pass",
|
||||
@@ -333,7 +357,7 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine
|
||||
data.tempBlurSrc = builder.write(data.tempBlurSrc,
|
||||
FrameGraphTexture::Usage::COLOR_ATTACHMENT);
|
||||
|
||||
data.blurRt = builder.declareRenderPass("Temp Shadow RT", {
|
||||
data.rt = builder.declareRenderPass("Temp Shadow RT", {
|
||||
.attachments = {
|
||||
.color = { data.tempBlurSrc },
|
||||
.depth = depth },
|
||||
@@ -352,9 +376,13 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine
|
||||
}
|
||||
|
||||
// finally, create the shadowmap render target -- one per layer.
|
||||
data.shadowRt = builder.declareRenderPass("Shadow RT", renderTargetDesc);
|
||||
auto rt = builder.declareRenderPass("Shadow RT", renderTargetDesc);
|
||||
|
||||
// render either directly into the shadowmap, or to the temporary texture for
|
||||
// blurring.
|
||||
data.rt = blur ? data.rt : rt;
|
||||
},
|
||||
[=, &engine, &entry, &view](FrameGraphResources const& resources,
|
||||
[=, &engine, &entry](FrameGraphResources const& resources,
|
||||
auto const& data, DriverApi& driver) {
|
||||
|
||||
// Note: we capture entry by reference here. That's actually okay because
|
||||
@@ -364,62 +392,14 @@ FrameGraphId<FrameGraphTexture> ShadowMapManager::render(FrameGraph& fg, FEngine
|
||||
// It wouldn't work to capture by copy because entry.pass wouldn't be
|
||||
// initialized, as this happens in an `execute` block.
|
||||
|
||||
auto& executor = entry.executor;
|
||||
CameraInfo const& cameraInfo = entry.cameraInfo;
|
||||
entry.shadowMap->bindPerViewUniformsAndSamplers(driver);
|
||||
|
||||
const bool blur = view.hasVSM() && options->vsm.blurWidth > 0.0f;
|
||||
|
||||
// set uniforms relative to the camera
|
||||
view.prepareCamera(cameraInfo);
|
||||
|
||||
// We set a viewport with a 1-texel border for when we index outside the
|
||||
// texture.
|
||||
// DON'T CHANGE this unless ShadowMap::getTextureCoordsMapping() is updated too.
|
||||
// see: ShadowMap::getTextureCoordsMapping()
|
||||
//
|
||||
// For floating-point depth textures, the 1-texel border could be set to
|
||||
// FLOAT_MAX to avoid clamping in the shadow shader (see sampleDepth inside
|
||||
// shadowing.fs). Unfortunately, the APIs don't seem let us clear depth
|
||||
// attachments to anything greater than 1.0, so we'd need a way to do this other
|
||||
// than clearing.
|
||||
const uint32_t dim = options->mapSize;
|
||||
filament::Viewport viewport{ 1, 1, dim - 2, dim - 2 };
|
||||
if (entry.shadowMap->isPointShadow()) {
|
||||
// for point-light we don't have a border
|
||||
viewport = { 0, 0, dim, dim };
|
||||
}
|
||||
|
||||
view.prepareViewport(viewport, 0, 0);
|
||||
|
||||
view.commitUniforms(driver);
|
||||
|
||||
// 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;
|
||||
|
||||
constexpr const backend::Viewport disabledScissor{ 0, 0,
|
||||
(uint32_t)std::numeric_limits<int32_t>::max(),
|
||||
(uint32_t)std::numeric_limits<int32_t>::max() };
|
||||
|
||||
if (!view.hasVSM()) {
|
||||
auto li = scene->getLightData().elementAt<FScene::LIGHT_INSTANCE>(
|
||||
entry.shadowMap->getLightIndex());
|
||||
|
||||
auto const& params = engine.getLightManager().getShadowParams(li);
|
||||
|
||||
const PolygonOffset polygonOffset = { // handle reversed Z
|
||||
.slope = -params.options.polygonOffsetSlope,
|
||||
.constant = -params.options.polygonOffsetConstant
|
||||
};
|
||||
executor.overridePolygonOffset(&polygonOffset);
|
||||
}
|
||||
|
||||
executor.overrideScissor(&disabledScissor);
|
||||
auto rt = resources.getRenderPassInfo(data.rt);
|
||||
rt.params.viewport = entry.shadowMap->getViewport();
|
||||
|
||||
engine.flush();
|
||||
driver.beginRenderPass(rt.target, rt.params);
|
||||
executor.execute(engine, "Shadow Pass");
|
||||
entry.executor.execute(engine, "Shadow Pass");
|
||||
driver.endRenderPass();
|
||||
});
|
||||
|
||||
@@ -710,9 +690,10 @@ void ShadowMapManager::prepareSpotShadowMap(ShadowMap& shadowMap,
|
||||
void ShadowMapManager::preparePointShadowMap(ShadowMap& shadowMap,
|
||||
FEngine& engine, FView& view, CameraInfo const& mainCameraInfo,
|
||||
FScene::RenderableSoa& renderableData, utils::Range<uint32_t> range,
|
||||
FScene::LightSoa& lightData, uint8_t face,
|
||||
FScene::LightSoa& lightData,
|
||||
ShadowMap::SceneInfo const& sceneInfo) noexcept {
|
||||
|
||||
const uint8_t face = shadowMap.getFace();
|
||||
const size_t lightIndex = shadowMap.getLightIndex();
|
||||
FLightManager::ShadowOptions const* const options = shadowMap.getShadowOptions();
|
||||
|
||||
@@ -803,9 +784,15 @@ ShadowMapManager::ShadowTechnique ShadowMapManager::updateSpotShadowMaps(FEngine
|
||||
shadowTechnique |= ShadowTechnique::SHADOW_MAP;
|
||||
for (auto const* pShadowMap : mSpotShadowMaps) {
|
||||
const size_t lightIndex = pShadowMap->getLightIndex();
|
||||
shadowInfo[lightIndex].castsShadows = true; // FIXME: is that set correctly?
|
||||
shadowInfo[lightIndex].index = pShadowMap->getShadowIndex();
|
||||
shadowInfo[lightIndex].layer = pShadowMap->getLayer();
|
||||
|
||||
// FIXME: currently we have one slot per shadowmap in the UBO, but we now have up to
|
||||
// 6 shadowmap per light. So for now, we only write the data of the face 0,
|
||||
// and the shader will figure out where to find the other face (layer+face)
|
||||
if (pShadowMap->getFace() == 0) {
|
||||
shadowInfo[lightIndex].castsShadows = true; // FIXME: is that set correctly?
|
||||
shadowInfo[lightIndex].index = pShadowMap->getShadowIndex();
|
||||
shadowInfo[lightIndex].layer = pShadowMap->getLayer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -846,10 +833,6 @@ void ShadowMapManager::calculateTextureRequirements(FEngine& engine, FView& view
|
||||
maxDimension = std::max(maxDimension, options->mapSize);
|
||||
elvsm = elvsm || options->vsm.elvsm;
|
||||
pShadowMap->setLayer(layer++);
|
||||
if (pShadowMap->isPointShadow()) {
|
||||
// FIXME: we need to make sure we don't exceed 256
|
||||
layer += 5;
|
||||
}
|
||||
}
|
||||
|
||||
const uint8_t layersNeeded = layer;
|
||||
|
||||
@@ -90,8 +90,8 @@ public:
|
||||
FScene::RenderableSoa& renderableData, FScene::LightSoa& lightData) noexcept;
|
||||
|
||||
// Renders all the shadow maps.
|
||||
FrameGraphId<FrameGraphTexture> render(FrameGraph& fg, FEngine& engine,
|
||||
RenderPass const& pass, FView& view, CameraInfo const& mainCameraInfo) noexcept;
|
||||
FrameGraphId<FrameGraphTexture> render(FEngine& engine, FrameGraph& fg, RenderPass const& pass,
|
||||
FView& view, CameraInfo const& mainCameraInfo, math::float4 const& userTime) noexcept;
|
||||
|
||||
ShadowMap* getCascadeShadowMap(size_t cascade) noexcept {
|
||||
assert_invariant(cascade < CONFIG_MAX_SHADOW_CASCADES);
|
||||
@@ -140,7 +140,7 @@ private:
|
||||
void preparePointShadowMap(ShadowMap& map,
|
||||
FEngine& engine, FView& view, CameraInfo const& mainCameraInfo,
|
||||
FScene::RenderableSoa& renderableData, utils::Range<uint32_t> range,
|
||||
FScene::LightSoa& lightData, uint8_t face,
|
||||
FScene::LightSoa& lightData,
|
||||
ShadowMap::SceneInfo const& sceneInfo) noexcept;
|
||||
|
||||
static void updateSpotVisibilityMasks(
|
||||
|
||||
@@ -656,7 +656,7 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
|
||||
|
||||
RenderPass shadowPass(pass);
|
||||
shadowPass.setVariant(shadowVariant);
|
||||
auto shadows = view.renderShadowMaps(fg, engine, cameraInfo, shadowPass);
|
||||
auto shadows = view.renderShadowMaps(engine, fg, cameraInfo, mShaderUserTime, shadowPass);
|
||||
blackboard["shadows"] = shadows;
|
||||
}
|
||||
|
||||
@@ -740,8 +740,8 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
|
||||
|
||||
// view set-ups that need to happen before rendering
|
||||
fg.addTrivialSideEffectPass("Prepare View Uniforms",
|
||||
[=, &uniforms = view.getPerViewUniforms()](DriverApi& driver) {
|
||||
uniforms.prepareCamera(cameraInfo);
|
||||
[=, &view](DriverApi& driver) {
|
||||
view.prepareCamera(cameraInfo);
|
||||
|
||||
// The code here is a little fragile. In theory, we need to call prepareViewport()
|
||||
// for each render pass, because the viewport parameters depend on the resolution.
|
||||
@@ -761,11 +761,14 @@ void FRenderer::renderJob(ArenaScope& arena, FView& view) {
|
||||
// The reason why this bug is acceptable is that the viewport parameters are
|
||||
// currently only used for generating noise, so it's not too bad.
|
||||
|
||||
uniforms.prepareViewport(svp,
|
||||
view.prepareViewport(svp,
|
||||
xvp.left * aoOptions.resolution,
|
||||
xvp.bottom * aoOptions.resolution);
|
||||
|
||||
uniforms.commit(driver);
|
||||
view.commitUniforms(driver);
|
||||
|
||||
// set uniforms and samplers for the color passes
|
||||
view.bindPerViewUniformsAndSamplers(driver);
|
||||
});
|
||||
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
@@ -606,9 +606,19 @@ void FView::prepare(FEngine& engine, DriverApi& driver, ArenaScope& arena,
|
||||
mPerViewUniforms.prepareFog(cameraInfo.getPosition(), mFogOptions);
|
||||
mPerViewUniforms.prepareTemporalNoise(mTemporalAntiAliasingOptions);
|
||||
mPerViewUniforms.prepareBlending(needsAlphaChannel);
|
||||
}
|
||||
|
||||
// set uniforms and samplers
|
||||
bindPerViewUniformsAndSamplers(driver);
|
||||
void FView::bindPerViewUniformsAndSamplers(FEngine::DriverApi& driver) const noexcept {
|
||||
mPerViewUniforms.bind(driver);
|
||||
|
||||
driver.bindUniformBuffer(+UniformBindingPoints::LIGHTS,
|
||||
mLightUbh);
|
||||
|
||||
driver.bindUniformBuffer(+UniformBindingPoints::SHADOW,
|
||||
mShadowMapManager.getShadowUniformsHandle());
|
||||
|
||||
driver.bindUniformBuffer(+UniformBindingPoints::FROXEL_RECORDS,
|
||||
mFroxelizer.getRecordBuffer());
|
||||
}
|
||||
|
||||
void FView::computeVisibilityMasks(
|
||||
@@ -656,7 +666,9 @@ UTILS_NOINLINE
|
||||
|
||||
void FView::prepareUpscaler(float2 scale) const noexcept {
|
||||
SYSTRACE_CALL();
|
||||
mPerViewUniforms.prepareUpscaler(scale, mDynamicResolution);
|
||||
const float bias = (mDynamicResolution.quality >= QualityLevel::HIGH) ?
|
||||
std::log2(std::min(scale.x, scale.y)) : 0.0f;
|
||||
mPerViewUniforms.prepareLodBias(bias);
|
||||
}
|
||||
|
||||
void FView::prepareCamera(const CameraInfo& cameraInfo) const noexcept {
|
||||
@@ -711,7 +723,7 @@ void FView::prepareShadow(Handle<HwTexture> texture) const noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void FView::prepareShadowMap(bool highPrecision) const noexcept {
|
||||
void FView::prepareShadowMapping(bool highPrecision) const noexcept {
|
||||
mPerViewUniforms.prepareShadowMapping(highPrecision);
|
||||
}
|
||||
|
||||
@@ -894,9 +906,9 @@ void FView::updatePrimitivesLod(FEngine& engine, const CameraInfo&,
|
||||
}
|
||||
}
|
||||
|
||||
FrameGraphId<FrameGraphTexture> FView::renderShadowMaps(FrameGraph& fg, FEngine& engine,
|
||||
CameraInfo const& cameraInfo, RenderPass const& pass) noexcept {
|
||||
return mShadowMapManager.render(fg, engine, pass, *this, cameraInfo);
|
||||
FrameGraphId<FrameGraphTexture> FView::renderShadowMaps(FEngine& engine, FrameGraph& fg,
|
||||
CameraInfo const& cameraInfo, float4 const& userTime, RenderPass const& pass) noexcept {
|
||||
return mShadowMapManager.render(engine, fg, pass, *this, cameraInfo, userTime);
|
||||
}
|
||||
|
||||
void FView::commitFrameHistory(FEngine& engine) noexcept {
|
||||
|
||||
@@ -92,6 +92,8 @@ public:
|
||||
filament::Viewport const& viewport, CameraInfo const& cameraInfo,
|
||||
math::float4 const& userTime, bool needsAlphaChannel) noexcept;
|
||||
|
||||
void bindPerViewUniformsAndSamplers(FEngine::DriverApi& driver) const noexcept;
|
||||
|
||||
void setScene(FScene* scene) { mScene = scene; }
|
||||
FScene const* getScene() const noexcept { return mScene; }
|
||||
FScene* getScene() noexcept { return mScene; }
|
||||
@@ -148,7 +150,7 @@ public:
|
||||
ScreenSpaceReflectionsOptions const& ssrOptions) const noexcept;
|
||||
void prepareStructure(backend::Handle<backend::HwTexture> structure) const noexcept;
|
||||
void prepareShadow(backend::Handle<backend::HwTexture> structure) const noexcept;
|
||||
void prepareShadowMap(bool highPrecision) const noexcept;
|
||||
void prepareShadowMapping(bool highPrecision) const noexcept;
|
||||
|
||||
void cleanupRenderPasses() const noexcept;
|
||||
void froxelize(FEngine& engine, math::mat4f const& viewMatrix) const noexcept;
|
||||
@@ -165,8 +167,9 @@ public:
|
||||
bool hasPCSS() const noexcept { return mShadowType == ShadowType::PCSS; }
|
||||
bool hasPicking() const noexcept { return mActivePickingQueriesList != nullptr; }
|
||||
|
||||
FrameGraphId<FrameGraphTexture> renderShadowMaps(FrameGraph& fg, FEngine& engine,
|
||||
CameraInfo const& cameraInfo, RenderPass const& pass) noexcept;
|
||||
FrameGraphId<FrameGraphTexture> renderShadowMaps(FEngine& engine, FrameGraph& fg,
|
||||
CameraInfo const& cameraInfo, math::float4 const& userTime,
|
||||
RenderPass const& pass) noexcept;
|
||||
|
||||
void updatePrimitivesLod(
|
||||
FEngine& engine, const CameraInfo& camera,
|
||||
@@ -451,13 +454,6 @@ private:
|
||||
Culler::result_type* visibleMask,
|
||||
size_t count);
|
||||
|
||||
void bindPerViewUniformsAndSamplers(FEngine::DriverApi& driver) const noexcept {
|
||||
mPerViewUniforms.bind(driver);
|
||||
driver.bindUniformBuffer(+UniformBindingPoints::LIGHTS, mLightUbh);
|
||||
driver.bindUniformBuffer(+UniformBindingPoints::SHADOW, mShadowMapManager.getShadowUniformsHandle());
|
||||
driver.bindUniformBuffer(+UniformBindingPoints::FROXEL_RECORDS, mFroxelizer.getRecordBuffer());
|
||||
}
|
||||
|
||||
// Clean-up the whole history, free all resources. This is typically called when the View is
|
||||
// being terminated.
|
||||
void drainFrameHistory(FEngine& engine) noexcept;
|
||||
|
||||
Reference in New Issue
Block a user