1

我在读取屏幕外帧缓冲区渲染通道的深度缓冲区时遇到问题。使用 OpenGL 4.5 时,它按预期工作,但在 OpenGL ES 2.0(角度)上,我的glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, depthBuffer)通话出错。错误是 0x502,这是一个 GL_INVALID_OPERATION 错误代码。

一些更多的背景。我在一个 Qt 环境中工作,它有一个主要的渲染例程,现在我正在做一些离屏渲染。通常我们使用 opengl 桌面实现,但是在某些机器上,我们遇到了一些糟糕的 opengl 版本的问题。因此,我目前正在努力使整个设置更加健壮。我做的一件事是改用角度。所以我只是想让角度工作,这应该对应于使用 OpenGL ES 2.0。

那么这里的帧缓冲区创建:

glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glGenRenderbuffers(1, &cboId);
glBindRenderbuffer(GL_RENDERBUFFER, cboId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);    
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, cboId);    
glGenRenderbuffers(1, &dboId);
glBindRenderbuffer(GL_RENDERBUFFER, dboId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, dboId);

帧缓冲区是完整的并且没有抛出错误。上一段和下一段之间的代码也不会引发任何错误。

glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, colorData);
//No error up to this point
glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_FLOAT, depthData));
//This call throws 0x502 (GL_INVALID_OPERATION)

通常我使用GL_DEPTH_COMPONENT24,由于某种原因它不起作用。所以我GL_DEPTH_COMPONENT16改用了。也许这暗示了什么是错的。仅供参考,主帧缓冲区使用 24 位深度和 8 位模板。(我也尝试使用该GL_DEPTH24_STENCIL8格式,但 glReadPixels 调用没有成功)。

使用纹理代替或 pbuffer 不起作用,因为此解决方法 ( glGetTexImage(...), glMapBuffer(...)) 所需的功能未在我坚持使用的 GL 版本中实现。

4

2 回答 2

1

根据Khronos 规范

format 指定像素数据的格式。接受以下符号值:GL_ALPHA、GL_RGB 和 GL_RGBA。

type 指定像素数据的数据类型。必须是 GL_UNSIGNED_BYTE、GL_UNSIGNED_SHORT_5_6_5、GL_UNSIGNED_SHORT_4_4_4_4 或 GL_UNSIGNED_SHORT_5_5_5_1 之一。

如果类型为 GL_UNSIGNED_SHORT_5_6_5 且格式不是 GL_RGB,则生成GL_INVALID_OPERATION 。

如果类型为 GL_UNSIGNED_SHORT_4_4_4_4 或 GL_UNSIGNED_SHORT_5_5_5_1 且格式不是 GL_RGBA,则生成GL_INVALID_OPERATION 。

如果格式和类型分别不是 GL_RGBA 和 GL_UNSIGNED_BYTE,也不是通过查询 GL_IMPLEMENTATION_COLOR_READ_FORMAT 和 GL_IMPLEMENTATION_COLOR_READ_TYPE 返回的格式/类型对,则生成 GL_INVALID_OPERATION

format您的代码和代码都不type符合此要求。

于 2017-09-27T18:05:38.673 回答
0

正如@xeed 已经指出的那样,@Reaper 已经回答了问题的“为什么”部分。至于在OpenGL ES中获取深度信息的“如何”,经过网上大量搜索,以及与一些同行交谈,我只看到提出了两种方法:

  1. (仅限 ES 3+)将深度纹理附加到渲染场景的帧缓冲区。然后渲染“全屏”四边形,在该四边形的片段着色器中采样深度纹理,并将深度纹理值作为颜色输出值,例如在您的红色通道中。最后,在这个颜色信息上使用 glReadPixels 来获取深度值。请参阅:https ://stackoverflow.com/a/35041374/11295586

  2. 使用 gl_FragCoord.z 获取值。请参阅:https ://stackoverflow.com/a/6140714/11295586

我已经尝试了这两个选项,并且似乎都有效,尽管我仍然有第二个深度反转问题,虽然很容易修复(只需从 1.0f 中减去该值),但我正在尝试破译原因。此外,第二个选项的详细信息取决于您何时需要这些值,以及原始场景所需的颜色信息。例如,在我的情况下,我可以将 gl_FragCoord.z 作为我的 alpha 通道值,因为我实际上并没有显示我的渲染结果。但是,如果您确实需要原始渲染的 alpha 通道完好无损,那么可能有多个渲染目标,其中一个获得 gl_FragCoord.z 值,将是解决方案吗?

于 2020-08-12T20:54:02.473 回答