I'm having a little trouble implementing a deferred rendering engine using OpenGL. I can render to texture and all the datas are correct for the first pass (calculating albedo, normals and depth), but when it comes to calculate the textures for the lightning (emissive and specular) I'm having some troubles.
This is what I've got so far:
The problem is, as you might have guessed, is that sort of line showing some sort of division between my red and blue light.
Using NSight to see the history of a pixel right next to the line that should have been red (or blended with a blue light pixel), I can see this:
So the pixel IS actually getting colored by the red light, but then it goes back to blue, and I really can't understand why.
This is the code I use to do deferred drawing:
//
// Preparing albedo, normals and depth
//
GetGBuffer("PrepassBuffer")->BindAsRenderTarget();
Start(stage);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glDepthMask(GL_TRUE);
glEnable(GL_DEPTH_TEST);
DeferredPreparePass(stage, shadersManager->GetProgramFromName("deferred-prepare"));
Finish(stage);
//
// Peparing light emissive and specular textures
//
GetGBuffer("LightsBuffer")->BindAsRenderTarget();
Start(stage);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
DeferredPointPass(stage, shadersManager->GetProgramFromName("deferred-point"));
glCullFace(GL_BACK);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Finish(stage);
//
// Final composition of the image
//
Start(stage);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
DeferredCombinePass(stage, shadersManager->GetProgramFromName("deferred-combine"));
Finish(stage);
This is the code I use to do the point light pass (DeferredPointPass function call above) (_pointLightMesh is a Icosahedron Sphere mesh)
for (ASizeT i = 0; i < nLights; i++)
{
AnimaLight* light = lightsManager->GetLight((AUint)i);
if (!light->IsPointLight())
continue;
AnimaVertex3f lPos = light->GetPosition();
AFloat range = light->GetRange();
AnimaMatrix m1, m2, m3;
m1.Translate(lPos);
m2.Scale(range, range, range, 1.0f);
m3 = m1 * m2;
float dist = (lPos - activeCamera->GetPosition()).Length();
if (dist < light->GetRange())
glCullFace(GL_FRONT);
else
glCullFace(GL_BACK);
program->UpdateLightProperies(light);
program->UpdateMeshProperies(_pointLightMesh, m3);
program->UpdateRenderingManagerProperies(this);
program->EnableInputs(_pointLightMesh);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _pointLightMesh->GetIndexesBufferObject());
glDrawElements(GL_TRIANGLES, _pointLightMesh->GetFacesIndicesCount(), GL_UNSIGNED_INT, 0);
program->DisableInputs();
}
And this is the shader I use to calculate my emissive and specular maps for the point lightn pass:
#version 150 core
in mat4 frag_inverseProjectionViewMatrix;
out vec4 FragColor[2];
uniform sampler2D REN_GB_PrepassBuffer_DepthMap;
uniform sampler2D REN_GB_PrepassBuffer_NormalMap;
uniform vec2 REN_InverseScreenSize;
uniform vec3 CAM_Position;
uniform float PTL_Range;
uniform vec3 PTL_Position;
uniform vec3 PTL_Color;
uniform float PTL_ConstantAttenuation;
uniform float PTL_LinearAttenuation;
uniform float PTL_ExponentAttenuation;
void main()
{
vec3 pos = vec3((gl_FragCoord.x * REN_InverseScreenSize.x), (gl_FragCoord.y * REN_InverseScreenSize.y), 0.0f);
pos.z = texture(REN_GB_PrepassBuffer_DepthMap, pos.xy).r;
vec3 normal = normalize(texture(REN_GB_PrepassBuffer_NormalMap, pos.xy).xyz * 2.0f - 1.0f);
vec4 clip = frag_inverseProjectionViewMatrix * vec4(pos * 2.0f - 1.0f, 1.0f);
pos = clip.xyz / clip.w;
float dist = length(PTL_Position - pos);
if(dist > PTL_Range)
{
discard;
}
float atten = (PTL_ConstantAttenuation + PTL_LinearAttenuation * dist + PTL_ExponentAttenuation * dist * dist + 0.00001);
vec3 incident = normalize(PTL_Position - pos);
vec3 viewDir = normalize(CAM_Position - pos);
vec3 halfDir = normalize(incident + viewDir);
float lambert = clamp(dot(incident, normal), 0.0f, 1.0f);
float rFactor = clamp(dot(halfDir, normal), 0.0f, 1.0f);
float sFactor = pow(rFactor, 33.0f);
FragColor[0] = vec4(PTL_Color * lambert / atten, 1.0f);
FragColor[1] = vec4(PTL_Color * sFactor / atten * 0.33f, 1.0f);
}
I hope someone has and idea of what's going on here, thanks in advance!
Ok I figured out what I was missing. I needed to disable depth test before doing the point light pass and the re-enable it to combine the final image.
My code for the deferred rendering function now looks like this (all the rest is still the same):
// Same as before
// ...
//
//
// Peparing light emissive and specular textures
//
GetGBuffer("LightsBuffer")->BindAsRenderTarget();
Start(stage);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ONE);
glDepthMask(GL_FALSE); // <---- this is what I was missing
DeferredPointPass(stage, shadersManager->GetProgramFromName("deferred-point"));
glCullFace(GL_BACK);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDepthMask(GL_TRUE); // <---- this is what I was missing
Finish(stage);
// Same as before
// ...
//