写入帧缓冲区的问题(颜色附件始终为黑色)

Issues writing to Framebuffer (Color attachments always black)

我正在尝试使用帧缓冲区作为延迟着色的几何缓冲区。我在写入和读取帧缓冲区的颜色附件时遇到问题。

我想做的就是验证我的帧缓冲区的颜色附件是否有一些数据。我通过绑定其中一个颜色附件并绘制全屏四边形来做到这一点。每个颜色附件都会导致全黑屏幕,即使我已经验证我的统一变量正在接收它们需要的数据。

我的帧缓冲区设置如下:

    glGenFramebuffers(1, &FBOID);
    glBindFramebuffer(GL_FRAMEBUFFER, FBOID);

    int WIDTH = windowDetails->width;
    int HEIGHT = windowDetails->height;

    glGenTextures(1, &gPosition);
    glBindTexture(GL_TEXTURE_2D, gPosition);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, WIDTH, HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gPosition, 0);

    glGenTextures(1, &gAlbedo);
    glBindTexture(GL_TEXTURE_2D, gAlbedo);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WIDTH, HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, gAlbedo, 0);

    glGenTextures(1, &gNormal);
    glBindTexture(GL_TEXTURE_2D, gNormal);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, WIDTH, HEIGHT, 0, GL_RGBA, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT2, GL_TEXTURE_2D, gNormal, 0);

    glGenTextures(1, &gEffects);
    glBindTexture(GL_TEXTURE_2D, gEffects);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, WIDTH, HEIGHT, 0, GL_RGB, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT3, GL_TEXTURE_2D, gEffects, 0);

    GLuint attachments[4] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 };
    glDrawBuffers(4, attachments);

    glGenRenderbuffers(1, &zBuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, zBuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, WIDTH, HEIGHT);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, zBuffer);

    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
    {
        std::cout << "Framebuffer not complete !" << std::endl;
    }   

每一帧,我都会绑定这个帧缓冲区并使用我的几何着色器绘制它。然后我将绑定一个测试着色器,通过将所有颜色附件绑定到它们自己的纹理单元并将其中一个传递给测试着色器来检查颜色附件的内容是否有一些数据:

glDisable(GL_BLEND); // No blend for deffered rendering
glEnable(GL_DEPTH_TEST); // Enable depth testing for scene render

glBindFramebuffer(GL_FRAMEBUFFER, FBOID); // Start drawing to FBO
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glUseProgram(gShader);

SubmittedGeometry& geometry = defferedGeometry[0];

glm::mat4 projViewModel = projection * view * geometry.transform;
glm::mat4& prevProjViewModel = prevProjViewModels.count(geometry.handle) <= 0 ? projViewModel : prevProjViewModels.at(geometry.handle);
prevProjViewModels.insert({ geometry.handle, projViewModel });

glUniformMatrix4fv(matModelLoc, geometry.transform);
glUniformMatrix4fv(matProjViewLoc, projViewModel);
glUniformMatrix4fv(matPrevProjeViewLoc, prevProjViewModel);

// Bind albedo textures
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, albedoTexID);
glUniform1i(albedoLoc, 0);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, normalTexID);
glUniform1i(normalLoc, 1);

glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, roughnessTexID);
glUniform1i(rougnessLoc, 2);

glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, metalnessTexID);
glUniform1i(metalnessLoc, 3);

glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, aoTexID);
glUniform1i(aoLoc, 4);

glBindVertexArray(geometry.vaoID);
glDrawElements(GL_TRIANGLES, geometry.indices, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);

glBindFramebuffer(GL_FRAMEBUFFER, 0); // Done drawing to FBO

// Test FBO color attachments
glUseProgram(testShaderID);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, gPosition);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, gAlbedo);

glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, gNormal);

glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, gEffects);

glUniform1i(testTextureLoc, 1);
quad->Draw();

为 testTexture 采样器分配 0、1、2 或 3 都会导致黑屏。

几何着色器:

VERTEX SHADER
#version 420

layout (location = 0) in vec3 vPosition;
layout (location = 1) in vec3 vNormal;
layout (location = 2) in vec2 vTextureCoordinates;
layout (location = 3) in vec3 vBiNormal;
layout (location = 4) in vec3 vTangent;

uniform mat4 uMatModel;
uniform mat4 uMatView;
uniform mat4 uMatProjection;
uniform mat4 uMatProjViewModel;
uniform mat4 uMatPrevProjViewModel;

out vec3 mViewPosition;
out vec2 mTextureCoordinates;
out vec3 mNormal;
out vec4 mFragPosition;
out vec4 mPrevFragPosition;

