Help with deferred rendering lighting pass

Hi,
I’ve been busting away at this for a few days now, as anyone with a gamedev.net account can tell you. I am working on a deferred render, and have the first past done. Now I am working on the lighting pass but have came up with some strange errors. Not only does the light move and rotate with me (its suposted to be a fixed location point light) but there is a black spot in the center of the screen. Can someone please help me?

in main
void init(){

GLfloat pos[] = { 0.0, 1.0, 0.0, 1.0 };
GLfloat dif[] = { 0.0, 1.0, 1.0, 1.0 };
glLightfv( GL_LIGHT0, GL_POSITION, pos );
glLightfv( GL_LIGHT0, GL_DIFFUSE, dif );
}

//start the second pass
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glLoadIdentity();
glLightfv( GL_LIGHT0, GL_POSITION, pos );

and the light shaders

vert

varying vec2 TexCoord;

void main(){
gl_Position = ftransform();
TexCoord = gl_MultiTexCoord0.st;
}

and frag, its kinda rought, need to clean it up after

uniform sampler2D colorMap;
uniform sampler2D normalMap;

varying vec2 TexCoord;

const vec2 camerarange = vec2( 1.0, 1000.0 );
const vec3 screensize = vec3( 640.0, 480.0, 640.0 / 480.0);

float DepthToZPosition(in float depth) {
return camerarange.x / (camerarange.y - depth * (camerarange.y - camerarange.x)) * camerarange.y;
}

void main(){
vec3 n = texture2D( normalMap, TexCoord).xyz ;
vec3 color = texture2D( colorMap, TexCoord ).rgb;
float depth = texture2D( normalMap, TexCoord).w;

    vec3 FragPosition = vec3( (((gl_FragCoord.x / screensize.x) - 0.5 ) * 2.0),
    (((-gl_FragCoord.y / screensize.y) + 0.5 ) * (2.0 / screensize.z)),
    DepthToZPosition( depth) );
    FragPosition.xy *= FragPosition.z;
    vec3 lightDir = normalize( gl_LightSource[0].position.xyz - FragPosition );
    vec3 dir = lightDir;
    float dist = length( gl_LightSource[0].position.xyz - FragPosition );
    vec3 pos = FragPosition;//vec3( 0.0, 1.0, 0.0 );
    float nDotL = dot(n,dir);
    vec3 hv = normalize( dir + normalize( FragPosition )  );
    if( nDotL > 0.0 ){
            float att = 1.0 / ( gl_LightSource[0].constantAttenuation +
                                    gl_LightSource[0].linearAttenuation * dist +
                                    gl_LightSource[0].quadraticAttenuation * dist * dist);
            color.xyz += att * ( gl_LightSource[0].diffuse.rgb * nDotL + gl_LightSource[0].ambient.rgb );
            float nDotHV = max(dot(n, hv), 0.0 );
            color += att * 0.4 * gl_LightSource[0].specular.rgb * pow( nDotHV, 1.0 ); //0.4 = spec power, 1.0 = shineyness
    }
    //color = FragPosition;
    gl_FragColor = vec4( color, 1.0 );

}

and here is the first pass if anyone needs it

vert
varying vec3 Normal;
varying vec2 TexCoord; //gl_TexCoord is deprecated in 1.3 =/
varying vec2 Position;

void main(){
TexCoord = gl_MultiTexCoord0.st; //but so is MultiTexCoord… find a replacement :stuck_out_tongue:
gl_Position = ftransform();

    Normal = gl_NormalMatrix * gl_Normal;
    Position = (gl_ModelViewMatrix * gl_Vertex).xy;

}

and frag

uniform sampler2D TextureMap;
uniform float farReciprocal; //the far plain Reciprocal, IE 1/far ( multi is faster then division )

//NOTE: varying is deprecated in 1.3
//change to in for frag and out for vert
varying vec3 Normal;
varying vec2 TexCoord; //Becouse gl_TexCoord is depercated…
varying vec2 Position;

void main(){
//normal is not normalized, so we make the normal normal :stuck_out_tongue:
vec3 n = normalize( Normal );

    float z = ( gl_FragCoord.z / gl_FragCoord.w ) * farReciprocal;
    gl_FragData[0] = texture2D( TextureMap, TexCoord );
    gl_FragData[1] = vec4( n, z );

}

I didn’t have time to read all of this. but a quick correction :

You specify light poition on GL side, immediately after glLoadIdentity. That means before you do any camera transformation, right? If that’s the case, then the light does well & follows you, since you don’t take into account a ‘camera’, so while the rest of the world is moving, your light stays fixed at a constant transformation.

So 1st correction : specify you glLight Position immediately after the camera transformation.

For the second pass there are no camera transformations, a simple squad is rendered using the MRTs…

//start the second pass
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glLoadIdentity();
glLightfv( GL_LIGHT0, GL_POSITION, pos );

//now we draw a square with the mrt texture
glActiveTexture(GL_TEXTURE0);
glBindTexture( GL_TEXTURE_2D, mrt[drawMRT] );

    glActiveTexture(GL_TEXTURE1);
    glBindTexture( GL_TEXTURE_2D, mrt[1] );

glBegin( GL_QUADS );
glTexCoord2f( 0.0, 0.0 ); glVertex3f( -10,-10, -25.0f);
glTexCoord2f( 1.0, 0.0 ); glVertex3f( 10,-10, -25.0f);
glTexCoord2f( 1.0, 1.0 ); glVertex3f( 10, 10, -25.0f);
glTexCoord2f( 0.0, 1.0 ); glVertex3f( -10, 10, -25.0f);
glEnd();
glBindTexture( GL_TEXTURE_2D, 0 );

