Engine Design: Shadow Mapping

Started by
3 comments, last by AgentC 11 years, 9 months ago
Hello,

In my (Direct9 based) Render Engine I render objects and each object has a material. A material is basically just a pixel and vertex shaders, a set of textures and render states.

So lets say I render an object with a material that uses 3 textures, I call 3 times setTexture:
device->setTexture(0, tex0);
device->setTexture(1, tex1);
device->setTexture(2, tex2);

It works great, but now I want to add Shadow Mapping to my Engine. The number of shadow casting lights should be flexible.
Since I need one Shadow Texture for each shadow casting light and since ALL material shaders need access to the shadow maps I guess the best (only) way to do this is to start with the shadow map textures at a specific sampler register.

For example: Lets say I have 4 lights and Light0 and Light2 cast shadows. The shadow map (aka depth map) textures start at sampler register s10. Then Depth Map for Light0 is in sampler s10 and Light2 in sampler s11.
Is this a good idea or rather crappy?

Thanks for any feedback!
Advertisement
You could use a shadow map atlas to avoid having to manage multiple textures. You then essentially have a single big shadow map, and render each lights depth to a part of that texture. Your shader then only needs to access a single sampler plus UV-coordinates for each light.

Something along those lines is described here: http://www.john-chapman.net/content.php?id=14
If doing multiple shadowed lights in one pass, you may hit the interpolator register limit when passing the shadow map projective coordinates from vertex to pixel shader, depending on what other interpolators your lighting calculations need, and especially if you're doing parallel-split shadows for a directional light, which needs coordinates for each split. In this case you can just multi-pass the lighting, ie. take one shadowed light and as many unshadowed lights as you can in the first pass, then render the second shadow casting light additively in a second pass.
When I use a texture atlas for multiple depth maps I assume I the part of the atlas specific for a certain light is selected by setting the viewport?

@AgentC: I do not know the maximum number of available registers from VS to PS (I use Shader Model 3), but I do not think this will be a problem. My shaders are relatively simple - just Pos, Normal and Tex Coordinates and then one additional texture coordinate for each Depth Map. I also just want to implement standard Shadow Mapping.

But do you think my idea with the fixes sampler registers (i.e. s10 for depth map 1, s11 for depth map 2 etc) is good?

Another question just came into my mind: Lets say I have 3 lights and I pass that information to my HLSL shader per constant float u_numLights;
Now I could write a for loop in the Pixel shader to iterate over all depthmaps and make the test if the pixel is in shadow. But my simple problem is: The samplers aren't an array, so I can't just use an array expression like this:

for(int i=0; i < u_numLights; i++) {
depth = tex2D(sampler[10 + i], texCoords);
}

I have to address each sampler with its full name, like depthMap1, depthMap2 etc, which makes it impossible to use a loop. Or do I miss something?

depthMaps[

But do you think my idea with the fixes sampler registers (i.e. s10 for depth map 1, s11 for depth map 2 etc) is good?


Nothing wrong with that. To reduce the amount of shader permutations and to make the mapping of lights to shadow maps straightforward, you can also arrange the shadowed lights to always be in the beginning of your light list, so in your example light0 & light1 would be shadowed, and the rest unshadowed.

Loop count based on an uniform will likely not work well with SM3 pixel shaders, so I believe you're better off building the shaders with different light counts explicitly.

This topic is closed to new replies.

Advertisement