void main()
{   
    // Translate to view space
    vec4 viewFragmentPosition = uMatView * uMatModel * vec4(vPosition, 1.0f);
    mViewPosition = viewFragmentPosition.xyz;
    
    mTextureCoordinates = vTextureCoordinates;
    
    // Apply transformation to normal
    mat3 matNormal = transpose(inverse(mat3(uMatView * uMatModel)));
    mNormal = matNormal * vNormal;
    
    mFragPosition = uMatProjViewModel * vec4(vPosition, 1.0f);
    mPrevFragPosition = uMatPrevProjViewModel * vec4(vPosition, 1.0f);
    
    gl_Position = uMatProjection * viewFragmentPosition;
};


FRAGMENT SHADER
#version 420 

layout (location = 0) out vec4 gPosition;
layout (location = 1) out vec4 gAlbedo;
layout (location = 2) out vec4 gNormal;
layout (location = 3) out vec3 gEffects;

in vec3 mViewPosition;
in vec2 mTextureCoordinates;
in vec3 mNormal;
in vec4 mFragPosition;
in vec4 mPrevFragPosition;

uniform sampler2D uAlbedoTexture1;

uniform sampler2D uNormalTexture;
uniform sampler2D uRoughnessTexture;
uniform sampler2D uMetalnessTexture;
uniform sampler2D uAmbientOcculsionTexture;

const float nearPlane = 1.0f;
const float farPlane = 1000.0f;

float LinearizeDepth(float depth);
vec3 ComputeTextureNormal(vec3 viewNormal, vec3 textureNormal);

void main()
{
    vec3 normal = normalize(texture(uNormalTexture, mTextureCoordinates).rgb * 2.0f - 1.0f); // Sample normal texture and convert values in range from -1.0 to 1.0
    
    vec2 fragPos = (mFragPosition.xy / mFragPosition.w) * 0.5f + 0.5f;
    vec2 prevFragPos = (mPrevFragPosition.xy / mPrevFragPosition.w) * 0.5f + 0.5f;
    
    gPosition = vec4(mViewPosition, LinearizeDepth(gl_FragCoord.z)); // Set position with adjusted depth
    
    gAlbedo.rgb = vec3(texture(uAlbedoTexture1, mTextureCoordinates)); // Sample and assign albedo rgb colors
    
    gAlbedo.a = vec3(texture(uRoughnessTexture, mTextureCoordinates)).r; // Sample and assign roughness value
    
    gNormal.rgb = ComputeTextureNormal(mNormal, normal); // Assign normal
    gNormal.a = vec3(texture(uMetalnessTexture, mTextureCoordinates)).r; // Sample and assign metalness value
    
    gEffects.r = vec3(texture(uAmbientOcculsionTexture, mTextureCoordinates)).r;
    gEffects.gb = fragPos - prevFragPos;
}

float LinearizeDepth(float depth)
{
    float z = depth * 2.0f - 1.0f;
    return (2.0f * nearPlane * farPlane) / (farPlane + nearPlane - z * (farPlane - nearPlane));
}

vec3 ComputeTextureNormal(vec3 viewNormal, vec3 textureNormal)
{
    // Get partial derivatives 
    vec3 dPosX = dFdx(mViewPosition);
    vec3 dPosY = dFdy(mViewPosition);
    vec2 dTexX = dFdx(mTextureCoordinates);
    vec2 dTexY = dFdy(mTextureCoordinates);

    // Convert normal to tangent space
    vec3 normal = normalize(viewNormal);
    vec3 tangent = normalize(dPosX * dTexY.t - dPosY * dTexX.t);
    vec3 binormal = -normalize(cross(normal, tangent));
    mat3 TBN = mat3(tangent, binormal, normal);

    return normalize(TBN * textureNormal);
}

我的测试着色器代码是:

VERTEX SHADER
#version 420

layout (location = 0) in vec3 vPosition;
layout (location = 1) in vec2 vTextureCoordinates;

out vec2 mTextureCoordinates;

void main()
{   
    mTextureCoordinates = vTextureCoordinates; // Pass out texture coords
    
    gl_Position = vec4(vPosition, 1.0f);
};



FRAGMENT SHADER
#version 420 

in vec2 mTextureCoordinates;

out vec4 oColor;

uniform sampler2D testTexture;

void main()
{
    vec3 color = texture(testTexture, mTextureCoordinates).rgb;
    oColor = vec4(color, 1.0f);
}

我已确保 glCheckFramebufferStatus 始终是完整的,并且我的所有统一变量都已正确传递到着色器

原来我的代码是正确的。我的问题是我穿过了错误的矢量,所以我的相机的视图矩阵是错误的。