• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Medo Mex

Computing view matrix to create shadow map

19 posts in this topic

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?

0

Share this post


Link to post
Share on other sites

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

 

Use D3DXMatrixLookAtLH, D3DXMatrixOrthoLH for directional lights for projection.

Edited by Tispe
1

Share this post


Link to post
Share on other sites

@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?

0

Share this post


Link to post
Share on other sites

@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.

0

Share this post


Link to post
Share on other sites

@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?

0

Share this post


Link to post
Share on other sites

@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?

1

Share this post


Link to post
Share on other sites

@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.
0

Share this post


Link to post
Share on other sites

@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.

Edited by Medo3337
0

Share this post


Link to post
Share on other sites

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.

Edited by Tispe
0

Share this post


Link to post
Share on other sites

@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);    


2

Share this post


Link to post
Share on other sites

I have created a shadow map

 

As I understand, I need to compare the current pixel depth with the shadow map, if the shadow map depth is LESS than the current pixel depth then I add shadow to the current pixel.

 

Now, I see half of the scene is darker (which is unexpected)

 

Shader

 

VS:

float4 oPosition = mul(float4(IN.Position, 1.0f), shadowWorldViewProj);
oPosition.x      = ((oPosition.x + oPosition.w) * ScreenParams.x + oPosition.w) * ScreenParams.z;
oPosition.y      = ((oPosition.w - oPosition.y) * ScreenParams.y + oPosition.w) * ScreenParams.w;
Out.screenPos    = oPosition;
Out.Z = mul(float4(IN.Position, 1.0f), shadowWorldView).z;

PS:

shadow = 0.0;
float scene_z = tex2Dproj(shadowMap, In.screenPos).x;
if (scene_z > 0)
{
    if (In.Z > scene_z)
        shadow = 1.0f;
}
Edited by Medo3337
0

Share this post


Link to post
Share on other sites

In the PS you should recieve the (x,y,z) position of the pixel in screen space (WorldViewProj). This position needs to be transformed to shadow map space using Proj-1*View-1*SMView*SMProj*SMTexBias matrices which can be calculated outside the shader and be set as a constant. Then you can do the comparison, I think :)

0

Share this post


Link to post
Share on other sites

@Tispe: I'm a little confused.

 

Can you show me any code example? I thought my above code is somehow correct.

 

BTW:

shadowWorldViewProj = The light worldViewProjection

shadowWorldView = The light worldView

0

Share this post


Link to post
Share on other sites

There are several ways of doing this.

 

You can calculate the vertex position in both shadow map space and screen space and then pass both positions to the PS. The PS would then recieve the interpolated position both in screen space and shadow map space. With this method you calculate first the vertex pos in world space. Then you calculate two positions from that world pos using ViewProj and SMViewSMProj.

 

Another method is the one I described above, it has less performance but more flexibility. I think :)

0

Share this post


Link to post
Share on other sites

@Tispe: I think I'm doing the same idea in my code

 

Comparing the depth in the shadow map with the current pixel depth to determine if the pixel should be darker or not

 

And it's still not working...

 

Here is my shader code:

...
...
VS_OUTPUT VS( VERTEX IN )
{
     VS_OUTPUT OUT;
     OUT = (VS_OUTPUT)0;
     OUT.Position  = mul(float4(IN.Position, 1.0f), WorldViewProjection);
     OUT.UV        = IN.UV;
     OUT.Normal    = mul(float4(IN.Normal, 0.0f), World).xyz;
     float4 oPosition = mul(float4(IN.Position, 1.0f), lightWorldViewProj);
     oPosition.x      = ((oPosition.x + oPosition.w) * ScreenParams.x + oPosition.w) * ScreenParams.z;
     oPosition.y      = ((oPosition.w - oPosition.y) * ScreenParams.y + oPosition.w) * ScreenParams.w;
     OUT.screenPos    = oPosition;

     OUT.Z = mul(float4(IN.Position, 1.0f), lightWorldView).z;
     return OUT;
}

float4 PS(VS_OUTPUT IN) : COLOR
{
    float scene_z = tex2Dproj(shadowMap, IN.screenPos).x;
    if (IN.Z > scene_z)
        // Pixel in shadow
        shadow = float4(0.4f, 0.4f, 0.4f);
    else
        shadow = float4(1.0f, 1.0f, 1.0f)
    return tex2D( colorTex, IN.UV ) * shadow;
}
Edited by Medo3337
0

Share this post


Link to post
Share on other sites


     oPosition.x      = ((oPosition.x + oPosition.w) * ScreenParams.x + oPosition.w) * ScreenParams.z;
     oPosition.y      = ((oPosition.w - oPosition.y) * ScreenParams.y + oPosition.w) * ScreenParams.w;

 

Where did you get this code? I have not seen it before.

 

Maybe you should remove it and apply SMTexBias to IN.screenPos in the PS.

float fTexOffs = 0.5 + (0.5 / (float)SHADOW_MAP_SIZE);
D3DXMATRIX SMTexBias( 0.5f,	 0.0f,	 0.0f, 0.0f,
					  0.0f,	 -0.5f,	0.0f, 0.0f,
					  0.0f,	 0.0f,	 1.0f, 0.0f,
					  fTexOffs, fTexOffs, 0.0f, 1.0f );
0

Share this post


Link to post
Share on other sites

