Odd Shadow Mapping Problem

Ok, I have shadow mapping working perfectly using the fixed-function pipeline. I use glTexGen with GL_EYE_LINEAR on GL_S, GL_T, GL_R, GL_Q, etc… Only problem is though, that to use shaders, I have to do shadow mapping in the shader as well.

I think I’ve officially found and tried every single GLSL shadow mapping tutorial and code bit that can be found online. And the ones I could get to work, all end up having the same issue: my shadows aren’t projected correctly.

The following is a simple scene using plain opengl without any shaders:

It works great.

The following is the same scene rendered using the shadow mapping shaders from the opengl orange book:

I haven’t blended anything with the base textures yet, since I want to solve the shadow mapping problem first. But, as you can see, the shadows aren’t being projected properly. And I’ve run into this same projection problem with every other GLSL shadow mapping shader I’ve gotten to “work.”

My guess is that it has something to do with how I’m setting up and creating the shadow map texture, but I fail to see why my method would work with the plain-opengl method and not a shader method? I’ve tried fiddling with my light’s matrices and perspective without any luck so far. About the only thing I haven’t been able to try is a non-power-of-two texture for the shadowmap to match the screen resolution (when I try that, my machine just freezes for some reason). Still, I don’t understand why it works fine when not using shaders.

Any ideas? Code examples? A possible tutorial I haven’t found yet?

ANY help is greatly appreciated! I’ve been stuck on this for a while now.

For an update (and a shameless bump), I’ve noticed that when moving the walls and other objects in the scene, the shadows don’t change on the object. It appears that the shadowmap is being mapped to each object individually.

Also, for reference, here is the shader code I’m using (it’s right out of the Orange Book):

//// Vertex Shader ////////

attribute float Accessibility;
varying vec4  ShadowCoord;
  
// Ambient and diffuse scale factors.
const float As = 1.0 / 1.5;
const float Ds = 1.0 / 3.0;

void main()
{
    vec4 ecPosition = gl_ModelViewMatrix * gl_Vertex;
    vec3 ecPosition3 = (vec3(ecPosition)) / ecPosition.w;
    vec3 VP = vec3(gl_LightSource[0].position) - ecPosition3;
    VP = normalize(VP);
    vec3 normal = normalize(gl_NormalMatrix * gl_Normal);
    float diffuse = max(0.0, dot(normal, VP));

    float scale = min(1.0, Accessibility * As + diffuse * Ds);

    vec4 texCoord = gl_TextureMatrix[1] * gl_Vertex;
    ShadowCoord   = texCoord / texCoord.w;

    gl_FrontColor  = vec4(scale * gl_Color.rgb, gl_Color.a);
    gl_Position    = ftransform();
}

//// Fragment Shader //////
uniform sampler2DShadow ShadowMap;
uniform float Epsilon;

varying vec4 ShadowCoord;

float lookup(float x, float y)
{
    float depth = shadow2DProj(ShadowMap,
                      ShadowCoord + vec4(x, y, 0, 0) * Epsilon).x;
    return depth != 1.0 ? 0.75 : 1.0;
}
 
void main()
{
    float shadeFactor = lookup(0.0, 0.0);
    gl_FragColor = vec4(shadeFactor * gl_Color.rgb, gl_Color.a);
}

Also, here is my code for setting up the matrices:


	private void recalcMatrix() {
		if (useFBOs || usePBuffer) {
			GL11.glMatrixMode(GL11.GL_PROJECTION);
			GL11.glPushMatrix();
			GL11.glLoadIdentity();
			GL11.glOrtho(-(float)shadowMapSize/2f, (float)shadowMapSize/2f, -(float)shadowMapSize/2f, (float)shadowMapSize/2f, 10f, 5000f);

			projectionMatrix.clear();
			GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projectionMatrix);
			GL11.glPopMatrix();

			GL11.glMatrixMode( GL11.GL_MODELVIEW );
			GL11.glPushMatrix();
			GL11.glLoadIdentity();

			Vector3f position = light.getPosition();
			Vector3f lookAt = light.getLookAt();
			GLU.gluLookAt(position.x, position.y, position.z,
					lookAt.x, lookAt.y, lookAt.z,
					0.0f, 1f, 0.0f );
			viewMatrix.clear();
			GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, viewMatrix);
			
			GL11.glPopMatrix();
		}

	}

	private void bindShadowMap() {
		if (useFBOs || usePBuffer) {
			GL11.glEnable( GL11.GL_LIGHTING );

			GL11.glMatrixMode(GL11.GL_TEXTURE);
			GL13.glActiveTexture(GL13.GL_TEXTURE1);
			GL11.glBindTexture(GL11.GL_TEXTURE_2D, shadowTextureID); 
			
			GL11.glEnable(GL11.GL_TEXTURE_2D);

			sX.rewind();
			sY.rewind();
			sZ.rewind();
			sW.rewind();
			GL11.glTexGen( GL11.GL_S, GL11.GL_EYE_PLANE, sX );
			GL11.glTexGen( GL11.GL_T, GL11.GL_EYE_PLANE, sY );
			GL11.glTexGen( GL11.GL_R, GL11.GL_EYE_PLANE, sZ );
			GL11.glTexGen( GL11.GL_Q, GL11.GL_EYE_PLANE, sW );

			biasMatrix.rewind();
			GL11.glLoadMatrix(biasMatrix);
			projectionMatrix.rewind();
			GL11.glMultMatrix(projectionMatrix);
			viewMatrix.rewind();
			GL11.glMultMatrix(viewMatrix);
			
			GL11.glMatrixMode(GL11.GL_MODELVIEW);
		}
	}

I had a problem with the Orange Book shaders for shadow mapping, see here: http://www.opengl.org/discussion_boards/…8834#Post248834

Maybe the same thing applies to you.

someone else on this board has written a nice little tutorial for shadow mapping:
http://fabiensanglard.net/shadowmapping/index.php

i hope some of this helps.

Yes, I’ve used that tutorial (and it’s a great tutorial), but I still get the same problem. That’s why I’m thinking I’m either doing something wrong on my end (I’m converting the tutorial over to Java in order to use it), or maybe there’s something wrong with my hardware setup I suppose.

For reference, I’m on a Mac Pro with an ATI 1900.

I also tried removing the divide by w line in the shader, but I get the exact same outcome as before. Is it possible that the shader isn’t actually picking up the texturematrix from the pipeline correctly? Maybe I’ll try passing it in manually and see what happens.

You could use glGetTexImage to download the shadow map from the GPU to the CPU and compare what you have in your 2 approaches. This would at least tell you if the problem is with the shadow generation or the application.

I’m not sure if that would help actually. Both versions use the same code base to generate the initial shadow map. I’m pretty sure it has to do with mapping that texture. In the fixed-function-pipeline version I use GL_EYE_PLANE with glTexGen (for s,t,r, and q) to create the coordinates. When I use the shader, I just don’t get the same result for some reason; the texture updates properly, but the way it’s mapped onto objects stays static even if the objects move around.

Also, as an update, I tried passing the texture matrix into the shader via a uniform, but it didn’t change anything. :frowning:

And now that I just posted that… I realized somewhere the problem might be!! The shader doesn’t seem to realize where the objects are located! It’s mapping everything as if it were at the origin!!! So how do I update the proper texture matrix with object locations?

HA! That was it! I have to do all the transformations for objects in the texture matrix as well as the modelview matrix! Sheesh!!!

Of course, now I have to figure out how to handle multiple textures that way. Ugh.