Add smooth shadows blending between directional light cascades
It was deprecated in 1.9 in favor for dithering between cascades. Bing back that option for games that don't use TAA.
This commit is contained in:
@@ -61,10 +61,9 @@ public:
|
||||
|
||||
/// <summary>
|
||||
/// Enables cascades splits blending for directional light shadows.
|
||||
/// [Deprecated in v1.9]
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(1320), DefaultValue(false), EditorDisplay(\"Quality\", \"Allow CSM Blending\")")
|
||||
DEPRECATED() bool AllowCSMBlending = false;
|
||||
bool AllowCSMBlending = false;
|
||||
|
||||
/// <summary>
|
||||
/// Default probes cubemap resolution (use for Environment Probes, can be overriden per-actor).
|
||||
|
||||
@@ -69,6 +69,7 @@ void GraphicsSettings::Apply()
|
||||
Graphics::VolumetricFogQuality = VolumetricFogQuality;
|
||||
Graphics::ShadowsQuality = ShadowsQuality;
|
||||
Graphics::ShadowMapsQuality = ShadowMapsQuality;
|
||||
Graphics::AllowCSMBlending = AllowCSMBlending;
|
||||
Graphics::GlobalSDFQuality = GlobalSDFQuality;
|
||||
Graphics::GIQuality = GIQuality;
|
||||
Graphics::GICascadesBlending = GICascadesBlending;
|
||||
|
||||
@@ -55,9 +55,8 @@ public:
|
||||
|
||||
/// <summary>
|
||||
/// Enables cascades splits blending for directional light shadows.
|
||||
/// [Deprecated in v1.9]
|
||||
/// </summary>
|
||||
API_FIELD() DEPRECATED() static bool AllowCSMBlending;
|
||||
API_FIELD() static bool AllowCSMBlending;
|
||||
|
||||
/// <summary>
|
||||
/// The Global SDF quality. Controls the volume texture resolution and amount of cascades to use.
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#define SHADOWS_MAX_TILES 6
|
||||
#define SHADOWS_MIN_RESOLUTION 32
|
||||
#define SHADOWS_MAX_STATIC_ATLAS_CAPACITY_TO_DEFRAG 0.7f
|
||||
#define SHADOWS_BASE_LIGHT_RESOLUTION(atlasResolution) atlasResolution / MAX_CSM_CASCADES // Allow to store 4 CSM cascades in a single row in all cases
|
||||
#define SHADOWS_BASE_LIGHT_RESOLUTION(atlasResolution) (atlasResolution / MAX_CSM_CASCADES) // Allow to store 4 CSM cascades in a single row in all cases
|
||||
#define NormalOffsetScaleTweak METERS_TO_UNITS(1)
|
||||
#define LocalLightNearPlane METERS_TO_UNITS(0.1f)
|
||||
|
||||
@@ -190,6 +190,7 @@ struct ShadowAtlasLight
|
||||
uint8 TilesNeeded;
|
||||
uint8 TilesCount;
|
||||
bool HasStaticShadowContext;
|
||||
bool BlendCSM;
|
||||
mutable StaticStates StaticState;
|
||||
BoundingSphere Bounds;
|
||||
float Sharpness, Fade, NormalOffsetScale, Bias, FadeDistance, Distance, TileBorder;
|
||||
@@ -769,6 +770,15 @@ void ShadowsPass::SetupLight(ShadowsCustomBuffer& shadows, RenderContext& render
|
||||
const RenderView& view = renderContext.View;
|
||||
const int32 csmCount = atlasLight.TilesCount;
|
||||
const auto shadowMapsSize = (float)atlasLight.Resolution;
|
||||
atlasLight.BlendCSM = Graphics::AllowCSMBlending;
|
||||
#if USE_EDITOR
|
||||
// Disable cascades blending when baking lightmaps
|
||||
if (IsRunningRadiancePass)
|
||||
atlasLight.BlendCSM = false;
|
||||
#elif PLATFORM_SWITCH || PLATFORM_IOS || PLATFORM_ANDROID
|
||||
// Disable cascades blending on low-end platforms
|
||||
atlasLight.BlendCSM = false;
|
||||
#endif
|
||||
|
||||
// Calculate cascade splits
|
||||
const float minDistance = view.Near;
|
||||
@@ -895,7 +905,8 @@ void ShadowsPass::SetupLight(ShadowsCustomBuffer& shadows, RenderContext& render
|
||||
Float3 frustumCornersVs[8];
|
||||
for (int32 j = 0; j < 4; j++)
|
||||
{
|
||||
float overlapWithPrevSplit = 0.1f * (splitMinRatio - oldSplitMinRatio); // CSM blending overlap
|
||||
float csmOverlap = atlasLight.BlendCSM ? 0.2f : 0.1f;
|
||||
float overlapWithPrevSplit = csmOverlap * (splitMinRatio - oldSplitMinRatio);
|
||||
const auto frustumRangeVS = frustumCorners[j + 4] - frustumCorners[j];
|
||||
frustumCornersVs[j] = frustumCorners[j] + frustumRangeVS * (splitMinRatio - overlapWithPrevSplit);
|
||||
frustumCornersVs[j + 4] = frustumCorners[j] + frustumRangeVS * splitMaxRatio;
|
||||
@@ -1602,7 +1613,9 @@ void ShadowsPass::RenderShadowMask(RenderContextBatch& renderContextBatch, Rende
|
||||
}
|
||||
else //if (light.IsDirectionalLight)
|
||||
{
|
||||
context->SetState(_psShadowDir.Get(permutationIndex));
|
||||
auto* atlasLight = shadows.Lights.TryGet(light.ID);
|
||||
ASSERT_LOW_LAYER(atlasLight);
|
||||
context->SetState(_psShadowDir.Get(permutationIndex + (atlasLight->BlendCSM ? 8 : 0)));
|
||||
context->DrawFullscreenTriangle();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,11 +19,11 @@ private:
|
||||
AssetReference<Model> _sphereModel;
|
||||
GPUPipelineState* _psDepthClear = nullptr;
|
||||
GPUPipelineState* _psDepthCopy = nullptr;
|
||||
GPUPipelineStatePermutationsPs<static_cast<int32>(Quality::MAX) * 2> _psShadowDir;
|
||||
GPUPipelineStatePermutationsPs<static_cast<int32>(Quality::MAX) * 2> _psShadowPoint;
|
||||
GPUPipelineStatePermutationsPs<static_cast<int32>(Quality::MAX) * 2> _psShadowPointInside;
|
||||
GPUPipelineStatePermutationsPs<static_cast<int32>(Quality::MAX) * 2> _psShadowSpot;
|
||||
GPUPipelineStatePermutationsPs<static_cast<int32>(Quality::MAX) * 2> _psShadowSpotInside;
|
||||
GPUPipelineStatePermutationsPs<int32(Quality::MAX) * 2 * 2> _psShadowDir;
|
||||
GPUPipelineStatePermutationsPs<int32(Quality::MAX) * 2> _psShadowPoint;
|
||||
GPUPipelineStatePermutationsPs<int32(Quality::MAX) * 2> _psShadowPointInside;
|
||||
GPUPipelineStatePermutationsPs<int32(Quality::MAX) * 2> _psShadowSpot;
|
||||
GPUPipelineStatePermutationsPs<int32(Quality::MAX) * 2> _psShadowSpotInside;
|
||||
PixelFormat _shadowMapFormat; // Cached on initialization
|
||||
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user