drawMRT is either 1 or 0, used for debugging…

also if i wrap the light postion in push and pop with a camera call, i still get the same effect.

    glPushMatrix();
    camera.setView();
    glLightfv( GL_LIGHT0, GL_POSITION, pos );
    glPopMatrix();

and if i remove the push and pop… the quad moves which cannot happen.

Ok I read the shader code & it seems that you’ve messed up with the spaces.

In the 1st pass, you store the normal in view space.
In the second pass, you pass the light in view space, but compute the position in screen space (and not even the corect one btw) . And then everything falls apart :slight_smile:

You just need to compute the position in view space, there are many ways to do this, and many articles here & in Gamedev (look for deferred rendering articles, position reconstruction from Z, etc.)

Hey, thanks for the information. I was under the impression the lights position was always in world space… Could you give me any advice on how to make it in world space?
Currently also trying to find those articles you mentions, but my lack of searching skills is becoming very apparent lol.
Thanks.

light position is given in eye space in the shader built-ins according the the glsl spec. To keep all in one space, like the eye space which is the space where the lighting operations are done, you just have to transform vertices coordinates (gl_Vertex) by the modelview matrix.

Thanks for hte information, If I got what you where saying (and I had done this before due to a post on some site that I dont rember lol) The following should work for packing

Position = (gl_ModelViewMatrix * gl_Vertex).xyz;
gl_FragData[2] = vec4( Position, 1.0 );

NOTE: I added a new MRT becouse I figured it would be easyer just getting the postion working and later I can worry about packing it so I just store the depth…

In the light pass I just pass it in with
vec3 FragPosition = texture2D( positionMap, TexCoord ).xyz;

This did fix a small amount of errors, mainly the black spot in the middle, however walls are now black 90% of the time and must be viewed at strange angles to show up ( I dont have a diffuse set, so it is going to default colors to black ), also the color of the ground messes up If I look at it odd. This makes me believe I am getting something wrong here…

To keep the light in world space, just pass it as a uniform, as is, not via glLight. But view space is a good idea anyway & simplifies some light computations later. But be consistent with the spaces!

(Model data)
(gl_ModelViewMatrix * gl_Vertex) -> view space (with your camera set up ofc)

(Light)
pushMView >> setCamera >> glLight >> popMView -> view space

I assume you use float MRTs, right? If not, use another format for your MRT textures. Like internalformat = GL_RGBA16F_ARB, pixeformat = GL_RGBA, datatype = GL_FLOAT.

Thanks for the help, Got that working and I can tell the light is now staying in place. However, I can tell this due to the fact that everything behind the light is black. It also turns with me.
I really appreciate everything you guys are doing to help me, thanks a lot! :slight_smile:

If it turns with you and nothing is lit behind it, then probably it is still wrong :slight_smile:

Any more details / updates?

Heres the frag shader, vert hasn’t changed much. Havn’t had much time to work on it and probably wont for a few days =/

uniform sampler2D colorMap;
uniform sampler2D normalMap;
uniform sampler2D positionMap;

varying vec2 TexCoord;

const vec2 camerarange = vec2( 1.0, 1000.0 );
const vec3 screensize = vec3( 640.0, 480.0, 640.0 / 480.0);

float DepthToZPosition(in float depth) {
return camerarange.x / (camerarange.y - depth * (camerarange.y - camerarange.x)) * camerarange.y;
}

void main(){
vec3 n = normalize( texture2D( normalMap, TexCoord).xyz * 2.0 - 1.0);
vec3 color = texture2D( colorMap, TexCoord ).rgb;
float depth = texture2D( normalMap, TexCoord).w;

    vec3 FragPosition = texture2D( positionMap, TexCoord ).xyz;
    //vec3 color = vec3(0.0, 0.0, 0.0 );    
    vec3 lightDir = normalize( gl_LightSource[0].position.xyz - FragPosition );
    vec3 dir = lightDir;
    float dist = length( gl_LightSource[0].position.xyz - FragPosition );
    vec3 pos = FragPosition;//vec3( 0.0, 1.0, 0.0 );
    float nDotL = dot(n,dir);
    vec3 hv = normalize( dir +  FragPosition );
    if( nDotL > 0.0 ){
            float att = 1.0 / ( gl_LightSource[0].constantAttenuation +
                                    gl_LightSource[0].linearAttenuation * dist +
                                    gl_LightSource[0].quadraticAttenuation * dist * dist);
            color.xyz += att * ( gl_LightSource[0].diffuse.rgb * nDotL + gl_LightSource[0].ambient.rgb );
            float nDotHV = max(dot(n, hv), 0.0 );
            color += att * 0.4 * gl_LightSource[0].specular.rgb * pow( nDotHV, 1.0 ); //0.4 = spec power, 1.0 = shineyness
    }
    //color = lightDir;//vec3(FragPosition);
    gl_FragColor = vec4( color, 1.0 );

}

the position map is saved as it shows above (its just gl_ModelViewMatrix * gl_Vertex)

vec3 n = normalize( texture2D( normalMap, TexCoord).xyz * 2.0 - 1.0);
This differs from the line in a previous shader in a previous post. Are you sure you’re saving the normals right?

Since you have a float texture (as you store positions), you
store :
normal = gl_NormalMatrix * gl_Normal;
restore :
normal = glTexture2D(normalMap,texc).xyz;

…Which leads to the question. Do you use float textures?
If not, there’s one more problem :slight_smile: Positions can’t be stored (successfully) in RGBA8.

Oh wow, I had forgot I added that, and it fixed it!! ^___^ Thank you so much!!!