Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm trying to implement shadow mapping to my engine. I started with directional lights because they seemed to be the easiest one, but I was wrong :) I have implemented deferred shading and I retrieve position from depth. I think that there is the biggest problem but code looks ok for me.

Now more about problem:

Shadow map projected onto meshes looks bad scaled and translated and also some informations from shadow map texture aren't visible. You can see it on this screen: http://img5.imageshack.us/img5/2254/93dn.png

Yelow frustum is light frustum and I have mixed shadow map preview and actual scene. As you can see shadows are in wrong place and shadow of cone and sphere aren't visible.

Could you look at my codes and tell me where I have a mistake?

// create shadow map
if(!_shd)glGenTextures(1, &_shd);
glBindTexture(GL_TEXTURE_2D, _shd);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_FLOAT,NULL); // shadow map size
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _shd, 0);

glDrawBuffer(GL_NONE);

// setting camera
Vector dire=Vector(0,0,1);
ACamera.setLookAt(dire,Vector(0));
ACamera.setPerspectiveView(60.0f,1,0.1f,10.0f); // currently needed for proper frustum corners calculation

Vector min(ACamera._point[0]),max(ACamera._point[0]);
for(int i=0;i<8;i++){
    max=Max(max,ACamera._point[i]);
    min=Min(min,ACamera._point[i]);
}

ACamera.setOrthogonalView(min.x,max.x,min.y,max.y,-max.z,-min.z);

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _s_buffer); // framebuffer for shadow map

// rendering to depth buffer

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _g_buffer);

Shaders["DirLight"].set(true);

Matrix4 bias;
bias.x.set(0.5,0.0,0.0,0.0);
bias.y.set(0.0,0.5,0.0,0.0);
bias.z.set(0.0,0.0,0.5,0.0);
bias.w.set(0.5,0.5,0.5,1.0);

Shaders["DirLight"].set("textureMatrix",ACamera.matrix*Projection3D*bias); // order of multiplications are 100% correct, everything gives mi the same result as using glm

glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_2D,_shd);

lightDir(dir); // light calculations

Vertex Shader makes nothing related to shadow calculatons

Pixel shader function which calculates if pixel is in shadow or not:

float readShadowMap(vec3 eyeDir)
{
// retrieve depth of pixel  
float z = texture2D(depth, gl_FragCoord.xy/screen).z;  

vec3 pos = vec3(gl_FragCoord.xy/screen, z); 

// transform by the projection and view inverse 
vec4 worldSpace = inverse(View)*inverse(ProjectionMatrix)*vec4(pos*2-1,1);

worldSpace /= worldSpace.w;

vec4 coord=textureMatrix*worldSpace;

float vis=1.0f;
if(texture2D(shadow, coord.xy).z < coord.z-0.001)vis=0.2f;

return vis;
}

I also have question about shadows specifically for directional light. Currently I always look at 0,0,0 position and in further implementation I have to move light frustum along to camera frustum. I've found how to do this here: http://www.gamedev.net/topic/505893-orthographic-projection-for-shadow-mapping/ but it doesn't give me what I want. Maybe because of problems mentioned above, but I want know your opinion.

EDIT:

vec4 worldSpace is position read from depht of the scene (not shadow map). Maybe I wasn't precise so I'll try quick explain what is what: View is camera view matrix, ProjectionMatrix is camera projection,. First I try to get world space position from depth map and then multiply it by textureMatrix which is light view *light projection*bias. Rest of code is the same as in many tutorials. I can't use vertex shader to make something like gl_Position=textureMatrix*gl_Vertex and get it interpolated in fragment shader because of deffered rendering use so I want get it from depht buffer.

EDIT2:

I also tried make it as in Coding Labs tutorial about Shadow Mapping with Deferred Rendering but unfortunately this either works wrong.

share|improve this question
    
Are you using different projection matrices between shadowmap and screen rendering, but then using the same one for both tasks in the fragment shader? –  MickLH Sep 22 '13 at 20:43
    
Projection3D in the expression of your textureMatrix should be the same as ACamera.setOrthogonalView. Is it? –  darius Sep 23 '13 at 0:08
    
darius - Yes, ACamera.setOrthogonalView set Projection2D matrix, but because rendering functions require Projection3D matrix, I overwrite it with Projection2D values. I have to reorganize here some things because code isn't clear right now. @MickLH Shadow map has diferent projection matrix than screen rendering. And I use the second one to get world space position (I get it from depth buffer and it's screen size, shadow map has 1024x1024 resolution). Should I use here light projection matrix? –  Harry Sep 23 '13 at 6:04
    
Yes, you must reverse exactly the lights transformation when reading the shadowmap. –  MickLH Sep 23 '13 at 12:50
    
@MickLH I'm a little bit confused right now. When I use inversed light projection effect is even worse than previous attemp. I wrote some extra informations in first post. –  Harry Sep 23 '13 at 16:33
add comment

1 Answer 1

I've already found some time and solution to my problems and I want share it with you. Maybe it will help someone:

float distFromCentroid=ACamera.far();
camera.setLookAt(frustum_centroid+dir->direction*distFromCentroid,frustum_centroid);

for(int i=0;i<8;i++){
    point[i]=ACamera._point[i]*camera.matrix;
}

min=point[0]; max=point[0];
for(int i=0;i<8;i++){
    max=Max(max,point[i]);
    min=Min(min,point[i]);
}

camera.setOrthogonalView(min.x,max.x,min.y,max.y,-max.z-distFromCentroid,-min.z);
camera.set();

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _s_buffer);

Shaders["Null"].set(true);

glViewport(0, 0, D.shadowMapSize(), D.shadowMapSize()); // this helps me to solve first problem
// rendering to depth buffer, I used here glPolygonOffset to solve problems with bias
glViewport(0, 0, D.x(), D.y()); // reset viewport

glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _g_buffer);

// rest of code is almost the same as in first post

Shadow shader method:

float readShadowMap()
{
vec4 worldSpace=inverse(View)*vec4(posFromDepth(gl_FragCoord.xy/screen),1); // posFromDepth get position in view space from depth texture

vec4 coord=textureMatrix*worldSpace;

float visible=1.0f;

if(texture2D(shadow, coord.xy).z < coord.z)
    visible=0.2f;

return visible;
}

Hope it will be useful :)

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.