PDA

View Full Version : Dynamic Shadow Mapping - FBO's and Cube Maps?



bChambers
04-09-2005, 11:33 AM
I'd like to try dynamic shadow mapping (so I can use procedural geometry, soft shadows, and other things), but I'm using omni-directional point lights. Now, my understanding is that I would need to generate a shadow map in a cube map.

Is this possible, using any standard shadow mapping extensions? Is it possible using FBO's, and rendering only depth to a cube map?

If not, I would have to use 6 maps for each light, which means 6 passes for each light just to generate the maps... then, I would have 6 maps per light to draw, so overall I'd be looking at 6*lights + 6*lights/texture_units number of passes. Just to do the lighting, and not counting other multi-pass algorithms. Naturally, I do not like this idea.

Any thoughts?

SirKnight
04-09-2005, 01:00 PM
Hardware shadow cube maps are not supported by any current hardware. Though you can render depth to a cube map and do the depth compares for shadow mapping yourself (instead of letting the hardware do it) in a fragment program. This route will also force you to do any shadow map filtering on your own also. Humus has some demos that do this: http://www.humus.ca

The 6 renderings for each point light is just the way it's done. But you don't always have to render 6 shadow maps for each light. It depends on what's currently in view. There is a method, however, of rendering only two times per light using Dual-Paraboloids. But this method is not all that great b/c it requires a high degree of tesselation on everything. Even things that do not need high tesselation like a plain flat floor or wall. Why spend all that geometry power on a flat surface that is made up of hundreds of triangles when you can use that power for higher details objects, like characters for instance?

But with the geometry transform power we have now, doing 6 depth renderings for each light is not all that big of a deal. As a matter of fact, it's not any worse (sometimes it's better) than the extra geometry generated using stencil shadow volumes typically.

EDIT: I found this link that has a neat little demo: http://www.sjbrown.co.uk/cubicshadows.html

-SirKnight

Java Cool Dude
04-09-2005, 01:49 PM
You can also update your frustum and check your objects against it everytime you render the depth (or distance) into the Cube.
I wrote a demo (That requires Float PBUFFERS for now, could do it with a regular INT target though...) a while ago that does what I described and the frame rate isn't too bad for 512*512*6 RGB render target.
Check it out here
http://www.realityflux.com/abba/C++/Point%20Shadow%20Maps/PointShadowMaps.jpg
http://www.realityflux.com/abba/C++/Point%20Shadow%20Maps/PointShadowMaps.zip
http://www.realityflux.com/abba/C++/Point%20Shadow%20Maps/PointShadowMapsSRC.zip

Ysaneya
04-12-2005, 01:21 PM
One important thing if you implement this technique in a real "game" scene, is the ability to scale well with the scene complexity and number of lights. Things that work well:

1. Generate a pool of cube maps of different resolutions. Assign a resolution for a light's cube map depending on the distance to the camera. A light that is very close could be assigned a 6x1024x1024, a far away light only a small 6x32x32

2. Updating the light not every frame, but again depending on the camera distance, and amount of dynamic entities updated in the light range. Don't re-render your light at 60 fps if it's far away! Don't update it at all if the light hasn't moved and no object in its area has changed either!

3. In the same idea, if you move your light, keep the list of objects in the light range, and only render them in the cube map (light culling).

4. Only update the cube map faces that have to. Different refresh rates for the different faces are a possibility.

5. If you have an LOD system, you can also use it to render the shadow maps (beware of popping).

6. Have your light shaders quality dependant on the screen area the object it is applied to fills. For example, don't apply an antialiasing pixel shader on an object that is 10 pixels big.

... and i'm probably forgetting a few ones. I implemented many of these in my engine and it scaled very well with from tens to a hundred small shadow mapped point-lights in a single scene/frame.

Y.

bChambers
04-13-2005, 11:22 AM
All good ideas, and I was already planning on implementing some of them. I esp. like the ones about the light remembering which objects are in it's area of influence, and only updated certain sides of the cube maps :)

One thing that surprised me, though, is the issue of not updating a light map every frame. According to NVidia's latest GPU Programming Guide, you will see *better* performance updating *every* texture, *every* frame - if you're using SLI. In single GPU systems, of course, you should still update as rarely as possible.

...Chambers

SirKnight
04-13-2005, 02:10 PM
Well if your program can detect if SLI is being used that would be great for knowing if you should update every frame or not.

I think doom 3 (I know it uses volumes) does something where it keeps track of the objects and other lights in each light's influence. There is this structure in the doom 3 engine called interaction_t where it looks to me that this is this structure's purpose, to keep track of everything like this. You can see the definition of interaction_t in a few of the doom 3 videos released a while back where it shows Carmack coding and in one shot they zoom close to his screen and you can read the code on there. ;) The point of saying all of this about D3 is that maybe you can look for this in those videos and see if the def of interation_t gives any inspiration on how to do this for your program. Then again, I may be totally wrong about what interaction_t does, it's just my guess.

-SirKnight

SirKnight
04-13-2005, 02:16 PM
Ah the hell with it. Why don't I just post that struct def here. :D


typedef struct interaction_s {
srfTriangles_t *lightTris;
srfTriangles_t *shadowTris;
srfTriangles_t *ambientTris;

shadowVolumeType_t shadowType;

idMaterial *shader;

struct entityDef_s *entityDef;
struct lightDef_s *lightDef;

struct interaction_s *lightNext, *lightPrev;
struct interaction_s *modelNext, *modelPrev;
} interaction_t;-SirKnight

zed
04-13-2005, 08:01 PM
if the objects/lights are moving youve gotta update each frame else it looks crap (though perhaps not necessary if the app runs at 200fps :) ), this is from my experience
heres an oldish implementation (new version in about a month)
motueka.homeip.net/captain_courgette.html
to back up what Ysaneya saiz, the biggest gain is getting your scenegraph really tight ie for each light area only render meshes that are in that area, make the cpu work