检索纹理像素数据的最有效方法是什么?

时间:2016-02-23 23:45:16

标签: opengl opengl-es-2.0 opengl-es-3.0

我至少知道Directx for Dx9,有一个纹理对象,你只能获得一小部分纹理到CPU可访问的内存。我认为这是一个名为“LockRect”的功能。 OpenGL有glGetTexImage()但它抓取整个图像,如果格式与纹理不同,那么它必须在传输整个纹理之前将整个纹理转换为新的像素格式。此功能也不在OpenGL ES中。 Framebuffers是另一种选择,但我可以绑定一个帧缓冲区,其中颜色附件连接到纹理。然后有glReadPixels从帧缓冲区读取,所以应该从纹理中读取。 glReadPixels具有有限的像素格式选项,因此必须进行转换,但我可以读取我需要的像素(只有1个像素)。我没有使用过这种方法,但似乎有可能。如果任何人都可以确认帧缓冲方法,那它就是一种可行的替代方法。那么这种方法也适用于OpenGL ES 2 +。

还有其他方法吗?帧缓冲方法的效率如何(如果有效),是否最终必须在读取像素之前将整个纹理转换为所需的格式,还是完全实现定义?

编辑:@ Nicol_Bolas 请停止从标签中删除OpenGL并添加OpenGL-ES,OpenGL-ES不适用,OpenGL是。这是专门针对OpenGL的,但如果可能的话,我希望它与Open ES 2+兼容,尽管它不是必须的。如果只有OpenGL解决方案可用,那么如果值得权衡,我将考虑这个问题。谢谢。

1 个答案:

答案 0 :(得分:2)

请注意,我对ES没有那么多的经验,所以在这种情况下可能有更好的方法来做到这一点。然而,一般的要点适用于普通的OpenGL或ES。

首先,最重要的性能考虑因素应该是您在阅读时。如果您在渲染时从视频卡请求数据,则您的程序(CPU端)将不得不停止,直到视频卡返回数据,由于您无法发出进一步的渲染命令,这将减慢渲染速度。作为一般规则,您应该始终上传,渲染,下载 - 不要混合任何这些过程,它会极大地影响速度,以及驱动程序/硬件/操作系统依赖的程度。

我建议在渲染周期结束时使用glReadPixels( )。我怀疑该功能的格式限制与帧缓冲格式的限制有关;此外,你真的应该使用8位无符号或浮点both of which are supported。如果你有一些边缘情况不允许任何这些支持的格式,你应该解释它是什么,因为可能有一种方法来专门处理它。

如果在渲染中的某个特定点(而不是结束点)需要帧缓冲的内容,请创建第二个纹理+帧缓冲(再次使用相同的格式)作为有效的“后备缓冲区”,然后从目标复制framebuffer到那个纹理。这发生在视频卡上,因此它不会直接读取总线延迟。这是我写的这个操作:

glActiveTexture( GL_TEXTURE0 + unit );
glBindTexture( GL_TEXTURE_2D, backbufferTextureHandle );
glBindFramebuffer( GL_READ_FRAMEBUFFER, framebufferHandle );
glCopyTexSubImage2D(
        GL_TEXTURE_2D,
        0, // level
        0, 0, // offset
        0, 0, // x, y
        screenX, screenY );
glBindFramebuffer( GL_DRAW_FRAMEBUFFER, framebufferHandle );

然后,当您需要数据时,将后备缓冲区绑定到GL_READ_FRAMEBUFFER并在其上使用glReadPixels( )

最后,您应该记住,下载数据仍然会停止CPU端。如果在显示帧缓冲区之前下载,则会在您再次执行命令之前推迟显示图像,这可能会导致可见的延迟。因此,我建议仍然使用非默认帧缓冲,即使您只关心最终缓冲区状态,并结束渲染周期,效果如下:

(1。)Blit到默认的帧缓冲区:

glBindFramebuffer( GL_DRAW_FRAMEBUFFER, 0 ); // Default framebuffer
glBindFramebuffer( GL_READ_FRAMEBUFFER, framebufferHandle );
glBlitFramebuffer(
        0, 0, screenX, screenY,
        0, 0, screenX, screenY,
        GL_COLOR_BUFFER_BIT,
        GL_NEAREST );

(2。)在您给定的情况下调用您的swap buffers命令。

(3。)来自帧缓冲区的下载调用(无论是glReadPixels( )还是其他)。

至于blit / texcopy操作的速度影响,它在大多数现代硬件上相当不错,而且我发现它甚至没有发生10次以上的显着影响,但是如果你正在处理过时的硬件,可能值得再考虑一下。