DEPTH_COMPONENT上的glReadPixels抛出GL_INVALID_OPERATION

时间:2017-09-27 13:13:11

标签: qt opengl-es qt-quick depth-buffer google-angle

我在读取屏幕外帧缓冲区渲染过程的深度缓冲区时遇到问题。使用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版本中实现。

2 个答案:

答案 0 :(得分:1)

根据Khronos specification

  

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

     

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

     如果type为GL_UNSIGNED_SHORT_5_6_5且格式不是GL_RGB,则会生成

GL_INVALID_OPERATION

     如果type为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_INVALID_OPERATION ,也不会通过查询GL_IMPLEMENTATION_COLOR_READ_FORMAT和GL_IMPLEMENTATION_COLOR_READ_TYPE返回格式/类型对。

代码中的formattype都不符合此要求。

答案 1 :(得分: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值)将是解决方案?