问题
我从事开源游戏 torcs 的工作(http://torcs.sourceforge.net/)。
游戏的图形管线仍然使用OpenGL 1.3的固定功能管线(FFP)。
我尝试将游戏场景渲染到 FBO(帧缓冲区对象)中的纹理,以便对渲染的纹理进行一些后处理。我使用 OpenGL 3.3。在我的机器上。
目前我已经在以下位置设置了带有附加纹理的 FBO:GL_COLOR_ATTACHMENT0&1
(2是为了在着色器中具有两个连续的帧可读)和一个附加的渲染缓冲区GL_DEPTH_ATTACHMENT
.
绑定FBO后,执行游戏渲染函数。当我随后解除 FBO 的绑定并通过着色器程序将纹理写回到窗口缓冲区进行验证时,场景不完整。更具体地说,只渲染了汽车的轮廓,还有轮胎的擦痕和一些烟雾。这表明有些东西被渲染到 FBO 的纹理,但不是所有东西。其中,没有纹理(树木、房屋、草地等)被渲染到 FBO 中的纹理。这表明我的纹理设置不正确,但不幸的是我对OpenGL的了解有限,这就是为什么我希望得到你的帮助。
另一件值得注意的事情是,如果我省略该行glActiveTexture(GL_TEXTURE0);
在绘制发生之前,将显示一个纹理(即,将被写入 FBO 并写回窗口系统帧缓冲区,而不是汽车轮廓。
The Code
下面的代码展示了FBO的初始化 (from https://en.wikibooks.org/wiki/OpenGL_Programming/Post-Processing):
int screen_width = 640;
int screen_height = 480;
/* Texture A*/
glGenTextures(1, &fbo_texture);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
/* Texture B*/
//glActiveTexture(GL_TEXTURE1);
glGenTextures(1, &fbo_texture_a);
glBindTexture(GL_TEXTURE_2D, fbo_texture_a);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screen_width, screen_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_2D, 0);
/* Depth buffer */
glGenRenderbuffers(1, &rbo_depth);
glBindRenderbuffer(GL_RENDERBUFFER, rbo_depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, screen_width, screen_height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
/* Framebuffer to link everything together */
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fbo_texture, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT1, GL_TEXTURE_2D, fbo_texture_a, 0);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rbo_depth);
GLenum status;
if ((status = glCheckFramebufferStatus(GL_FRAMEBUFFER)) != GL_FRAMEBUFFER_COMPLETE) {
fprintf(stderr, "glCheckFramebufferStatus: error 0x%x", status);
return 0;
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
/* Compile and link shaders */
...
以下代码显示了绘图发生的位置:
Edit: if use_fbo=false
那么所有内容都会像以前一样直接渲染到屏幕上。我所做的唯一更改在括号内。
if (use_fbo)
{
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0,0,grWinw, grWinh);
if (fbo_a) // drawing to fbo_texture_a
{
glDrawBuffer(GL_COLOR_ATTACHMENT1);
glActiveTexture(GL_TEXTURE0+11);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, fbo_texture_a);
}
else
{
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glActiveTexture(GL_TEXTURE0+12);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, fbo_texture);
}
glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
}
glClearColor(0.7f, 0.1f, 0.1f, 1.0f); //clear with red to see what is drawn to the fbo
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
grScreens[0]->update(s, grFps);//THIS IS WHERE THE DRAWING HAPPENS unchanged from original drawing in TORCS
if (use_fbo)
{
glPopAttrib();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_TEXTURE_2D);
glDrawBuffer(GL_BACK);
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glUseProgram(program_postproc);
if (fbo_a) // drawn to fbo_texture_a
{
glUniform1i(uniform_fbo_texture, 11);
glUniform1i(uniform_fbo_texture_a, 12);
fbo_a=!fbo_a;
}
else
{
glUniform1i(uniform_fbo_texture, 12);
glUniform1i(uniform_fbo_texture_a, 11);
fbo_a=!fbo_a;
}
glEnableVertexAttribArray(attribute_v_coord_postproc);
glBindBuffer(GL_ARRAY_BUFFER, vbo_fbo_vertices);
glVertexAttribPointer(
attribute_v_coord_postproc, 2, GL_FLOAT, GL_FALSE, 0, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableVertexAttribArray(attribute_v_coord_postproc);
glUseProgram(0);
}
我希望我为您提供了足够的信息来帮助我解决这个问题。任何建议表示赞赏。
EDIT:我再次检查了我的着色器代码和 FBO 实现(使用简化的绘图将其简化为仅一种颜色附件等),并且一切正常。我认为问题在于用于绘图的固定功能管道和我对 FBO 的实现的混合......
EDIT:以下两张图片展示了 use_fbo=true 与 false 时发生的情况:
(注:红色是FBO绑定后的清晰颜色,看看渲染到FBO上的是什么:除了阴影和防滑痕迹之外什么都没有)
我还尝试可视化深度缓冲区(将实现更改为深度纹理附件),即使我线性化,也没有任何信息。我想深度也没有正确写入 FBO。