Computing view matrix to create shadow map

Started by
18 comments, last by Tispe 10 years, 5 months ago

I'm trying to generate shadow map so I can pass it to the shader and create shadow

I have bunches of lights (including directional lights, point lights and spot lights)

How do I calculate the view matrix to create the shadow map?

Advertisement

You need one view matrix for each light, and 6 for point lights.

Use D3DXMatrixLookAtLH, D3DXMatrixOrthoLH for directional lights for projection.

@Tispe: I still don't understand, how should I work with multiple view matrices? Lets say I have 10 view matrices for the shadow map, should I multiply them with each others?

@Tispe: I still don't understand, how should I work with multiple view matrices? Lets say I have 10 view matrices for the shadow map, should I multiply them with each others?

Each shadow map represent a single direction of light source, and so for each shaodw map you use a single ViewProjection matrix. Point lights have 6 matrices, because they reflect light in all directions, so you have a matrix for each direction.

Here is a tutorial about shadow mapping. It's OGL, but the same exact principles apply for DX. I suggest you start with shadow of a single directional light, once you understand it multiple light sources and point lights will become easier.

@N.I.B.: This is my first time to implement shadows, so I have some questions

Does that means I have to send multiple shadow maps to the shader?

Lets say I have 2 point lights, you said that point light have 6 view/projection matrices, does that means I have to render the scene 12 times?

@Tispe: I still don't understand, how should I work with multiple view matrices? Lets say I have 10 view matrices for the shadow map, should I multiply them with each others?

You mean multiple lights at the same time, all casting shadows? You need one shadow map per each light! But usually just one light is casting dynamic shadows at a time ;) So you need just one view matrix.

And how to construct the view matrix? Just imagine a camera instead of the light - a camera looking the same direction as the light is shining on the scene. And forget about point lights as shadow casters. It's not impossible of course, but definitely not good for somebody who's beginning with shadow mapping.

I'm quite confused about your question whether you should multiply the view matrices of different lights with each other. I don't mean any offense, but are you sure you understand the basics well enough to be able to start dealing with the kinda more advance technique of shadow mapping?

@N.I.B.: This is my first time to implement shadows, so I have some questions

Does that means I have to send multiple shadow maps to the shader?

Lets say I have 2 point lights, you said that point light have 6 view/projection matrices, does that means I have to render the scene 12 times?


Theoretically, yes. But like Tom said, that's usually not necessary.

Shadows are a huge subject, and trickier than you might imagine. If you are just beginning, start with a single spot casting shadow. Get it to work, make sure you understand it well. Than you can start thinking about more advanced shadow techniques.

@Tom KQT: How do I determine which light is CURRENTLY casting shadow? I'll mostly be having 2 directional lights out door, and several point lights indoor.

Another thing, to create shadow map for directional light I know how to create the projection matrix, however, how can I create the view matrix using D3DXMatrixLookAtLH()? I only have the light direction.

For every light source you need to generate a shadow map. A shadow map is a a complete render of the scene where the camera is placed at the light source. Instead of saving the colors like a normal render pass, you save the depth Z.

When you have all the shadow maps you need there are several ways of applying shadows to the scene:

Option A, render the scene and check each pixel against each shadow map. This requires you to bind the shadow maps to samplers, and you are limited with how many samplers you have available.

Option B, you can also composition shadows ontop of the rendered scene. This is handy if you have many shadow maps. Render the scene to a texture for color and a depth buffer for Z. Then render a fullscreen quad with the scene. For each pixel check the depth buffer value against each shadow map.

Before you start applying shadows to your scene, try to render something like this first:

shadowmap-small.png

This is an inverted shadow map with a single channel. Instead of colors, the distance to the light determines the pixel value.

@Tom KQT: How do I determine which light is CURRENTLY casting shadow? I'll mostly be having 2 directional lights out door, and several point lights indoor.

That's also related to level design, usually designers decide which lights will cast shadows. And even in top games, shadows aren't fully realistic. They are important to be there, because they improve the visual quality and overall feeling from the game a lot, but it usually doesn't quite matter (players won't notice it) whether the shadows are cast from all lights, whether the shadows correspond perfectly with the light type etc.

2 directional lights outdoor? Isn't sun enough? Specifically outdoor scenes are perfect for shadows, because you can be absolutely fine with 1 directional light casting shadows (the sun or moon) and the scene will look realistic, because that's what people expect. Of course for a good appearance you will need more complex lighting than just one directinal light, because in real life also the skydome add a lot of scattered light and light bounces on objects. But as far as shadows are concerned, casting them from the sun is enough.

Indoor scenes are much more complicated. You can still be fine with quite "fake" shadows like in some FPS games (TF2 for example) because as I said - most players won't care as long as the shadow is there. But then there are games where lighting is very important part of the gameplay or feeling (survival horrors for example) and these games need better shadows. But I personaly have more experience with outdoor and faked indoor shadows, so I don't know exactly how to do it, how to seamlessly swap shadows when moving from one room (one light) to another.

So you should answer to yourself - how accurate shadows do you need? Does the game rely on them much? Is it worth the additional performance cost? The answers can be 'yes' of course.

Another thing, to create shadow map for directional light I know how to create the projection matrix, however, how can I create the view matrix using D3DXMatrixLookAtLH()? I only have the light direction.

Something like this should work:


// Variables you already know:
D3DXVECTOR3 lightDirectionVector = D3DXVECTOR3(....); // the light direction
// Variables you have to define somehow:
D3DXVECTOR3 lookAt = D3DXVECTOR3(...); // where the virtual light camera is looking, 
                                       // this doesn't come directly from the light because directional light has
                                       // just direction and not position, so you have to choose it somehow,
                                       // for example as the centre of you scene, for a start ;)
float distance = ....; // how far the virtual light camera is from the lookAt point (again, you have to choose this value)

// Then you go:
D3DXVECTOR3 front, left, up; // basic view matrix orientation vectors
D3DXVECTOR3 eyePosition; // where the virtual light camera is 

D3DXVec3Normalize(&front, &lightDirectionVector));
eyePosition = lookAt - front * distance;
D3DXVec3Cross(&right, &UNIT_Y, &front);
D3DXVec3Normalize(&right, &right);
// 'right' can be almost zero if 'front' was almost parallel with UNIT_Y, so check it and fix if needed:
if (D3DXVec3LengthSq(&right) < 0.5f)
	right = Vec3(1, 0, 0);
D3DXVec3Cross(&up, &front, &right);

// You can use D3DXMatrixLookAtLH, of fill the matrix manually like this (the function does it also, under the hood):
D3DXMATRIX view;
view._11 = right.x;        view._12 = up.x;    view._13 = front.x;        view._14 = 0;    
view._21 = right.y;        view._22 = up.y;    view._23 = front.y;        view._24 = 0;    
view._31 = right.z;        view._32 = up.z;    view._33 = front.z;        view._34 = 0;    
                                                                          view._44 = 1.f;    
view._41 = -D3DXVec3Dot(&right, &eyePosition);    
view._42 =-D3DXVec3Dot(&up, &eyePosition);    
view._43 = -D3DXVec3Dot(&front, &eyePosition);    


This topic is closed to new replies.

Advertisement