使用帧缓冲区对象作为纹理的视觉问题

Posted

技术标签:

【中文标题】使用帧缓冲区对象作为纹理的视觉问题【英文标题】:Visual issue using Frambuffer Object as texture 【发布时间】:2015-03-22 13:20:19 【问题描述】:

我的 OpenGL 引擎将给定的场景绘制到帧缓冲区对象中,然后将其颜色附件用作纹理。然后将其放在视口中的一个正方形上。

问题是我看到了一个奇怪的视觉伪影:

广场是用

建造的
glm::vec2 square[4];
square[0] = glm::vec2(0.f, 0.f);
square[1] = glm::vec2(engWidth, 0.f);
square[2] = glm::vec2(0.f, engHeight);
square[3] = glm::vec2(engWidth, engHeight);
glm::vec2 texcoords[4];
texcoords[0] = glm::vec2(0.f, 0.f);
texcoords[1] = glm::vec2(1.f, 0.f);
texcoords[2] = glm::vec2(0.f, 1.f);
texcoords[3] = glm::vec2(1.f, 1.f);

glGenBuffers(2, Buffer2D);
glBindBuffer(GL_ARRAY_BUFFER, Buffer2D[0]);
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(glm::vec2), square, GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, Buffer2D[1]);
glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(glm::vec2), texcoords, GL_STATIC_DRAW);

orthographicProj = glm::ortho(0.f, (float)engWidth, 0.f, (float)engHeight, -1.f, 1.f);

engWidth 和 engHeight 是实际的窗口大小。

然后用帧渲染

shaderProgram->setMatrix("Clip", orthographicProj);

glBindBuffer(GL_ARRAY_BUFFER, Buffer2D[0]);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(0);

glBindBuffer(GL_ARRAY_BUFFER, Buffer2D[1]);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr);
glEnableVertexAttribArray(1);

glDisableVertexAttribArray(2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

最后阶段的顶点和片段着色器很简单

const char *frontVertexShader = R"(
    #version 440 core

    uniform mat4 Clip;

    layout(location = 0) in vec2 Position;
    layout(location = 1) in vec2 TexCoord;

    out vec2 Tex_Coord;

    void main() 
        gl_Position = Clip * vec4(Position, 0.0, 1.0);
        Tex_Coord = TexCoord;
    
)";

const char *frontFragmentShader = R"(
    #version 440 core

    in vec2 Tex_Coord;  
    uniform sampler2D sampler;

    out vec4 Fragment;

    void main() 
        Fragment = texture(sampler, Tex_Coord);
    
)";

我尝试使用三角形而不是三角形条,但结果相同。

有什么想法吗?如果需要,我可以发布更多代码。

【问题讨论】:

只是好奇为什么你有一个剪辑矩阵。它是干什么用的?如果你传入的几何被归一化为 -1 到 1,你只需通过它,纹理坐标为 * 0.5 并将 0.5 添加到顶点位置即可。 首先,您是否验证了您的纹理内容是完全正确的,即工件不在纹理中?除此之外:确保您的片段没有被丢弃(深度测试、模板测试等)。 其实我没有,但它应该是因为在 FBO 中的渲染与在后台缓冲区中的渲染方式相同。无论如何,我会将内容保存到图像中以进行检查。 【参考方案1】:

我不知道这是否会有所帮助,但值得这样做的是我为全屏四边形所做的:

(请注意顶点没有纹理分量 - 它只是 -1 到 1)。

v[0].x = -1.f; v[0].y = -1.f; v[0].z = 0.f;
v[1].x = -1.f; v[1].y =  1.f; v[1].z = 0.f;
v[2].x =  1.f; v[2].y = -1.f; v[2].z = 0.f;
v[3].x =  1.f; v[3].y =  1.f; v[3].z = 0.f;

顶点着色器很简单:

void main()

    attrib_Fragment_Texture = attrib_Position.xy * 0.5 + 0.5; 

    gl_Position = vec4(attrib_Position.xy, 0.0, 1.0);

使用以下像素着色器:

void main(void)

    Out_Colour = texture2D(Map_Diffuse, attrib_Fragment_Texture);

您不需要正交投影矩阵。

【讨论】:

我没有意识到我可以避免使用正交矩阵。我使用了这段代码,现在看起来更干净了。但是,问题仍然存在。 嗯,好的。它看起来确实很奇怪。起初我以为这可能是采样问题,但边缘太粗糙了。 您甚至不需要在 GLSL 4.40 着色器中使用顶点属性来执行此操作。只需使用const vec4 pos [4] = vec4 [] (vec4 (-1.0, -1.0, 0.0, 1.0), vec4 (-1.0, 1.0, 0.0, 1.0), vec4 (1.0, -1.0, 0.0, 1.0), vec4 (1.0, 1.0, 0.0, 1.0)); gl_Position = pos [gl_VertexID]; attrib_Fragment_Texture = pos [gl_VertexID].xy * 0.5 + 0.5; 不需要分配或绑定顶点缓冲区,它应该会更快一些。 哈哈不错。谢谢你的安东。【参考方案2】:

找到了!我忘记在后台缓冲区上调用 glClear 并且由于奇怪的原因只有一些像素出现了问题。

【讨论】:

以上是关于使用帧缓冲区对象作为纹理的视觉问题的主要内容,如果未能解决你的问题,请参考以下文章

使用帧缓冲区将深度缓冲区渲染到纹理中

使用帧缓冲区(纹理空白)向纹理发出绘图

通过帧缓冲区对象渲染到纹理

如何在多采样纹理上渲染帧缓冲区对象?

从帧缓冲区对象读取时,OpenGL 纹理坐标是相反的

纹理和渲染缓冲区是不是在帧缓冲区对象上共享相同的空间?