问题描述
我正在使用 MRT 来解决 OpenGL 4.5 中的 3D 拾取问题。 (参考链接:http://ogldev.atspace.co.uk/www/tutorial29/tutorial29.html)
根据我在网上找到的信息,我们在使用MRT时一般会申请一个新的FBO。如果是这样,我应该在3D采摘时对场景进行两次daw(3D采摘的新FBO,以及屏幕的默认FBO),这会浪费时间。
所以我想知道是否可以在默认 FBO 中使用 MRT,但我遇到了一些问题。
这是我的代码。
// apply the texture buffer attached to GL_COLOR_ATTACHMENT1. (GL_COLOR_ATTACHMENT0 is reserved for the screen ?)
glEnable(GL_TEXTURE_2D);
glGenTextures(1,&m_pickingColorTexture);
glBindTexture(GL_TEXTURE_2D,m_pickingColorTexture);
glTexImage2D(GL_TEXTURE_2D,GL_RGB32F,w,h,GL_RGB,GL_FLOAT,nullptr);
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT1,GL_TEXTURE_2D,m_pickingColorTexture,0);
gldisable(GL_TEXTURE_2D);
// draw code.
GLenum buffers[] = { GL_COLOR_ATTACHMENT0,GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2,buffers);
glDrawElements(........);
// fragment shader,output two kinds of things: frag_color0 for screen display,frag_color1 for 3D picking
.......
layout (location = 0) out vec4 frag_color0;
layout (location = 1) out vec4 frag_color1;
void main() {
frag_color0 = vec4(...);
frag_color1 = vec4(...);
}
// query the result
glreadBuffer(GL_COLOR_ATTACHMENT1);
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glreadPixels(x,y,1,&pixelInfo);
当我最后查询 GL_COLOR_ATTACHMENT1 时,结果似乎是 frag_color0 而不是 frag_color1。
如果有人能帮我解决问题,我将不胜感激,谢谢!
解决方法
当我最后查询 GL_COLOR_ATTACHMENT1
时,结果似乎是 frag_color0
而不是 frag_color1
。
不,它不是,唯一的原因是FBO 0 没有GL_COLOR_ATTACHMENT1
,因此您无法查询它。 FBO 0 指的是窗口系统提供的帧缓冲区(通过 windows 上的 pixelformat、X11/Unix 上的 visual 或 fbconfig 以及其他特定于平台的方式指定)。
这个帧缓冲区可能有也可能没有深度缓冲区,可能有也可能没有模板缓冲区,可能有也可能没有(旧的,弃用的)累积缓冲区,可能有以下颜色缓冲区 :
GL_BACK_LEFT
GL_BACK_RIGHT
GL_FRONT_LEFT
GL_FRONT_RIGHT
这是您所能获得的最大数量,而且前提是您的 GPU 和驱动程序支持用于 3D 立体渲染的“四缓冲立体”模式。在典型情况下,您只有两个:
-
GL_BACK
:绘制新帧的缓冲区 -
GL_FRONT
:当前显示在屏幕上的缓冲区。
您不能从 GL 内部更改任何这些缓冲区配置(您只能在设置将 GL 上下文连接到的窗口时影响这一点),并且无法将 GL 对象(纹理、渲染缓冲区)与默认帧缓冲区
glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT1,GL_TEXTURE_2D,m_pickingColorTexture,0);
如果在绑定 FBO 0 时调用此方法,只会导致 GL 错误,否则会被忽略。这些情况也是如此:
GLenum buffers[] = { GL_COLOR_ATTACHMENT0,GL_COLOR_ATTACHMENT1 };
glDrawBuffers(2,buffers);
[...]
glReadBuffer(GL_COLOR_ATTACHMENT1);
因此,您要渲染的是 glDrawBuffer 的默认值,在典型情况下为 GL_BACK
,您的第二个着色器输出最终无处可去,而您正在回读的是 {{ 1}} 是默认值,在典型情况下也是 glReadBuffer
。
根据我在网上查到的信息,我们在使用捷运时一般都会申请一个新的FBO。
您在网上找到的信息是正确的。对于 OpenGL 中的 MRT,您需要设置自定义 FBO,并且不能与来自 FBO 0 的缓冲区共享它。(从技术上讲,这并非严格正确,您仍然可以使用诸如 { {1}} 或者如果您有一个支持立体声的 GPU,您甚至可能(误)使用 GL_BACK
。但这些的实际用例非常有限)。
如果是这样,我应该在3D采摘过程中绘制两次场景(3D采摘的新FBO,屏幕的默认FBO),这会浪费时间。
不一定是这样。您仍然可以使用 MRT 将其渲染到一些自定义 FBO 中,然后仅 blit 一种颜色附件到 FBO 0 的 {GL_FRONT,GL_BACK}
缓冲区。