hello,
i am optimizing my shadowmap sampling in my own game engine.
Until now i have implemented typical PCS for directional and point lights.
As we all know the amount of samples that have to be fetched from the shadow texture per pixel is N * N.
I want to reduce the amount of fetched pixels to 2 * N with the following
1. renderpass -> float RenderTarget
Typical Shadowmap pass -> writing geometry to shadow depthmap from light viewpoint
Loop over all lights with individual shadowmaps
2a. renderpass -> tmp RenderTarget ( which format is smallest or best ??? )
read GBuffer depth Map compare with individual shadowmap depth and store result => so the Info is only has shadow or not
e.g. point lights are written with sphere geometry only the coresponding pixels will be evaluated in the pixel shader
end Loop
result => screenspace shadow texture (unsoftend)
3/4. renderpass -> tmp float or halfe float RenderTarget
typical gaussian blur separable with desired Kernel Size N => 2 * N texture fetches ( row pass / colum pass)
result => screenspace shadow texture (softend)
5. renderpass -> lightning pass as usual feeded with our already softened shadow texture
Pro:
- a. no additional Texture Memory is needed only tmp rendertarget textures
- b. the shadowmap fetching of large Kernel sizes ist faster N*N vs. 2 *N
Con:
- the geometry e.g. sphere geometry per light has to be written twice.
- the depth has to be read and reconstructed twice
Do i miss something ? Is this route worth the effort ?
//[unroll] is better, but can't be used when dynamically changing size
[loop]
for (float y = -fRadius; y <= fRadius; y++)
{
[loop]
for (float x = -fRadius; x <= fRadius; x++)
{
if (x != 0 || y != 0)
{
closestDepth = 1 - LoadShadowMapUV(GetSampleOffset(sampleCoord, float2(x, y)*texelSize)).r;
}
else
{
closestDepth = centerDepth;
}
float fSample = testDepth < closestDepth;
// Edge tap smoothing
float xWeight = 1;
float yWeight = 1;
//Our edge texels get smoothed, they are weighted by area covered
if (x == -fRadius)
xWeight = complFractionals.x;
else if (x == fRadius)
xWeight = fractionals.x;
if (y == -fRadius)
yWeight = complFractionals.y;
else if (y == fRadius)
yWeight = fractionals.y;
fShadowTerm += fSample * xWeight * yWeight;
}
}