无法从 OpenGL 中的着色器访问先前渲染的纹理

Posted

技术标签:

【中文标题】无法从 OpenGL 中的着色器访问先前渲染的纹理【英文标题】:Cannot access previously rendered texture from shader in OpenGL 【发布时间】:2011-08-23 22:55:33 【问题描述】:

我有一个 OpenGL 程序,我在其中做一些增强现实工作。它分 2 次运行。

首先,它使用标准的 OpenGL 调用来渲染帧。接下来,它使用着色器将来自相机的帧与渲染帧进行比较。

在第一遍中,我渲染到绑定到我的帧缓冲区对象的纹理,并将相机帧上传到绑定到该对象的其他纹理。

在我的第二遍中,我的着色器可以毫无问题地访问上传的纹理(即相机帧),但是它无法访问第一遍渲染的纹理

如果我制作一个调试着色器,只是将顶点颜色设置为该点的纹理颜色,那么当我使用从相机上传的纹理时,我会看到:

但是,如果我将着色器更改为使用在第一遍中渲染的纹理,我会看到:

我将尝试在下面提供足够的背景来说明这一点,但非常感谢任何帮助!


背景

我知道它在第一遍中就可以正确渲染,因为我有一个调试窗口显示渲染结果,此外我正在使用 Apple 的 OpenGL Profiler,并且可以看到所有纹理。

我基本上是像这个网站一样对纹理进行渲染

http://www.songho.ca/opengl/gl_fbo.html#example

不同之处在于我从不切换帧缓冲区对象。也就是说,我从不打电话

// switch back to window-system-provided framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);

在进行初始渲染以及使用着色器比较它们时是否需要使用不同的 FBO?


我对可能发生的事情的另一个提示是,如果在 OpenGL 分析器中查看我的状态,它只会声称 GL_TEXTURE0 和 GL_TEXTURE4 已从其默认状态更改。这些都是我明确将像素数据加载到其中的纹理。其他 3 个纹理在我的第一遍中被渲染。


相关代码

// First I create the textures
glGenTextures(1, &renderTexture);
glGenTextures(1, &cameraTexture);
glGenTextures(1, &correlationTexture);

gllActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, cameraTexture);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img->width, img->height, 0,GL_BGR, GL_UNSIGNED_BYTE, img->imageData); 

glActiveTexture(GL_TEXTURE0+1);
glBindTexture(GL_TEXTURE_2D, renderTexture);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderTexture, 0);

glActiveTexture(GL_TEXTURE0+2);
glBindTexture(GL_TEXTURE_2D, correlationTexture);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width, size.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, correlationTexture, 0);

// Now I render to the renderTexture. This works fine, I can verify
// it using glReadPixels.

// However, later on when I'm ready to do the shader, I do this
// First I switch the bound texture
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,      GL_TEXTURE_2D,correlationTexture, 0); // (this has been set up earlier)
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(theProgram);
glUniform1i(renderTexLoc, 1); // This should tell it to look at the rendered texture from earlier, it does not.

【问题讨论】:

【参考方案1】:

啊,看来我解决了。因此,在使用着色器渲染之前,我必须绑定第一次渲染的纹理:

  glActiveTexture(GL_TEXTURE0+1);
  glBindTexture(GL_TEXTURE_2D,renderTexture);

我想我对绑定纹理与活动纹理之间的确切区别仍然有点模糊,但现在这可行。

【讨论】:

glActiveTexture() 告诉驱动程序分配 GPU 的哪个纹理单元来处理纹理。随后的 glBindTexture() 将导致纹理由该纹理单元处理。这在混合纹理或使用着色器程序时变得很重要。所以 glActiveTexture 指的是 GPU 上的一些硬件,而 glBindTexture 指的是你上传到驱动程序的纹理。 感谢 karx11erz,这是一个简洁的解释。【参考方案2】:

您不能同时读取和写入同一个图像。这样做会导致未定义的行为。

您可以写入同一纹理中的不同图像(不同的 mipmap 或数组/立方体/3D 纹理的层)。但是您不能在纹理中写入和读取同一图像。

我猜您在尝试进行第二次渲染之前调用了glClear(GL_COLOR_BUFFER_BIT),这覆盖了您希望从中读取的纹理。

一般来说,如果纹理附加到 FBO,它应该绑定到上下文。反之亦然。也许你应该在两个纹理之间打乒乓球。一个是当前目的地,另一个是之前的目的地。完成第二遍后,您切换。这是一种很常见的技术。

【讨论】:

我实际上确实切换了颜色缓冲区附件,我只是没有包含相应的代码。我已经修改了问题以包含它。所以当着色器运行时,之前渲染的纹理不再绑定到上下文。

以上是关于无法从 OpenGL 中的着色器访问先前渲染的纹理的主要内容,如果未能解决你的问题,请参考以下文章

使用现代 OpenGL 渲染纹理

OpenGL:如何将多个纹理传递给具有一个变量的着色器?

纹理中的 OpenGL 片段着色器

OpenGL着色器没有传递正确的纹理坐标

一个支持纹理渲染和逐顶点颜色的着色器,还是两个专用着色器?

OpenGL中的多个渲染目标与Cg