延迟着色OpenGL实现



我目前正试图在OpenGL 3.2中实现延迟着色,并且有一个问题,无论我尝试什么,我似乎都无法解决。

我像人们期望的那样分两步实现它(几何通道和照明通道)。在编译和运行它之后,屏幕显示了我准备的场景,几乎就像人们期望的那样。物体的颜色是正确的,它们也被放置在我想要的位置和方式。

问题是,光的计算似乎对颜色没有影响,不管怎样。很多小时后,我发现,位置和法线的纹理似乎包含相同的内容,就像颜色纹理一样。

如果将光照片段着色器的最后一行从fragColor = lightIntensity * color;更改为fragColor = lightIntensity * norm;fragColor = lightIntensity * pos;,则绝对不会影响屏幕的渲染方式。

我试了很多办法想弄清楚是什么出了问题,但老实说,我不知道它可能是什么。
如果有人能帮我,那就太好了。

我的渲染方法是这样的:

void render()
{
    //geometry pass
    gBuffer->bindForWriting();
    geometryShader->use(true);
    calculateGBuffer();

    //lighting pass 
    gBuffer->bindForReading(lightShader->programID());
    lightShader->use(true);
    drawOnScreen();
}

gBuffer对象的初始化如下:

void GBuffer::initializeFBO(int viewWidth, int viewHeight)
{
    //initialize fbo and corresponding textures;
    glGenFramebuffers(1, &fbo_ID);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo_ID);
    glGenTextures(1, &colorTexture_ID);
    glBindTexture(GL_TEXTURE_2D, colorTexture_ID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, viewWidth, viewHeight, 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_ATTACHMENT0, GL_TEXTURE_2D, colorTexture_ID, 0);
    glGenTextures(1, &posTexture_ID);
    glBindTexture(GL_TEXTURE_2D, posTexture_ID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, viewWidth, viewHeight, 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_ATTACHMENT1, GL_TEXTURE_2D, posTexture_ID, 0);
    glGenTextures(1, &normTexture_ID);
    glBindTexture(GL_TEXTURE_2D, normTexture_ID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB16F, viewWidth, viewHeight, 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_ATTACHMENT2, GL_TEXTURE_2D, normTexture_ID, 0);
    GLuint attachments[3] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2 };
    glDrawBuffers(3, attachments);
    glGenRenderbuffers(1, &depthBuffer_ID);
    glBindRenderbuffer(GL_RENDERBUFFER, depthBuffer_ID);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, viewWidth, viewHeight);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthBuffer_ID);

    //Check Status
    if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        qDebug() << "error while initializing framebuffer" << glCheckFramebufferStatus(GL_FRAMEBUFFER);
    else{
        qDebug() << "framebuffer successfully created";
        initialized = true;
    }
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

方法bindForReadingbindForWriting:

void GBuffer::bindForWriting()
{
    glBindFramebuffer(GL_FRAMEBUFFER, fbo_ID);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void GBuffer::bindForReading(GLuint programID)
{
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, colorTexture_ID);
    GLuint samplerTexture_ID = glGetUniformLocation(programID, "colorTexture");
    glUniform1i(samplerTexture_ID, 0);
    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, posTexture_ID);
    samplerTexture_ID = glGetUniformLocation(programID, "positionTexture");
    glUniform1i(samplerTexture_ID, 1);
    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, normTexture_ID);
    samplerTexture_ID = glGetUniformLocation(programID, "normTexture");
    glUniform1i(samplerTexture_ID, 2);
}

最后是4个着色器:

Geometry Vertex Shader:

#version 150
#extension GL_ARB_separate_shader_objects : enable
uniform mat4 MVPMatrix;
uniform mat4 modelMatrix;
in vec4 in_position;
in vec4 in_color;
in vec2 in_texcoord;
in vec3 in_norm;
out vec4 color_varying;
out vec3 frag_position;
out vec3 norm_vec;
out vec2 texcoord_varying;
void main()
{
    gl_Position = MVPMatrix * in_position;
    vec4 worldPosition = (modelMatrix * in_position);
    frag_position = worldPosition.xyz;
    norm_vec = in_norm;
    color_varying = in_color;
    texcoord_varying = in_texcoord;
}

Geometry Fragment Shader:

#version 150
#extension GL_ARB_explicit_attrib_location : enable
in vec4 color_varying;
in vec3 frag_position;
in vec3 norm_vec;
in vec2 texcoord_varying;
layout (location = 0) out vec4 fragColor;
layout (location = 1) out vec3 fragPosition;
layout (location = 2) out vec3 frag_norm_vec;
uniform sampler2D myTexture;
void main()
{
    vec4 texel = texture(myTexture, texcoord_varying);
    fragColor = texel * color_varying;
    fragPosition = frag_position;
    frag_norm_vec = normalize(norm_vec);
}
照明VertexShader:

#version 150
#extension GL_ARB_explicit_attrib_location : enable
layout (location = 0) in vec2 in_position;
out vec2 texCoord;
void main()
{
    gl_Position = vec4(in_position, 0, 1.0f);
    texCoord = in_position;
    if(texCoord.x == -1.0f)
        texCoord.x = 0.0f;
    if(texCoord.y == -1.0f)
        texCoord.y = 0.0f;
}

光照片段着色器(没有光照计算使其更短)

#version 150
#extension GL_ARB_separate_shader_objects : enable
out vec4 fragColor;
in vec2 texCoord;

uniform sampler2D colorTexture;
uniform sampler2D positionTexture;
uniform sampler2D normTexture;
void main()
{
    //extract fragment data from fbo
    vec3 pos = texture(positionTexture, texCoord).rgb;
    vec3 norm = texture(normTexture, texCoord).rgb;
    vec4 color = texture(colorTexture, texCoord);

    fragColor = lightIntensity * color;
}

很抱歉,但是我无法缩小错误范围

问题很可能出在这里的操作顺序上:

gBuffer->bindForReading(lightShader->programID());
lightShader->use(true);

bindForReading()中,您有这样的调用:

samplerTexture_ID = glGetUniformLocation(programID, "positionTexture");
glUniform1i(samplerTexture_ID, 1);

glUniform*()调用在当前活动的程序上设置统一的值。因为你在之后使lightShader激活,统一值将在之前激活的程序上设置,它甚至可能没有这些统一值。

简单地改变这些调用的顺序可能已经解决了这个问题:

lightShader->use(true);
gBuffer->bindForReading(lightShader->programID());

另外,您使用GL_RGB16F作为两个缓冲区的格式。你使用的OpenGL实现可能支持这一点,但这不是规范中要求的可颜色渲染的格式。如果你想让你的代码跨平台工作,你应该使用GL_RGBA16F,它保证是可颜色渲染的。

最新更新