Original Post
Has anyone played with per-object shadow maps? I did several years ago in a small demo, but didn''t really take it very far- at the time I was still playing w/ object ids.
Let me explain how I''m planning to use them - I''d love to hear other experiences.
I''d like self-shadowing for some objects, but depth shadow mapping my entire scene for the sunlight was way slow and aliased. Yes I know about PSMs, etc that can help, but just the speed of rendering to a 1k x 1k shadow map was killing my fps.
So, what I''ve done is to break shadowing into two parts : static and dynamic.
Static shadows are like lightmaps, except they only store an occlusion amount in [0..1]. These are done at a 6 texels per meter density, and then undergo a 3x3 blur at create time, followed by bilinear filtering at runtime - so they look smooth, if not soft in the correct way.
By each world surface having an occlusion factor with each light, I avoid many potential shadowmap issues, including leaks and depth precision problems. I''ve also found through playing with shadow map approaches for several years on world geometry, that few approaches work really well on world geometry.
Depth approaches alias when drawing front faces, and have light leaks when drawing back faces. Object ID''s fix this to some degree, but are more expensive to compute, and a pain to allocate, and must be filtered at runtime to avoid wall/floor shadowing problems.
If you''re willing to not have your lights move at runtime, you can pre-bake per-light occlusion info in occlusion maps, or in vertices.
With Dynamic shadows, the problems to solve are world->entity shadows, entity->world shadows, and entity->entity shadows.
The since all 3 cases involve entities, you can do your shadows per-entity. For the 2nd two cases, find your entity''s bounding sphere, create a frustum from bounding sphere out to the shadow fade distance, along the light direction.
What I''m doing now is to render the entity in black to a white texture, and modulate with the world or entity shadow receiver''s occlusion term already in dest alpha.
Then use this combined static * dynamic shadow term to choose where the lighting goes.
The downsides to this are that :
a) your entities can''t self shadow - not a huge deal for most objects.
b) Sometimes when your shadow casting entity is very close to a wall or object in front of the entity, the black & white entity shadow map gets mapped onto the geometry that should be lit, causing artifacts.
To solve both of these problems, you can use 8-bit depth shadow maps.
The key idea is to keep things fast & avoid needing > 8 bits of depth, which slows things down and hurts compatibilty with older hw.
So, you still create a per-entity frustum, but instead of rendering the entity in black, you render the entity and any other entity or geometry intersecting the mini-frustum into the shadow map with an 8-bit depth value mapped over the shadow casting entity''s bounding diameter. This should actually be mapped from [0x1-0xfe] instead of [0x0-0xff].
When drawing the objects in the mini-frustum, test their depth vs the 8-bit depth in the shadow map and see if they are in shadow or not. You can use alpha test if the object should be lit, otherwise, write zero to dest alpha.
This way any object that could potentially screw up the shadowing due to being too near the caster, gets mapped into the caster''s depth range, and is shadow testing properly.
If you have too many object interactions, you might want to merge many nearby objects into a single mini-frustum and into the same shadow map.
World->entity problems can be solved by creating a frustum from the entity back towards the light, mapping depth the same way. Come to think of it, all of these cases are the same. Any casting entity has a frustum that goes from the light through the entity''s bounding sphere, and then out to the shadow fade distance. Any world geometry or entity in that area can be rendered to the shadow map using the 8-bit depth. Objects way in front of the entity all get mapped to value [0x00] and all behind the entity get [0xff].