The current sytem is ok, but it has 4 main problems:
- No support real for UV atlases or texture arrays: We need 1 shadow map per light (and in the case of PSSM, one shadow map per split!). This wastes valuable texture slots, unnecessarily eats valuable GPU registers, and prevents certain optimizations like issuing a single clear to the whole depth texture atlas (instead of issuing N clears)
- No support for point lights.
- Using PSSM without a directional light in scene causes a crash.
- No support for lazily updated lights. Some people can get away with many shadow maps because they are rarely updated. We currently don't support that because lights get sorted per frame based on distance to camera (so if Light A was assigned to shadow map 3 in the previous frame, it may be assigned to shadow map 4 in this frame). The user should be able to "freeze" and "reserve" a specific shadow map to a specific light; and this shadow map should not update unless specifically requested. Of course, if you share an UV atlas with other dynamic lights and your compositor script clears the whole atlas, that would be your fault (you should best keep an UV atlas for dynamic lights, and an UV atlas for static lights; or one shadow map per static light).
Code: Select all
compositor_node_shadow ShadowMapDebuggingShadowNode
{
technique pssm
texture dynamicTex0 8192 8192 PF_D32_FLOAT
texture staticTex0 8192 8192 PF_D32_FLOAT
texture tmpCubemap 1024 1024 PF_D32_FLOAT cubemap
num_splits 2
pssm_lambda 0.99
shadow_map 0 dynamicTex0 light 0 split 0
shadow_map 1 dynamicTex0 uv 0.0 0.0 0.5 0.5 light 0 split 1
shadow_map 2 dynamicTex0 uv 0.0 0.5 0.5 0.5 light 0 split 2
technique focused
shadow_map 3 dynamicTex0 uv 0.0 0.0 0.5 0.5 light 1 spot point
shadow_map 4 dynamicTex0 uv 0.0 0.5 0.5 0.5 light 2 spot point
shadow_map 5 staticTex0 uv 0.0 0.5 0.5 0.5 light 3 spot point
shadow_map 6 staticTex0 uv 0.0 0.5 0.5 0.5 light 4 spot point
shadow_map 7 staticTex0 uv 0.0 0.5 0.5 0.5 light 5 spot point
initial
{
target dynamicTex0
{
//Will clear everything in one swoop
pass clear
{
colour_value 1 1 1 1
}
}
}
shadow_map_target_type directional spot
{
shadow_map 0 1 2 3 4
{
pass render_scene
{
}
}
shadow_map 5 6 7
{
//Will clear the particular region affected that could be dirty.
pass render_quad
{
material Shadows/ClearRegion
}
pass render_scene
{
}
}
}
shadow_map_target_type point
{
target tmpCubemap +X : cubemap_target {}
target tmpCubemap -X : cubemap_target {}
target tmpCubemap +Y : cubemap_target {}
target tmpCubemap -Y : cubemap_target {}
target tmpCubemap +Z : cubemap_target {}
target tmpCubemap -Z : cubemap_target {}
shadow_map 3 4
{
pass render_quad
{
material dpsm/converter
input 0 tmpCubemap
}
}
shadow_map 5 6 7
{
//Will clear the particular region affected that could be dirty.
pass render_quad
{
material Shadows/ClearRegion
}
pass render_quad
{
material dpsm/converter
input 0 tmpCubemap
}
}
}
}
- dynamicTex0 is the dynamic atlas
- staticTex0 is the static atlas
- tmpCubemap is a temporary RTT used for point lights
- What's in "initial" gets executed in all paths at the beginning (regardless of whether the light is point or spot)
- Shadow maps [0; 2] are used for PSSM for directional lights only.
- Shadow maps [3; 4] are dynamic and support point and spot lights.
- Shadow maps [5; 7] are static, support point and spot lights, and will require additional C++ code to handle their updates.
The overall syntax is a little uglier and perhaps not so straightforward compared to the current system; however this new one is much more powerful; and shadow nodes is something you deal once (usually copy paste a reference) and then forget about it.