hello all,

I'm having trouble understanding the math behing lightvolumes in a deferred shading process. I've implemented a solution that works but I don't exactly understand why it works the way it does. Here's essentially what I do:
  • setting up a g-buffer for albedo, depth, lightmaps and normals. Depth buffer is GL_DEPTH24_STENCIL8.
  • 1. pass: render the geometry in the g-buffer.
  • 2. pass for every light in the scene draw a sphere at (0,0,0) and scale/translate the sphere to fit the lights radius and position.
  • enable stencil depth to increment/decrement when the viewray enters/leaves the sphere.
  • 3. pass render pointlights only in the area inside the sphere by querying stencil.
  • Blit the rest of the geometry from g-buffer to fragment shader color output.

Now this all works nice and I believe I got the implementation right. But when it comes to the math to calculate the lights illumination in the light shader I still fail to wrap my mind around it.

Here is what I did and don't understand:

Now the lights fragment shader looks like this. because the lightsource is always inside the sphere at its center and the sphere is being translated/scaled, the lights position itself is always (0,0,0). I've done all my math in eye/view space.

Code :
void main(void) {
  io_texcoord = li_texcoord;
  io_lightpos = u_mvmatrix * vec4(0,0,0,1); // get lights center position in eye space
  gl_Position = u_pjmatrix * u_mvmatrix * li_vtx;
}

Here comes the fragment shader and this one gives me a headeache:

To get the fragments 3D position in view space I derive my position from depth buffer:

u_pjimatrix is the transposed inverse projectionmatrix.
Please note I have to TRANSPOSE the matrix in order to make the lighting work. I do not understand why I have to do this!
To transpose the projectionmatrix I set the transpose variable in glUniformMatrix4fv() to GL_TRUE.

Code :
vec3 GetPositionFromDepth(vec2 t) {
  float depth = texture(u_depth, t).r; // get depth in clip space
  vec4 p = vec4(t.xy * 2 - 1, depth * 2 - 1, 1) * u_pjimatrix;
  p /= p.w;
  return p.xyz;
}

The actual code to calculate the light is something I got to work by trial and error but I still not quite understand:

Code :
vec4 DoPointLight(vec3 pos, vec3 n) {
  vec3 ldir = pos - io_lightpos.xyz;   // direction should be in eye space, right?
// maybe someone can explain why this code works with in inverse transposed projection matrix for
// deriving the eye space pixel 3D position?
  float radsqr = u_lrad * u_lrad;  
  float dist = min(dot(ldir, ldir), radsqr) / radsqr;      
  ldir = normalize(ldir);
  float diffuseDot = dot(n, ldir);    
  vec3 diffuse = vec3(1) * clamp(diffuseDot, 1.0, 1.0) * (1.0 - dist);
  return vec4(diffuse, 1);
}

the main of the fragment shader is very strightforward:
Code :
void main(void) {
  vec2 t = vec2(gl_FragCoord.x / screenx, gl_FragCoord.y / screeny);
  vec4 c = texture(u_albedo, t);
  vec4 l = texture(u_light, t);
  vec3 n = texture(u_normal, t).rgb;     
  vec3 p = GetPositionFromDepth(t); // pixel pos in eye space
 
  lo_fragcolor = clamp(c * vec4(u_lcolor, 1) * (l + DoPointLight(p, n)), 0, 1);
}

Now the above code works but it shouldn't since I have to transpose the inverse projectionmatrix to obtain the 3D pixel position in eye space. Please keep in mind the light is at the ogigin inside a translated sphere. Maybe someone can shade some light on this issue?

Thanks a bunch in advance
Saski