Blending multiple lights in deferred renderer

Started by
9 comments, last by kalle_h 11 years, 8 months ago
Hello.
I was looking for methods to render multiple lights without redrawing the scene multiple times and i found article about "Deferred Lighting". It didnt took me much time to render my scene into 4 buffers using FBO, i store 4 textures for position, normals, color and depth, then i render a fullscreen quad in ortho mode and apply lighting shader to it but, as i've suspected my shader doesn't blend multiple lights together so if i draw light B, the light A isnt rendered, now im capable of rendering just one light on scene.

I would like to blend those lights but to be honest GLSL isn't something that i'm experienced in.

This is the light pass shader that i'm using, i found it somewhere but i'm not sure who's the author of it.

Fragment:

varying vec3 p;
varying vec3 sDir;
varying vec4 lpos;
uniform sampler2D normalBuffer;
uniform sampler2D depthBuffer;
uniform sampler2D colorBuffer;
uniform vec3 lightPos;
uniform vec3 lightColor;
uniform float lightRadius;
float color_to_float(vec3 color)
{
const vec3 byte_to_float = vec3(1.0,1.0/256.0,1.0/(256.0*256.0));
return dot(color,byte_to_float);
}
vec3 lighting(vec3 SColor, vec3 SPos, float SRadius, vec3 p, vec3 n, vec3 MDiff, vec3 MSpec, float MShi)
{
vec3 l = SPos-p;
vec3 v = normalize(p);
vec3 h = normalize(v+l);
l = normalize(l);
vec3 Idiff = max(0.0, dot(l, n)) * MDiff * SColor;
float att = max(0.0,1.0-length(l)/SRadius);
vec3 Ispec = pow(max(0.0,dot(h,n)),MShi)*MSpec*SColor;
return att*(Idiff+Ispec);
}
void main()
{
vec3 depthcolor = texture2D(depthBuffer, gl_TexCoord[0].st).rgb;
vec3 n = texture2D(normalBuffer, gl_TexCoord[0].st).rgb;
float pixelDepth = color_to_float(depthcolor);
vec3 WorldPos = pixelDepth * normalize(sDir);
gl_FragColor = vec4(lighting(lightColor, lightPos, lightRadius, WorldPos, n, vec3(1.0,1.0,1.0), vec3(1,1,1) ,1) ,128);
gl_FragColor *= texture2D(colorBuffer, gl_TexCoord[0].st);
}



Vertex:

uniform vec3 lightPos;
attribute vec3 screenDir;
varying vec3 sDir;
varying vec4 lpos;
varying vec4 Ldir;
void main()
{
gl_TexCoord[0] = gl_MultiTexCoord0;
gl_TexCoord[1] = gl_MultiTexCoord0;
gl_TexCoord[2] = gl_MultiTexCoord0;
gl_Position = ftransform();
sDir = screenDir;
vec4 lp = vec4(lightPos,1);
lpos = lp;
}
Advertisement
You have to call it once for every light, with glBlendFunc(GL_ONE, GL_ONE) so that it adds the results together.
You can make an array of light sources, using a uniform array (for lightPos, lightColor and lightRadius). Then you make a loop in the fragment shader. You also need another uniform that specifies the number of lights.
[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

You can make an array of light sources, using a uniform array (for lightPos, lightColor and lightRadius). Then you make a loop in the fragment shader. You also need another uniform that specifies the number of lights.


Pushing all your lights into a single shader does not sound like a good idea to me.

The normal way of rendering deferred lights is to run your lighting shader per light using additive blending.
You could use light volumes for this (make sure you handle cases for when the camera is both inside and outside of the light radius) or plain screen quads.

I gets all your texture budgets!


Pushing all your lights into a single shader does not sound like a good idea to me.

Please explain why. I am doing that just now, and would sure like to know disadvantages and better ways.

One advantage with doing all lights in the deferred lighting phase is that it is easier to do HDR computation, where you do the tone mapping in the end. I suppose that can be done in a this step, but I am afraid it adds more overhead?
[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/
Thanks Hedanito, it worked ;)
Thanks Hedanito, it worked ;)

This shows how i render the lighting:
-[set blending]
-[bind lighting shader]
--[for each visible light]
----[send lightPos, radius and color to shader]
----[render quad]
-[unbind shader]

PS. sorry for double post, my connection lagged a bit.

[quote name='Radikalizm' timestamp='1345405507' post='4971190']
Pushing all your lights into a single shader does not sound like a good idea to me.

Please explain why. I am doing that just now, and would sure like to know disadvantages and better ways.

One advantage with doing all lights in the deferred lighting phase is that it is easier to do HDR computation, where you do the tone mapping in the end. I suppose that can be done in a this step, but I am afraid it adds more overhead?
[/quote]

You're basically limiting yourself when pushing all your lighting calculations through a single shader. When you use a multipass approach you can truly render any amount of lights as the data required for your lighting remains constant for each pass. Your shader will also become less complex as you don't have to deal with loops.
Another optimization which only works with the multi-pass approach is the usage of light volumes.

I don't see how you're doing tonemapping directly in your light shader? How do you handle multiple types of lights? Unless your shader is heavy with branches you can't really render all your ambient lights, point lights, spot lights, directional lights, and any other type of light you might have with a single shader.

Tonemapping is generally seen as a post-processing step which is completely decoupled from your lighting pass.

I gets all your texture budgets!

Well now i'm in another trouble, my objects became transparent, i like how the lights blend but the rest should be solid.
btw. thank you Radikalizm for idea, i will try doing it your way.

lightJPG_xprnxxh.JPG

You're basically limiting yourself when pushing all your lighting calculations through a single shader. When you use a multipass approach you can truly render any amount of lights as the data required for your lighting remains constant for each pass. Your shader will also become less complex as you don't have to deal with loops.
Another optimization which only works with the multi-pass approach is the usage of light volumes.

I suppose it is the same as shadow volumes?

I don't see how you're doing tonemapping directly in your light shader? How do you handle multiple types of lights? Unless your shader is heavy with branches you can't really render all your ambient lights, point lights, spot lights, directional lights, and any other type of light you might have with a single shader.
[/quote]
Ha, yes, it is heavy with branches and loops. Anyway, thanks, I see the advantages and disadvantages of the way you describe.
[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

This topic is closed to new replies.

Advertisement