Fix VSM mipmap generation
- the clear color was broken since we switched dot EVSM - use the scissor instead of the viewport, it makes it easier to compute the uv-scale. - the min/max lod level wasn't reset properly - also clamp the minimum shadowmap size to 8, and document it.
This commit is contained in:
committed by
Mathias Agopian
parent
61bf472426
commit
4b5dc5b3af
+1
-1
@@ -188,7 +188,7 @@ public class LightManager {
|
||||
* Control the quality / performance of the shadow map associated to this light
|
||||
*/
|
||||
public static class ShadowOptions {
|
||||
/** Size of the shadow map in texels. Must be a power-of-two. */
|
||||
/** Size of the shadow map in texels. Must be a power-of-two and larger or equal to 8. */
|
||||
public int mapSize = 1024;
|
||||
|
||||
/**
|
||||
|
||||
@@ -189,7 +189,7 @@ public:
|
||||
* Control the quality / performance of the shadow map associated to this light
|
||||
*/
|
||||
struct ShadowOptions {
|
||||
/** Size of the shadow map in texels. Must be a power-of-two. */
|
||||
/** Size of the shadow map in texels. Must be a power-of-two and larger or equal to 8. */
|
||||
uint32_t mapSize = 1024;
|
||||
|
||||
/**
|
||||
|
||||
@@ -757,7 +757,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::gaussianBlurPass(FrameGraph&
|
||||
data.temp = builder.sample(data.temp);
|
||||
data.temp = builder.declareRenderPass(data.temp);
|
||||
|
||||
data.out = builder.createSubresource(output, "Blurred texture mip",{ .level = dstLevel, .layer = layer });
|
||||
data.out = builder.createSubresource(output, "Blurred texture mip",
|
||||
{ .level = dstLevel, .layer = layer });
|
||||
data.out = builder.declareRenderPass(data.out);
|
||||
},
|
||||
[=](FrameGraphResources const& resources,
|
||||
@@ -2320,7 +2321,8 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::resolve(FrameGraph& fg,
|
||||
}
|
||||
|
||||
FrameGraphId<FrameGraphTexture> PostProcessManager::vsmMipmapPass(FrameGraph& fg,
|
||||
FrameGraphId<FrameGraphTexture> input, uint8_t layer, size_t level, bool finalize) noexcept {
|
||||
FrameGraphId<FrameGraphTexture> input, uint8_t layer, size_t level,
|
||||
math::float4 clearColor, bool finalize) noexcept {
|
||||
|
||||
struct VsmMipData {
|
||||
FrameGraphId<FrameGraphTexture> in;
|
||||
@@ -2337,7 +2339,7 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::vsmMipmapPass(FrameGraph& fg
|
||||
out = builder.write(out, FrameGraphTexture::Usage::COLOR_ATTACHMENT);
|
||||
builder.declareRenderPass(name, {
|
||||
.attachments = { .color = { out }},
|
||||
.clearColor = { 1.0f, 1.0f, 1.0f, 1.0f },
|
||||
.clearColor = clearColor,
|
||||
.clearFlags = TargetBufferFlags::COLOR
|
||||
});
|
||||
},
|
||||
@@ -2355,6 +2357,12 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::vsmMipmapPass(FrameGraph& fg
|
||||
driver.setMinMaxLevels(in, level, level);
|
||||
|
||||
auto& material = getPostProcessMaterial("vsmMipmap");
|
||||
|
||||
// When generating shadow map mip levels, we want to preserve the 1 texel border.
|
||||
// (note clearing never respects the scissor in filament)
|
||||
PipelineState pipeline(material.getPipelineState());
|
||||
pipeline.scissor = { 1u, 1u, dim - 2u, dim - 2u };
|
||||
|
||||
FMaterialInstance* const mi = material.getMaterialInstance();
|
||||
mi->setParameter("color", in, {
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
@@ -2363,12 +2371,12 @@ FrameGraphId<FrameGraphTexture> PostProcessManager::vsmMipmapPass(FrameGraph& fg
|
||||
mi->setParameter("level", uint32_t(level));
|
||||
mi->setParameter("layer", uint32_t(layer));
|
||||
mi->setParameter("uvscale", 1.0f / dim);
|
||||
mi->commit(driver);
|
||||
mi->use(driver);
|
||||
|
||||
// When generating shadow map mip levels, we want to preserve the 1 texel border.
|
||||
auto vpWidth = (uint32_t) std::max(0, dim - 2);
|
||||
out.params.viewport = { 1, 1, vpWidth, vpWidth };
|
||||
|
||||
commitAndRender(out, material, driver);
|
||||
driver.beginRenderPass(out.target, out.params);
|
||||
driver.draw(pipeline, mEngine.getFullScreenRenderPrimitive());
|
||||
driver.endRenderPass();
|
||||
|
||||
if (finalize) {
|
||||
driver.setMinMaxLevels(in, 0, level);
|
||||
|
||||
@@ -131,7 +131,8 @@ public:
|
||||
|
||||
// VSM shadow mipmap pass
|
||||
FrameGraphId<FrameGraphTexture> vsmMipmapPass(FrameGraph& fg,
|
||||
FrameGraphId<FrameGraphTexture> input, uint8_t layer, size_t level, bool finalize) noexcept;
|
||||
FrameGraphId<FrameGraphTexture> input, uint8_t layer, size_t level,
|
||||
math::float4 clearColor, bool finalize) noexcept;
|
||||
|
||||
FrameGraphId<FrameGraphTexture> gaussianBlurPass(FrameGraph& fg,
|
||||
FrameGraphId<FrameGraphTexture> input, uint8_t srcLevel,
|
||||
|
||||
@@ -120,6 +120,10 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, FView& view,
|
||||
passes.emplace_back(&map, pass);
|
||||
}
|
||||
|
||||
const float vsmMoment2 = std::numeric_limits<math::half>::max();
|
||||
const float vsmMoment1 = std::sqrt(vsmMoment2);
|
||||
const float4 vsmClearColor{ vsmMoment1, vsmMoment2, 0.0f, 0.0f };
|
||||
|
||||
assert_invariant(passes.size() <= textureRequirements.layers);
|
||||
|
||||
// -------------------------------------------------------------------------------------------
|
||||
@@ -202,7 +206,7 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, FView& view,
|
||||
renderTargetDesc.clearFlags =
|
||||
TargetBufferFlags::COLOR | TargetBufferFlags::DEPTH;
|
||||
// we need to clear the shadow map with the max EVSM moments
|
||||
renderTargetDesc.clearColor = { 256.0f, 65536.f, 0.0f, 0.0f };
|
||||
renderTargetDesc.clearColor = vsmClearColor;
|
||||
renderTargetDesc.samples = options->vsm.msaaSamples;
|
||||
|
||||
if (blur) {
|
||||
@@ -213,7 +217,7 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, FView& view,
|
||||
.attachments = {
|
||||
.color = { data.tempBlurSrc },
|
||||
.depth = depth },
|
||||
.clearColor = { 256.0f, 65536.f, 256.0f, 65536.f },
|
||||
.clearColor = vsmClearColor,
|
||||
.samples = options->vsm.msaaSamples,
|
||||
.clearFlags = TargetBufferFlags::COLOR
|
||||
| TargetBufferFlags::DEPTH
|
||||
@@ -294,8 +298,9 @@ void ShadowMapManager::render(FrameGraph& fg, FEngine& engine, FView& view,
|
||||
// So generate the mipmaps for each layer
|
||||
if (textureRequirements.levels > 1) {
|
||||
for (size_t level = 0; level < textureRequirements.levels - 1; level++) {
|
||||
const bool finalize = textureRequirements.levels - 2;
|
||||
shadows = ppm.vsmMipmapPass(fg, shadows, layer, level, finalize);
|
||||
const bool finalize = level == textureRequirements.levels - 2;
|
||||
shadows = ppm.vsmMipmapPass(fg, shadows, layer, level,
|
||||
vsmClearColor, finalize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -708,7 +708,7 @@ void FView::prepareShadow(backend::Handle<backend::HwTexture> texture) const noe
|
||||
texture, {
|
||||
.filterMag = SamplerMagFilter::LINEAR,
|
||||
.filterMin = filterMin,
|
||||
.anisotropyLog2 = anisotropy,
|
||||
.anisotropyLog2 = anisotropy, // ignored for PCF
|
||||
.compareMode = SamplerCompareMode::COMPARE_TO_TEXTURE, // ignored for VSM
|
||||
.compareFunc = SamplerCompareFunc::GE // ignored for VSM
|
||||
}});
|
||||
|
||||
@@ -171,27 +171,8 @@ void FLightManager::create(const FLightManager::Builder& builder, utils::Entity
|
||||
lightType.shadowCaster = builder->mCastShadows;
|
||||
lightType.lightCaster = builder->mCastLight;
|
||||
|
||||
ShadowParams& shadowParams = manager[i].shadowParams;
|
||||
shadowParams.options = builder->mShadowOptions;
|
||||
|
||||
// validate all shadow options
|
||||
shadowParams.options.mapSize = clamp(shadowParams.options.mapSize, 0u, 2048u);
|
||||
shadowParams.options.shadowCascades = clamp<uint8_t>(shadowParams.options.shadowCascades, 1, CONFIG_MAX_SHADOW_CASCADES);
|
||||
shadowParams.options.constantBias = clamp(shadowParams.options.constantBias, 0.0f, 2.0f);
|
||||
shadowParams.options.normalBias = clamp(shadowParams.options.normalBias, 0.0f, 3.0f);
|
||||
shadowParams.options.shadowFar = std::max(shadowParams.options.shadowFar, 0.0f);
|
||||
shadowParams.options.shadowNearHint = std::max(shadowParams.options.shadowNearHint, 0.0f);
|
||||
shadowParams.options.shadowFarHint = std::max(shadowParams.options.shadowFarHint, 0.0f);
|
||||
shadowParams.options.stable = shadowParams.options.stable;
|
||||
shadowParams.options.polygonOffsetConstant = shadowParams.options.polygonOffsetConstant;
|
||||
shadowParams.options.polygonOffsetSlope = shadowParams.options.polygonOffsetSlope;
|
||||
shadowParams.options.screenSpaceContactShadows = shadowParams.options.screenSpaceContactShadows;
|
||||
shadowParams.options.stepCount = shadowParams.options.stepCount;
|
||||
shadowParams.options.maxShadowDistance = shadowParams.options.maxShadowDistance;
|
||||
shadowParams.options.vsm.msaaSamples = std::max(uint8_t(0), shadowParams.options.vsm.msaaSamples);
|
||||
shadowParams.options.vsm.blurWidth = std::max(0.0f, shadowParams.options.vsm.blurWidth);
|
||||
|
||||
// set default values by calling the setters
|
||||
setShadowOptions(i, builder->mShadowOptions);
|
||||
setLocalPosition(i, builder->mPosition);
|
||||
setLocalDirection(i, builder->mDirection);
|
||||
setColor(i, builder->mColor);
|
||||
@@ -232,6 +213,20 @@ void FLightManager::terminate() noexcept {
|
||||
}
|
||||
}
|
||||
|
||||
void FLightManager::setShadowOptions(Instance i, ShadowOptions const& options) noexcept {
|
||||
ShadowParams& params = mManager[i].shadowParams;
|
||||
params.options = options;
|
||||
params.options.mapSize = clamp(options.mapSize, 8u, 2048u);
|
||||
params.options.shadowCascades = clamp<uint8_t>(options.shadowCascades, 1, CONFIG_MAX_SHADOW_CASCADES);
|
||||
params.options.constantBias = clamp(options.constantBias, 0.0f, 2.0f);
|
||||
params.options.normalBias = clamp(options.normalBias, 0.0f, 3.0f);
|
||||
params.options.shadowFar = std::max(options.shadowFar, 0.0f);
|
||||
params.options.shadowNearHint = std::max(options.shadowNearHint, 0.0f);
|
||||
params.options.shadowFarHint = std::max(options.shadowFarHint, 0.0f);
|
||||
params.options.vsm.msaaSamples = std::max(uint8_t(0), options.vsm.msaaSamples);
|
||||
params.options.vsm.blurWidth = std::max(0.0f, options.vsm.blurWidth);
|
||||
}
|
||||
|
||||
void FLightManager::setLocalPosition(Instance i, const float3& position) noexcept {
|
||||
assert_invariant(i);
|
||||
auto& manager = mManager;
|
||||
|
||||
@@ -221,10 +221,7 @@ public:
|
||||
return getShadowParams(i).options;
|
||||
}
|
||||
|
||||
void setShadowOptions(Instance i, ShadowOptions const& options) noexcept {
|
||||
ShadowParams& params = mManager[i].shadowParams;
|
||||
params.options = options;
|
||||
}
|
||||
void setShadowOptions(Instance i, ShadowOptions const& options) noexcept;
|
||||
|
||||
private:
|
||||
friend class FScene;
|
||||
|
||||
Reference in New Issue
Block a user