Отложенный рендеринг странное поведение

У меня возникли небольшие проблемы с реализацией механизма отложенного рендеринга с использованием 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
// ...
//
Другие вопросы по тегам