@Tispe: The code I posted is somehow close to the one that I use for soft particles, but of course the depth map is different as well as I'm comparing the pixel depth with the scene depth to determine if the pixel is in shadow

 

I tried using the code you mentioned, but it's still not working... what I see is that half of scene is darker instead of shadows.

 

Here is what I have done:

// Shadow map size: 1024 x 1024

VS_OUTPUT VS( VERTEX IN )
{
     VS_OUTPUT OUT;
     OUT = (VS_OUTPUT)0;
     OUT.Position  = mul(float4(IN.Position, 1.0f), WorldViewProjection);
     OUT.UV        = IN.UV;
     OUT.Normal    = mul(float4(IN.Normal, 0.0f), World).xyz;
     OUT.vTexCoord = mul( IN.Position, SMTexBias );
     OUT.ShadowZ = mul(float4(IN.Position, 1.0f), lightViewProj).z;
     return OUT;
}

float4 PS(VS_OUTPUT IN) : COLOR
{
    // Generate the 9 texture co-ordinates for a 3x3 PCF kernel
    float4 vTexCoords[9];
    // Texel size
    float fTexelSize = 1.0f / 1024.0f;

    // Generate the tecture co-ordinates for the specified depth-map size
    // 4 3 5
    // 1 0 2
    // 7 6 8
    vTexCoords[0] = IN.vTexCoord;
    vTexCoords[1] = IN.vTexCoord + float4( -fTexelSize, 0.0f, 0.0f, 0.0f );
    vTexCoords[2] = IN.vTexCoord + float4( fTexelSize, 0.0f, 0.0f, 0.0f );
    vTexCoords[3] = IN.vTexCoord + float4( 0.0f, -fTexelSize, 0.0f, 0.0f );
    vTexCoords[6] = IN.vTexCoord + float4( 0.0f, fTexelSize, 0.0f, 0.0f );
    vTexCoords[4] = IN.vTexCoord + float4( -fTexelSize, -fTexelSize, 0.0f, 0.0f );
    vTexCoords[5] = IN.vTexCoord + float4( fTexelSize, -fTexelSize, 0.0f, 0.0f );
    vTexCoords[7] = IN.vTexCoord + float4( -fTexelSize, fTexelSize, 0.0f, 0.0f );
    vTexCoords[8] = IN.vTexCoord + float4( fTexelSize, fTexelSize, 0.0f, 0.0f );
    // Sample each of them checking whether the pixel under test is shadowed or not
    float fShadowTerms[9];
    float fShadowTerm = 0.0f;
    for( int i = 0; i < 9; i++ )
    {
        float A = tex2Dproj( shadowMap, vTexCoords[i] ).r;
        float B = (IN.ShadowZ - 0.1f);
        // Texel is shadowed
        fShadowTerms[i] = A < B ? 0.0f : 1.0f;
        fShadowTerm += fShadowTerms[i];
    }
    // Get the average
    fShadowTerm /= 9.0f;
    return fShadowTerm;
}
Edited by Medo3337
0

Share this post


Link to post
Share on other sites

@Tispe: Unfortunately, I'm still having troubles getting shadow to work.

 

Please check my code and let me know if there is something wrong:

 

Shader for rendering the final scene:

...
texture shadowMapTexture;
sampler shadowMap = sampler_state
{
    Texture     = <shadowMapTexture>;
    MinFilter = Point;
    MagFilter = Point;
    MipFilter = Point;
};

// Vertex shader
VS_OUTPUT VS( VERTEX IN )
{
     VS_OUTPUT OUT;
     OUT = (VS_OUTPUT)0;
     OUT.Position  = mul(float4(IN.Position, 1.0f), WorldViewProjection);
     OUT.UV        = IN.UV;
     OUT.Normal    = mul(float4(IN.Normal, 0.0f), World).xyz;
     OUT.vTexCoord = mul( IN.Position, g_matTexture[0] );
     OUT.Z = mul(float4(IN.Position, 1.0f), lightWorldView).z;
     return OUT;
}

// Pixel shader
float3 PS( VS_OUTPUT IN ) : COLOR
{
     float A = tex2Dproj( shadowMap, IN.vTexCoord ).r;
     float B = (IN.ShadowZ - 0.1f);
     float shadow = A < B ? 0.4f : 1.0f;
     return tex2D(colorMap, IN.UV) * shadow;
}
 
Shader for generating shadow map (depth texture):
...
VS_OUTPUT VS( VS_INPUT IN )
{
    VS_OUTPUT OUT;
    OUT = (VS_OUTPUT)0;
    OUT.Pos = mul(float4(IN.Pos, 1.0f), WorldViewProj);
    OUT.UV = IN.UV;
    OUT.Normal    = mul(float4(IN.Normal, 0.0f), World).xyz;
    OUT.Z = mul(float4(IN.Pos, 1.0f), WorldView).z;
    return OUT;
}

PS_OUTPUT PS( VS_OUTPUT IN )
{
    OUT.Depth = IN.Z;
    OUT.Color = ...;
}
0

Share this post


Link to post
Share on other sites

In the shadow map VS shader:

 


OUT.Z = mul(float4(IN.Pos, 1.0f), WorldView).z;

 

I think you need WorldViewProj here. But call it LightViewProj instead for proper naming convention for the second pass.

 

Also you need to pass two floats zw, not just z. Then in PS you need to divide z by w:

OUT.Depth = IN.z / IN.w;
Edited by Tispe
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0