Refactor shadows rendering to use Shadow Map Atlas

This commit is contained in:
Wojtek Figat
2024-04-04 12:54:07 +02:00
parent 017def29d4
commit 61323f8526
31 changed files with 1115 additions and 1826 deletions

View File

@@ -12,32 +12,57 @@
#ifndef SHADOWS_QUALITY
#define SHADOWS_QUALITY 0
#endif
#ifndef CSM_BLENDING
#define CSM_BLENDING 0
#endif
// Structure that contains information about light
struct LightShadowData
// Shadow data for the light
struct ShadowData
{
float2 ShadowMapSize;
float Sharpness;
float Fade;
float FadeDistance;
float NormalOffsetScale;
float Bias;
float FadeDistance;
uint NumCascades;
uint TilesCount;
float4 CascadeSplits;
float4x4 ShadowVP[6];
};
#ifdef PLATFORM_ANDROID
// #AdrenoVK_CB_STRUCT_MEMBER_ACCESS_BUG
#define DECLARE_LIGHTSHADOWDATA_ACCESS(uniformName) LightShadowData Get##uniformName##Data() { LightShadowData tmp; tmp.ShadowMapSize = uniformName.ShadowMapSize; tmp.Sharpness = uniformName.Sharpness; tmp.Fade = uniformName.Fade; tmp.NormalOffsetScale = uniformName.NormalOffsetScale; tmp.Bias = uniformName.Bias; tmp.FadeDistance = uniformName.FadeDistance; tmp.NumCascades = uniformName.NumCascades; tmp.CascadeSplits = uniformName.CascadeSplits; tmp.ShadowVP[0] = uniformName.ShadowVP[0]; tmp.ShadowVP[1] = uniformName.ShadowVP[1]; tmp.ShadowVP[2] = uniformName.ShadowVP[2]; tmp.ShadowVP[3] = uniformName.ShadowVP[3]; tmp.ShadowVP[4] = uniformName.ShadowVP[4]; tmp.ShadowVP[5] = uniformName.ShadowVP[5]; return tmp; }
#else
#define DECLARE_LIGHTSHADOWDATA_ACCESS(uniformName) LightShadowData Get##uniformName##Data() { return uniformName; }
#endif
// Shadow projection tile data for the light
struct ShadowTileData
{
float4 ShadowToAtlas;
float4x4 WorldToShadow;
};
// Loads the shadow data of the light in the shadow buffer
ShadowData LoadShadowsBuffer(Buffer<float4> shadowsBuffer, uint shadowsBufferAddress)
{
// This must match C++
float4 vector0 = shadowsBuffer.Load(shadowsBufferAddress + 0);
float4 vector1 = shadowsBuffer.Load(shadowsBufferAddress + 1);
ShadowData shadow;
uint packed0x = asuint(vector0.x);
shadow.Sharpness = (packed0x & 0x000000ff) * (10.0f / 255.0f);
shadow.Fade = ((packed0x & 0x0000ff00) >> 8) * (1.0f / 255.0f);
shadow.TilesCount = ((packed0x & 0x00ff0000) >> 16);
shadow.FadeDistance = vector0.y;
shadow.NormalOffsetScale = vector0.z;
shadow.Bias = vector0.w;
shadow.CascadeSplits = vector1;
return shadow;
}
// Loads the shadow tile data of the light in the shadow buffer
ShadowTileData LoadShadowsBufferTile(Buffer<float4> shadowsBuffer, uint shadowsBufferAddress, uint tileIndex)
{
// This must match C++
shadowsBufferAddress += tileIndex * 5 + 2;
ShadowTileData tile;
tile.ShadowToAtlas = shadowsBuffer.Load(shadowsBufferAddress + 0);
tile.WorldToShadow[0] = shadowsBuffer.Load(shadowsBufferAddress + 1);
tile.WorldToShadow[1] = shadowsBuffer.Load(shadowsBufferAddress + 2);
tile.WorldToShadow[2] = shadowsBuffer.Load(shadowsBufferAddress + 3);
tile.WorldToShadow[3] = shadowsBuffer.Load(shadowsBufferAddress + 4);
return tile;
}
float3 GetShadowPositionOffset(float offsetScale, float NoL, float3 normal)
{
@@ -48,8 +73,16 @@ float3 GetShadowPositionOffset(float offsetScale, float NoL, float3 normal)
float CalculateSubsurfaceOcclusion(float opacity, float sceneDepth, float shadowMapDepth)
{
float thickness = max(sceneDepth - shadowMapDepth, 0);
float occlusion = 1 - thickness * lerp(1.0f, 100.0f, opacity);
float occlusion = 1 - saturate(thickness * lerp(1.0f, 100.0f, opacity));
return shadowMapDepth > 0.99f ? 1 : occlusion;
}
float PostProcessShadow(ShadowData lightShadow, float shadow)
{
// Apply shadow fade and sharpness
shadow = saturate((shadow - 0.5) * lightShadow.Sharpness + 0.5);
shadow = lerp(1.0f, shadow, lightShadow.Fade);
return shadow;
}
#endif