Shadow Mapping, Shadow Depth Buffer, whatever you call it

Started by
10 comments, last by okonomiyaki 21 years, 5 months ago
A while back (I think it was Yann) someone answered one of my questions about how to shade terrain so that the hills actually cast shadows. He answered with a solution that I thought was brilliant, but now that I''m trying to implement it I''m having some problems. It took me a while to get around to implementing shadows into my engine and it didn''t work like I thought. The technique I''m trying to use is render the scene from the light''s perspective and do all the other stuff and take the depth buffer and apply it as a texture. I get everything except render it from the light''s point of view. Now I am shading my hills with sunlight but this technique could be used for any type of shadow casting. But in my case I have a directional light. I know how to render the scene from an orthogonal perspective. I know how to make the camera look in the direction of the light. But *where do I put the camera*? It''s directional so it doesn''t have a point either. Is this a usual problem or is there a simple thing that I am not trying? Once I get the camera positioned looking at the terrain I can do the rest, but how does the perspective work out with directional lighting? I know where the target vector is, but where should I position the viewpoint vector? Thanks for the help, James
Advertisement
Yeah, I think it was me. Anyway, selecting the position for a directional light source is somewhat tricky. A directional light is basically just a direction vector, there is no explicit position (mathematically, the lightsource is infinitely far away). So you can theoretically position your directional lightview camera anywhere , as long as it points in the direction of the light vector, and the scene is infront of it (ie. visible to the camera).

That would work fine in a perfect world of infinite resolution shadow maps

First problem is the limited shadowmap resolution. Assuming you don't want to use insanely large maps (eg. 4096²) because of speed and memory, you probably won't use a single map over the entire terrain. If you do, the shadows will be blurry (although it depends on your terrain size, obviously). So, first select the part of the scene you'd like to shadowmap. That would be all parts of the terrain that are currently visible and/or could cast shadows into a visible part. If you use multiple resolution shadowmaps (shadow LODs), then take that into account here. In other words: select all parts of the scene, that are in the lightpath for the current view frustum (and current shadow LOD level, if applicable).

Now, you simpy adjust the position and orthographic scale of your camera, so that it encompasses the selected terrain parts. This is basically a 2D operation (remember, directional light has no perspective).

Next problem is depth resolution. The camera has been positioned on the plane perpendicular to the light direction, but where to position it along that vector ? Fact is, that for the results of the rendering itself, it doesn't matter. The distance is irrelevant in orthogrpahic projection, since the depth is ignored. But the problem is that your shadowmap does not have infinite dynamic range (but more something like 16 or 24bit).

Fortunately, the range can be computed easily, as you don't need very high precision. An approximation is OK: go through the bounding volumes of the selected terrain parts visible to the light (as done before to adjust the camera position), and compute the minimum and maximum extend along the light direction vector. The scene that will be rendered into the shadowmap lies between those two z values (zmin, zmax).

Now you basically have two possibilities to limit the range:

1) position the camera very far away, so that it will never interfere with any scene you have. Adjust the depth offset and scale of the projection matrix, so that zmin corresponds to 0, and zmax to 1. The GPU will clamp everything else.

or

2) Position the camera on the plane formed by the light direction vector and zmin. Adjust the depth clipping planes to match the new dynamic range (from 1 to zmax-zmin).

Now render the view of the camera into the shadowmap (or multiple maps in the case of shadow LODs).

When rendering the scene, you'll have to make sure to use exactly the same transformations as before, when projecting the shadowmap onto the geometry. That's pretty easy: keep your light camera matrix, reuse it as texture projection matrix and you'
re done.

BTW: I implemented the shadowing system we were talking about a few months ago myself, in an architectural visualization application. It looks really good, almost like raytraced realtime shadows. I have some screenies here, if someone is interested.

[Edit: typos. I'm thinking faster than I can type ]

/ Yann


[edited by - Yann L on October 21, 2002 8:31:28 PM]
We adore screenies

2DNow - Specializing in yesterday''s technology today!
wouldn''t it be better to use vertex lighting on terrains? you could have it raytrace from a light to each point and if it hits a hill, make the vertex you are raytracing darker with the diffuse color part of the vertex FVF. if it doesn''t hit anything (the ray) on the way to the vertex, make it the color of the light + attenuation if you wanted. that way there wouldn''t be any multitexturing going on
How do you perform shadow mapping in real-time? I know this is possible, but how do you do it in OpenGL or DirectX.

What I''m doing now is taking each pixel in the color buffer, transform it into shadow map space, and use that value to determine if the current pixel should be shaded. Of course, this is VERY slow.
quote:
wouldn''t it be better to use vertex lighting on terrains?

It would certainly be easier and faster to implement. But the quality of the shadow mapping method is in a totally different league: well adjusted in can approach the quality of raytraced shadows in realtime.

Another big advantage of shadowmaps is their inherent ''totally realtime'' nature: you can move the sun position, morph the terrain, make objects move on the terrain, etc, and the shadowing will always be perfectly realtime without additional overhead. Also, the shadow solution is complete, means that the shadows will project from every object onto every object.

/ Yann
I actually have implemented a vertex shading raytracing technique that you describe, but it does not have good quality. And it''s too slow for the dynamic nature I want. And it also doesn''t have the volume effect
Thanks so much Yann, I think I grasp the concept but it''ll take a few days to understand how to implement it. I''ll be working on it. It''s weird, I understand perfectly how to implement something like this for regular objects (such as a standing person) but I''m having trouble visualizing how to do this with terrain, one big self-shadowing object. I''m gonna try whatever I can and see if I can get something working anyway. Thanks again guys

And yes, we''d definitely like to see some screenshots!
You might want to check out the following paper, and also the discussion about it on the gdalgorithms mailing list.

Perspective Shadow Maps

BTW to see how to accelerate it in hardware just check out some of the NVIDIA presentations/whitepapers.

[edited by - PinkyAndThaBrain on October 22, 2002 11:58:25 PM]
Directional light without perspective?

once you have a direction for the light, simply rotate the mesh....then useing the the triangle X and Y values (don''t do any perspective Z stuff)...anyway use the the triangle X and Y values to cull polygons into a list...polygons that face the opposite direction cast shadows, so you want the list to contain these...you can then use the list to render shadows on the texture...either directly, or vertex shaders, or whatever....

Hey, I got a program running with the regular shadow map technique! Yeah, it has the aliasing artifacts for now, but I was still impressed with the results. It was very cool too see my terrain self shadow real-time while the "sun" moved around.
I''m afraid some of the math provided for the "perspective" shadow maps is too complex for me to understand without any code, visual explanation or such. I read the "Perspective Shadow Map" paper and the explanations didn''t relate well enough. Maybe I''m trying to jump into something too quickly, but maybe if someone could still answer a few specific questions I can crawl my way through this.
Explain 4-d texture coordinates. How the heck does transforming oT0.x y z and w "project" the texture? I was amazed when it worked. Is there a paper out there that explains it conceptually? I don''t understand anything outside of the 2-d texture coordinates.
How am I to take the depth buffer if there is none?? I''m rendering my light from an orthogonal aspect ( it''s a directional light ), meaning -there is no depth!- Can someone explain this ?
I''m still satisfied with what I have because my first game does not have to be perfect. If I can''t get any farther than this I will just keep this for this program. Thanks again everyone.

This topic is closed to new replies.

Advertisement