Shadow mapping - Multiple lights problem

Hello programmers!
I guess this post will be kinda long, but for anyone who read it and might give one suggestion you should know that I would be very very thankfull.
Anyhow, I am following this tutorial about shadow mapping in GLSL: Shadow Mapping

I have implemented it in my own project and try to modify it so that it supports more than one light, a custom texture can be loaded and all objects are lit from directional light. I have managed to customize the shader so that the two last works
but I get huge problems when trying to implement more than one light.

You should know that I am actually hard-coding my program to work with Two lights, because if I can manage that it will be a piece of cake with 3 lights etc.
This is basically what I do:

  • Create 2 different FBOs and 2 two different depth textures.
  • Render a first pass with FBO1 and texture 1
  • Render a second pass with FBO2 and texture 2
  • Render the scene as normal with the Fragment and Vertex Shader.

Well, with only one light everything works fine and I can see that the depth texture looks great. Although when I try to add another light things start to look weird; depth texture 1 gets messed and texture 2 just seems screwed. I know that It will be hard for you to give me suggestions, and it is very hard to explain my problem indeed. But I will give you some examples:

This is how my textures look with one light. Texture 2 is empty couse it is not assigned with only one light. Texture1 gets a perfect value where you can see a plane and a cube placed on the scene.

This is how everything looks with 2 lights:

As you can see Texture1 gets 1/4 the size and Texture2 is screwed (you can see the plane but everything seems rotated).

Here is my what I do in my render function for each object (half-edge-structure). So this code is run for every object in the scene. The drawTriangle() function is basically where I loop throught the objects faces and do the drawing:


if( i_ShadowShader->m_renderToFBO)
{
	if ( i_ShadowShader->m_renderPass == 1 )
	{
		glMatrixMode(GL_TEXTURE);
		glActiveTextureARB(GL_TEXTURE7);
		glPushMatrix();
		glMultMatrixf(transformGL);
		
		drawTriangle( &i_objecCount[1] );

		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);
		glPopMatrix();
	}

	else if ( i_ShadowShader->m_renderPass == 2 )
	{
		glMatrixMode(GL_TEXTURE);
		glActiveTextureARB(GL_TEXTURE6);
		glPushMatrix();
		glMultMatrixf(transformGL);
					
		drawTriangle( &i_objecCount[1] );
					
		glPopMatrix();
		glMatrixMode(GL_MODELVIEW);
		glPopMatrix();
	}
}

else
{
	glMatrixMode(GL_TEXTURE);
				
	glUniform1iARB(i_ShadowShader->m_shadowMapUniform, 7);
	glActiveTextureARB(GL_TEXTURE7);
	glBindTexture(GL_TEXTURE_2D,  i_ShadowShader->m_depthTextureId);
	glPushMatrix();
	glMultMatrixf(transformGL);
				
				
	if( i_ShadowShader->m_numLights == 2 )
	{
		glUniform1iARB(i_ShadowShader->m_shadowMapUniform, 6);
		glActiveTextureARB(GL_TEXTURE6);
		glBindTexture(GL_TEXTURE_2D,  i_ShadowShader->m_depthTextureId2);
					
		glPushMatrix();
		glMultMatrixf(transformGL);
       }

	drawTriangle( &i_objecCount[1] );

	glPopMatrix();
				
	if(i_ShadowShader->m_numLights == 2)
        {
		glPopMatrix();
	}
	glMatrixMode(GL_MODELVIEW);
	glPopMatrix();
}

