1
votes

I'm trying to implement shadow mapping in my game. The shaders you see below result in correctly drawn shadows for the game's map, but all the models walking around on the map are completely black.

Here's a screenshot:

I suspect the problem lies with the calculation of the world position. The gl_Vertex is not transformed in any way. Because the map is generated with absolute world coordinates, the transformation with the light matrix results in a correct relative position that can be used to perform the shadow mapping.

However, my 3D models are all very close to the origin. So if their coordinates are plainly transformed using the light matrix, they will most likely never be lit.

I'm wondering if this could be the case, and if so, how I could fix it.

Here's my vertex shader:

#version 120
uniform mat4x4 LightMatrixValue;

varying vec4 shadowMapPosition;
varying vec3 worldPos;

void main(void)
{
    vec4 modelPos = gl_Vertex;
    worldPos=modelPos.xyz/modelPos.w;

    vec4 lightPos = LightMatrixValue*modelPos;

    shadowMapPosition = 0.5 * (lightPos.xyzw +lightPos.wwww);
    gl_Position = ftransform();
}

And the fragment shader: varying vec4 shadowMapPosition; varying vec3 worldPos;

uniform sampler2D depthMap;
uniform vec4 LightPosition;

void main(void)
{
    vec4 textureColour = gl_Color;
    vec3 realShadowMapPosition = shadowMapPosition.xyz/shadowMapPosition.w;
    float depthSm = texture2D(depthMap, realShadowMapPosition.xy).r;

    if (depthSm < realShadowMapPosition.z-0.0001)
    {       
        textureColour = vec4(0, 0, 0, 1);
    }
    gl_FragColor= textureColour;
}
1
First of all, the screenshot is not telling anything - second - why so complicated? Just render the scene from the light point of view in the first pass - surface positions in the shadows will be overwritten by positions which are nearer to the light due to depth test! In the second pass render the scene from eye point of view, also transform the vertices to the light pov, to perform the shadow map check!dinony
@dinony looks to me as if it is done that way. There is the LightMatrixValue*modelPos for transformation in the light pov. And the corresponding lookup. But without knowing how the shadow map is created it is hard to guess what is wrong. 0.5 * (lightPos.xyzw +lightPos.wwww) could be the problem. But also the realShadowMapPosition.xy in the texture lookup.t.niese
@dinony: I do indeed already do that as t.niese pointed out. As far as I can see the problem lies with calculating the shadow distance itself. The map has the correct shadow cast on it because the pixels have been occluded by the units in front of it. The units don't because they haven't been transformed in a way that gives their position relative to the light's location.Bartvbl
@t.niese: I create the shadow map with an additional render pass that only stores the depth of the pixel, from the light's point of view. I can add the code if you want.Bartvbl
The way (shading code) how that shadow map is create is always important, because this influences the sotred z value. Why do you do this 0.5 * (lightPos.xyzw +lightPos.wwww) (what do you expect from this) lightPos this is the vector from the origin of the light position to the vertex (assuming LightMatrixValue is the same matrix used in the Shadow shader) . So with this calculation (depending on the w) you move the point towards the light source or in the other direction.t.niese

1 Answers

2
votes

I write this here because it will not fit above, i hope it will solve you problem.

For rendering you on the one hand have your models with their model matrix to position the element, on the other hand you have you view and projection matrix that transforms your model into the screen space.

For creating your shadow map (simplest approach, and i guess the one you have chosen) you render the scene from the view of the light source, so you apply the view and projection matrix of you light source, which will map the x, y and z value to screen space. The x and y values are for the position in the image, the z is for the depth buffer test and for the color you write in your color buffer (you later use as shadow map).

For the final rendering you load this shadow map and the view and projection matrix of the light to your shader. For the display in the scene you apply your view and project matrix of the camera to the vertexes, for the shadow map lookup you apply the view and projection matrix of the light to the vertex (like you did with the rendering for the shadow map). When you apply the lights view and projection matrix to the vertex you have the same mapping as in the shadow map pass, now you only need to transform your x and y coordinates to the texture coordinates and lookup the stored z value, which you compare with the calculated one.

Transforming the models world position into screen space (from the lights point of view)

This part is often done in the vertex or geometry shader:

shadowMapPosition = matLightViewProjection * modelWoldPos;

This is often done in the fragment shader:

shadowMapPosition = shadowMapPosition / shadowMapPosition.w ;

// Add an offset to prevent self-shadowing and moiré pattern
shadowMapPosition.z += 0.0005;

//lookup the stored z value
float distanceFromLight = texture2D(depthMap,shadowMapPosition.xz).z;

Now just compare the distanceFromLight with the shadowMapPosition.z to see if the object is in shadow or not.

So in your second pass you will do the steps of the shadow mapping again, except that you don't draw the data you calculated but compare it to the one you calculated in the pass before.