Отложенный рендеринг странное поведение
У меня возникли небольшие проблемы с реализацией механизма отложенного рендеринга с использованием OpenGL. Я могу сделать рендеринг в текстуру, и все данные верны для первого прохода (вычисление альбедо, нормалей и глубины), но когда дело доходит до вычисления текстур для молнии (эмиссионного и зеркального), у меня возникают некоторые проблемы.
Вот что у меня так далеко:
Проблема, как вы уже догадались, заключается в том, что такая линия показывает какое-то разделение между моим красным и синим светом.
Используя NSight, чтобы увидеть историю пикселя рядом со строкой, которая должна была быть красной (или смешанной с пикселем синего света), я могу увидеть это:
Таким образом, пиксель на самом деле окрашивается красным светом, но затем он становится синим, и я действительно не могу понять, почему.
Это код, который я использую для отложенного рисования:
//
// 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);
Это код, который я использую для прохождения точечного света (вызов функции DeferredPointPass выше) (_pointLightMesh - это сетка икосаэдра Sphere)
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();
}
И это шейдер, который я использую для расчета излучающих и зеркальных карт для точечного прохода света:
#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);
}
Я надеюсь, что у кого-то есть и представление о том, что здесь происходит, спасибо заранее!
1 ответ
Хорошо, я понял, чего мне не хватало. Мне нужно было отключить тест глубины, прежде чем делать точечный световой проход, и снова включить его, чтобы объединить окончательное изображение.
Мой код для функции отложенного рендеринга теперь выглядит следующим образом (все остальное остается прежним):
// 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
// ...
//