OpenGL 不会通过调用 glBindFramebuffer(GL_FRAMEBUFFER,0) 渲染到屏幕

Posted

技术标签:

【中文标题】OpenGL 不会通过调用 glBindFramebuffer(GL_FRAMEBUFFER,0) 渲染到屏幕【英文标题】:OpenGL does not render to screen by calling glBindFramebuffer(GL_FRAMEBUFFER,0) 【发布时间】:2017-02-25 12:14:24 【问题描述】:

通常,此代码会将纹理图像渲染到屏幕上。但是,如果我现在将命令 glBindFramebuffer(GL_FRAMEBUFFER,0) 添加到代码中,它将不会呈现任何内容。它以 glClearColor 的颜色渲染屏幕。我正在使用 QT,所以使用 QOpenGLWidget。

glViewport(0, 0, _width, _height);
glBindFramebuffer(GL_FRAMEBUFFER, 0);

glClearColor(0.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);

_program.bind();
glBindVertexArray(_vao);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureID);
glUniform1i(glGetUniformLocation(_program.programId(), "u_texture"), 1);

glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);

想可能会出错吗?

编辑:

/* final.fsh */

# version 330 core

uniform sampler2D u_texture;
in vec4 qt_TexCoord0;

out vec4 fragColor;

void main(void)

    fragColor = texture(u_texture, qt_TexCoord0.xy);

/* final.vsh */

# version 330 core

layout (location = 0) in vec3 a_position;

out vec4 qt_TexCoord0;

void main(void)

    gl_Position =  vec4(a_position, 1.0);

    const mat4 B = mat4(0.5,  0.0, 0.0, 0.0,
                            0.0,  0.5, 0.0, 0.0,
                            0.0,  0.0, 0.5, 0.0,
                            0.5,  0.5, 0.5, 1.0);

    qt_TexCoord0 = B * vec4(a_position, 1.0);

/* 将 VAO 加载到 GPU */

GLfloat max_ = 1.0;
GLfloat min_ = -1.0;
GLfloat vert[] = 
    max_,  max_, 0,
    max_, min_, 0,
    min_, max_, 0,

    max_,  min_, 0,
    min_, min_, 0,
    min_,  max_, 0,
;

glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);

GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);

glBufferData(GL_ARRAY_BUFFER, sizeof(vert), vert, GL_STATIC_DRAW);

glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*3, (GLvoid*)0);
glBindVertexArray(0);

【问题讨论】:

0 为目标调用glBindFramebuffer 将break any existing binding to GL_FRAMEBUFFER。鉴于这种情况,您为什么要调用它并不明显。目的是什么? 这个想法是将来对帧缓冲区进行一些额外的渲染调用。然后将结果传递给该代码以在屏幕上呈现结果。 glDrawBuffer(GL_BACK) 我猜应该可以解决问题 嗯,不知道这有什么帮助。这应该放在哪里?我没有绑定任何帧缓冲区。 【参考方案1】:

正如 G.M. 所说,根据the docs,glBindFramebuffer(GL_FRAMEBUFFER, 0)“破坏了帧缓冲区对象与目标的现有绑定”。在使用帧缓冲区进行一些离屏渲染后,您需要此调用。当您想最终渲染到屏幕上时,您必须通过调用glDrawBuffer(GL_BACK) 来渲染后台缓冲区

所以你的渲染循环可能看起来像

// Do some rendering stuff in n offscreen textures
glBindFramebuffer(GL_FRAMEBUFFER, the_buffer);
glDrawBuffers(n, buffers);
// Rendering calls

// Finally use the results for the final rendering 
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDrawBuffer(GL_BACK);
// Rendering calls

编辑: 看来您正在使用 QOpenGLWidget 作为您的 OpenGL 提供程序/窗口系统。 Qt 的人正在使用帧缓冲区来呈现他们的 UI,而您的 QOpenGLWidget 的结果内容是在 FBO 中绘制的。

所以,这意味着(至少根据我的经验,可能有更好的方法来解决这个问题),是你不能再在后台缓冲区中渲染,你必须在Qts framebuffer 中渲染。

执行此操作的一种方法(同样,它可能根本不是最好的方法,但它对我有用)是在渲染开始时保存绑定的帧缓冲区,并在此缓冲区中进行最终渲染.这导致

// First of all, save the already bound framebuffer
GLint qt_buffer;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &qt_buffer);

// Do some rendering stuff in n offscreen textures
glBindFramebuffer(GL_FRAMEBUFFER, your_buffer);
glDrawBuffers(n, buffers);
// Rendering calls

// Finally use the results for the final rendering 
if (glIsFramebuffer(qt_buffer))

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glDrawBuffer(GL_BACK);

else

    glBindFramebuffer(GL_FRAMEBUFFER, qt_buffer);
    glDrawBuffers(1, buffers);

// Rendering calls

【讨论】:

好的,为了测试,我把我的代码加倍了。并将 glBindFramebuffer 更改为成功创建的 FBO。与:GLuint 附件 [2] = GL_COLOR_ATTACHMENT0,GL_COLOR_ATTACHMENT1; glDrawBuffers(2, 附件);其余的就像你展示的那样,通过使用 glDrawBuffer 再次将 0 绑定到 Framebuffer。但什么都没有改变 等等,你用的是Qt的QOpenGLWidget吗? 是的,有区别吗? 哦,是的。那行得通^^我实际上使用GL_FRAMEBUFFER_BINDING 来获取FBO。但我在初始化 OpenGL 后调用它,它告诉我它是 0 ^^。但是是的,我不得不将它移到paintGL()。谢谢 很高兴它完成了这项工作:) 我可以建议您编辑您的问题以包括您使用QOpenGLWidget 的事实吗?它可能会帮助其他人:)【参考方案2】:

我有同样的问题,最后我发现原因是glBindFramebuffer(GL_FRAMEBUFFER, 0); QOpenGLWidget的默认framebuffer可能不是0,需要通过调用QOpenGLContext::defaultFramebufferObject()来获取

所以改成这样:

glViewport(0, 0, _width, _height);
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject()); //<-- change here

glClearColor(0.0,0.0,0.0,1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);

_program.bind();
glBindVertexArray(_vao);

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, textureID);
glUniform1i(glGetUniformLocation(_program.programId(), "u_texture"), 1);

glDrawArrays(GL_TRIANGLES, 0, 6);
glBindVertexArray(0);

【讨论】:

以上是关于OpenGL 不会通过调用 glBindFramebuffer(GL_FRAMEBUFFER,0) 渲染到屏幕的主要内容,如果未能解决你的问题,请参考以下文章

在 openGL 中,模型坐标应该在我的 CPU 上还是通过 OpenGL 调用在 GPU 上计算?

如果在加载场景时移动鼠标光标不会消失 - OpenGL 和 GLFW

如果当前处于活动状态,则 OpenGL 纹理不会渲染

OpenGL几何着色器三角形不会没有错误地绘制

调用 glDrawElements 时的段错误

为啥这个在opengl中绘制三角形的着色器不会多次运行