tags:

views:

447

answers:

2

hello, i have implemented shadowmapping with an FBO and GLSL. it is used on a heightfield. that is some objects (trees, plants, ...) cast shadows on the heightfield.

the problem i have, is that the shadows are only visible on the ground of the heightfield. that is, where the heightfield's height = 0. as soon as there is some height involved, the shadows disappear. if i look at the shadowmap itself, everything looks fine... objects that are closer to the light are darker.

here is my GLSL vertexshader:

uniform mat4 lightView, lightProjection;

const mat4 biasMatrix = mat4(   0.5, 0.0, 0.0, 0.0,
       0.0, 0.5, 0.0, 0.0,
       0.0, 0.0, 0.5, 0.0,
       0.5, 0.5, 0.5, 1.0);     //bias from [-1, 1] to [0, 1]

void main()
{   
gl_Position = ftransform(); 

mat4 shadowMatrix = biasMatrix * lightProjection * lightView;
shadowTexCoord = shadowMatrix * gl_Vertex;    
}

fragmentshader:

uniform sampler2DShadow shadowmap;
varying vec4 shadowTexCoord;

void main() 
{    
vec4 shadow = shadow2DProj(shadowmap, shadowTexCoord, 0.0);
float colorshadow = shadow.r < 0.1 ? 0.5 : 1.0;

vec4 color = vec4(1,1,1,1); 

gl_FragColor = vec4( color*colorshadow, color.w );

}

thanks a lot for any help on this!

A: 

Maybe you just missed it copy-pasting, but I don't see shadowTexCoord as varying in the vertex shader. This should result in a compilation error, though.

heeen
this is really more of a comment and not an answer
IanNorton
+2  A: 

I think there might be some confusion between the different spaces here. As written, it looks like your code would only work if gl_ModelViewMatrix for the ground contains only camera transformations. This is because ftransform basically goes

gl_Position = gl_ProjectionMatrix * (gl_ModelViewMatrix * gl_Vertex)

that means that the gl_Vertex is specified in object coordinates. However typically the view matrix of the light maps from world coordinates to the light's view space so this code would only work if object space = world space. So basically, lets say you scale the terrain, well then object space doesn't equal world space anymore. Because of this you need to separate out the gl_ModelViewMatrix into two parts: the camera view matrix and the modeling transform (eg object -> world space)

I havent tested this code, but I would try something like this:

uniform mat4 lightView, lightProjection;
uniform mat4 camView, camProj, modelTrans;
const mat4 biasMatrix = mat4(   0.5, 0.0, 0.0, 0.0,
                                                        0.0, 0.5, 0.0, 0.0,
                                                        0.0, 0.0, 0.5, 0.0,
                                                        0.5, 0.5, 0.5, 1.0);        //bias from [-1, 1] to [0, 1]

void main()
{
mat4 modelViewProjMatrix =  camProj * camView * modelTrans;  
gl_Position =  modelViewProjMatrix * gl_Vertex;   

mat4 shadowMatrix = biasMatrix * lightProjection * lightView * modelTrans;
shadowTexCoord = shadowMatrix * gl_Vertex;    
}

Technically it's faster to multiply the matrices on the CPU and only pass the exact ones you need but for getting stuff working sometimes its easier to do this way.

Lucas
couldnt you just use gl_MovelViewMatrix instead of passing it to the shader with a uniform?
clamp
Yes, but the gl_ModelViewMatrix contains both the object and view transform combined. This is what you need to transform the vertex for rendering but you still need to pass a separate "only the object transform" matrix to do the shadow. Personally, I just pass everything as a uniform since I think it's bad form to differentiate between built-ins and "custom" uniforms since it's the same thing hardware-wise and the built-ins are deprecated in GL3. That's kind of tabs vs. spaces thing though so feel free to do whatever.
Lucas
ok, i see thanks! btw: how do you get the modelTrans on the client side? do you need to manually multiply all the glRotates, glScales, etc. and make it into a matrix you put into the shader as "modelTrans" ?
clamp
Basically, the counterintuitive thing is that none of the OpenGL matrix operations are actually done GPU-side. All glRotate and friends do is compose a matrix on the CPU which is sent in a hidden uniform by the driver. You can get the matrix using glGet but at that point you might as well just compose it yourself and not worry about the different OpenGL matrix modes and states. That's why they are also deprecated in 3.0
Lucas