Got some issues making ESMs work. Here's my workflow:
- Render exp(depth) into shadow maps
- Horizontal+Vertical blur said shadow maps
- Test in lighting pass
The problem is the shadow maps are just pure white, when looking at them in the debugger, making the comparison garbage. If I render only depth (no exp(depth)) it works just fine (of course I have to change step 3 though)
The shaders used:
Step 1:
#ifndef EXP_DEPTH_PIXEL_HLSL
#define EXP_DEPTH_PIXEL_HLSL
float ps_main(float4 position : SV_Position) : SV_Depth
{
return exp(position.z / position.w);
}
#endif
Step 2:
#ifndef BOX_BLUR_PIXEL_HLSL
#define BOX_BLUR_PIXEL_HLSL
#include "Constants.hlsl"
cbuffer BoxBlurConstants : register(CBUFFER_REGISTER_PIXEL)
{
// (1 / TEXTURE_WIDTH, 0) for horizontal pass, (0, 1 / TEXTURE_HEIGHT) for vertical pass
float2 gTexelSize;
float gTextureIndex;
};
SamplerState gSampler : register(SAMPLER_REGISTER_DEPTH_NO_COMPARE);
Texture2DArray gDepthTexture : register(TEXTURE_REGISTER_DEPTH);
static const uint NUM_SAMPLES = 7;
float ps_main(float4 position : SV_Position) : SV_Depth
{
float ret = 0.0;
for (int i = -3; i <= 3; i++)
{
const float2 texCoord = (uint2)position.xy + i;
ret += gDepthTexture[float3(texCoord, gTextureIndex)].r;
}
ret /= NUM_SAMPLES;
return ret;
}
#endif
Step 3:
#ifndef DIRECTIONAL_LIGHT_PIXEL_HLSL
#define DIRECTIONAL_LIGHT_PIXEL_HLSL
#include "FullscreenTriangleVertex.hlsl"
#include "Constants.hlsl"
#define DEPTH_BIAS 0.005
#define NUM_CASCADES 4
#define ESM_CONSTANT 10
cbuffer DirectionalLightConstants : register(CBUFFER_REGISTER_PIXEL)
{
float4x4 gSplitVPMatrices[NUM_CASCADES];
float4x4 gCameraViewMatrix;
float4 gSplitDistances;
float4 gLightColor;
float4 gLightDirection;
};
Texture2D gPositionTexture : register(TEXTURE_REGISTER_POSITION);
Texture2D gDiffuseTexture : register(TEXTURE_REGISTER_DIFFUSE);
Texture2D gNormalTexture : register(TEXTURE_REGISTER_NORMAL);
Texture2DArray gShadowmap : register(TEXTURE_REGISTER_DEPTH);
SamplerState gShadowmapSampler : register(SAMPLER_REGISTER_DEPTH_NO_COMPARE);
float4 ps_main(float4 position : SV_Position) : SV_Target0
{
float4 worldPos = gPositionTexture[uint2(position.xy)];
float4 diffuse = gDiffuseTexture[uint2(position.xy)];
float4 normal = gNormalTexture[uint2(position.xy)];
float4 camPos = mul(gCameraViewMatrix, worldPos);
uint index = 3;
if (camPos.z > gSplitDistances.x)
index = 0;
else if (camPos.z > gSplitDistances.y)
index = 1;
else if (camPos.z > gSplitDistances.z)
index = 2;
float3 projCoords = (float3)mul(gSplitVPMatrices[index], worldPos);
const float2 texelSize = 1.0 / float2(1024.0, 1024.0);
projCoords.xy = (floor(projCoords.xy / texelSize)) * texelSize;
float viewDepth = projCoords.z - DEPTH_BIAS;
projCoords.z = float(index);
//float visibilty = gShadowmap.SampleCmpLevelZero(gShadowmapSampler, projCoords, viewDepth);
float occluder = gShadowmap.Sample(gShadowmapSampler, projCoords).r;
float visibility = occluder / exp(ESM_CONSTANT * viewDepth);
float angleNormal = clamp(dot(normal, gLightDirection), 0, 1);
return visibility * diffuse * angleNormal * gLightColor;
}
#endif
It strikes me though, maybe the shadow map needs to cleared with a different default depth value... but what?