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 中绘制的。
所以,这意味着(至少根据我的经验,可能有更好的方法来解决这个问题),是你不能再在后台缓冲区中渲染,你必须在Qt
s 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 上计算?