Shadow Cube for a Point Light

Started by
1 comment, last by ddamicoAVI 16 years, 1 month ago
I have a room with a few spot lights and a few point lights. I was able to create shadow maps for each of the spot lights and apply those maps in my shader. I'm a stuck on the point lights though. I know I need to use a shadow cube. The only problem is I don't know how to use one. Can anyone help me out with a simple example? Thanks, Dave
Advertisement
What you'll need to do is render 6 passes, with each pass corresponding to a single face of a cube (you can also do all the faces in one pass if you're using D3D10). You can facilitate this with cube textures: you simplly create a single texture, and you can then access each individual face as a surface that you can render to. For each pass, you'll need to set up a temporary camera (view matrix and projection matrix) that you'll apply to all the objects that are rendered to the shadow map. The projection matrix is easy: simple create a perspective projection with an aspect ratio of 1 and a vertical FOV of pi/2, and the near/far parameters set to something reasonable for the size of the light source's area of influence. You can use that same projection matrix for all of your passes. The view matrix is slightly trickier: for whichever face you're currently rendering to you need to come up with a view matrix that looks in the direction of that face. So for the top face you'll look in the direction of <0,1,0>, and so on. You also have to make sure your up-vector is set correctly. One of the SDK samples (for HDR cubemap, I think) includes a simple switch statement you can use, it looks something like this:

switch( cubeFace ){	case 0:		vLookDirection = D3DXVECTOR3( 1.0f, 0.0f, 0.0f);		vUpVec = D3DXVECTOR3(0.0f, 1.0f, 0.0f);		break;	case 1:		vLookDirection = D3DXVECTOR3( -1.0f, 0.0f, 0.0f);		vUpVec = D3DXVECTOR3(0.0f, 1.0f, 0.0f);		break;	case 2:		vLookDirection = D3DXVECTOR3( 0.0f, 1.0f, 0.0f);		vUpVec = D3DXVECTOR3(0.0f, 0.0f, -1.0f);		break;	case 3:		vLookDirection = D3DXVECTOR3( 0.0f, -1.0f, 0.0f);		vUpVec = D3DXVECTOR3(0.0f, 0.0f, 1.0f);		break;	case 4:		vLookDirection = D3DXVECTOR3( 0.0f, 0.0f, 1.0f);		vUpVec = D3DXVECTOR3(0.0f, 1.0f, 0.0f);		break;	case 5:		vLookDirection = D3DXVECTOR3( 0.0f, 0.0f, -1.0f);		vUpVec = D3DXVECTOR3(0.0f, 1.0f, 0.0f);		break;}D3DXMatrixLookAtLH(&matView, &vLightPos, &vLookDirection, &vUpVec);


Once your shadowmap is rendered, your pixel shader has to access the correct texel. Cube textures are accessed by a 3D vector, where the vector points from an imaginary point at the center of the cube towards the texel you want. This is convenient, because it means that for any surface that you're calculating the shadow factor you simply need to calculate the world-space direction of the light source to that pixel. Then you just normalize, grab the depth value, and proceed as normal.

The key to performance with this technique is that you have to cull fairly aggressively. If the view frustum for a corresponding cube face isn't visible in your actual viewing frustum, you can skip that pass. Then for the passes you do have to make you can cull out individual objects that aren't within that view frustum.

I don't know of any samples that do this offhand...but if you want I could probably modify the ShadowMap sample in the SDK to use a point light.
Thanks for the reply, it was very informative. What you said makes sense. But I guess I should have specified I was using XNA. Even though the ideas are the same the implementation will be different. I guess what I need to know is how to store the shadow maps and pass them along to the effect, and then how to sample the cube from the effect.

This topic is closed to new replies.

Advertisement