As you can see I am saving the first Texture to TEXTURE7 and the second Texture to TEXTURE6. As for the tutorial the author is transforming TEXTURE7 so that it gets to the right position, and thats what I am trying to do with TEXTURE7 and TEXTURE6. As I mentioned, it works with 1 light but not with 2. renderPass == 1 is where I draw the first depth texture, renderPass == 2 is where I draw the second, and the last step (within the else-bracket is the actual rendering.
A question would be if there is possible to bind both TEXTURE6 and TEXTURE7 and use them in the same shader? Couse that is what I am trying to do.

Here is what my Vertex shader looks like:


#define MAX_LIGHTS 8

uniform int numLights;

varying vec4 ShadowCoord[MAX_LIGHTS];
varying vec3 lightDir;
varying vec3 normal;

void main()
{
	vec3 viewVector, halfVector;
		
	vec4 diffuse, color = vec4(0.0);
		
	float NdotL;
		
	float NdotHV;
				
	normal = normalize(gl_NormalMatrix * gl_Normal);
		
       for (int i = 0; i < numLights; i++)
	{
		lightDir = normalize( vec3(gl_LightSource[i].position) );
			
		NdotL = max(dot(normal, lightDir), 0.0);
			
		diffuse += gl_FrontMaterial.diffuse * gl_LightSource[i].diffuse;
					
		if (NdotL > 0.0) 
		{
			NdotHV = max( dot(normal, normalize(gl_LightSource[i].halfVector.xyz)), 0.0 );
				
			color += (diffuse * NdotL + gl_FrontMaterial.specular * gl_LightSource[i].specular * pow(NdotHV, gl_FrontMaterial.shininess)) ;
		}
	}
		
	gl_TexCoord[0] = gl_MultiTexCoord0;
			
     	ShadowCoord[0] = gl_TextureMatrix[7] * gl_Vertex;
	if(numLights > 1)
	{
		ShadowCoord[1] = gl_TextureMatrix[6] * gl_Vertex;
	}
				
		
	gl_Position = ftransform();

	gl_FrontColor = (color);	
}

…and here is my fragment shader. They are kinda messy because I have involved a directional light shader into it, as well as a shader for a custom texture.


varying vec3 lightDir;
varying vec3 normal;

void main(void)
{	
	vec3 ct, cf;
	vec4 texel;
	float intensity = 0.0;
	float at, af;
	
	for(int i = 0; i < numLights; i++)
	{
		intensity += max(dot(lightDir, normalize(normal)), 0.0);
	}
	
	intensity = intensity/numLights;
	
	cf = intensity * (gl_FrontMaterial.diffuse).rgb + gl_FrontMaterial.ambient.rgb;
	af = gl_FrontMaterial.diffuse.a;

	
	texel = texture2D( tex, gl_TexCoord[0].st );
	ct = texel.rgb;
	at = texel.a;
	
	
	float shadow = 1.0;
	vec4 shadowCoordinateWdivided;
	float distanceFromLight;
	
	for (int i = 0; i < numLights; ++i)
	{
		shadowCoordinateWdivided = ShadowCoord[i] / ShadowCoord[i].w;
		
		shadowCoordinateWdivided.z += 0.0005;
		
		if(i == 0)
		{
			distanceFromLight = texture2D(ShadowMap1, shadowCoordinateWdivided.st).z;
		}
		else if(i == 1)
		{
			distanceFromLight = texture2D(ShadowMap2, shadowCoordinateWdivided.st).z;
		}
		
		if (ShadowCoord[i].w > 0.0)
		{
			shadow *= distanceFromLight < shadowCoordinateWdivided.z ? 0.5 : 1.0 ;
		}
	}

	gl_FragColor = shadow * gl_Color + vec4(ct * cf, at * af);
}

I also got code where I create the FBO and assign them a texture, sending stuff to the shader, adding a bias to each texture and calling the render function. Althought I highly NOT think that my problem lies there (but who would know). I could post that afterwards if it is needed.

To YOU if YOU have read everything so far I would like to give you a big THANKS. I really don’t know what the problem is, and suggestions are warmly welcome.

Incrementally comment out / disable your changes until Tex1 looks correct again. That’ll reveal what is wrong.

Just skimming, looks to me like you’ve got more PopMatrix calls than PushMatrix, but I realize you haven’t provided complete source.

Also, admittedly it’s been years since I sifted Fabien’s shadow mapping examples but I have to say looking at your code I’m a bit puzzled by the glActiveTexture calls to TEXTURE7 and 6 and the modifications to their texture matrices when you’re rendering the shadow map (you’re also doing a MultMatrix not a LoadMatrix so you have to be conscious of what was there before). IIRC, those texture matrices are for passing in the to-shadow-space transforms for the main scene render pass (for the projected shadow map lookups), not the shadow map rendering passes. But again, it’s been a while since I’ve looked at that.

Also, when you are doing main scene render pass, you’re not being careful to ensure that the correct texture matrix stack is active when you do your PopMatrix calls. And same possible issue with glMultMatrix.

You need to be doing some glGetError() calls in here to ensure that you aren’t throwing GL errors. I think you might be. Use this:


void checkGLError( const char hdr[] )
{
  int err = glGetError();
  if( err )
  {
    fprintf(stderr, "ERROR %s: %s
", hdr, gluErrorString(err));
    exit(1);
  }
}

...

checkGLError( "In foo()" );

This topic was automatically closed 183 days after the last reply. New replies are no longer allowed.