Android OpenGL ES帧缓冲对象 - 将深度缓冲区渲染到纹理

15

我正在使用运行Froyo的Android设备,支持OpenGL ES 1.1和OpenGL ES 2.0。

我想将深度缓冲区渲染到纹理中。在看到其他平台(包括iPhone)的OpenGL、OpenGL ES示例之后,我尝试了多个FBO配置。

我似乎可以设置一个带有颜色纹理的FBO,但每次附加深度纹理时都会失败。

我的当前代码基于此示例,但是创建一个颜色纹理而不是将绘制和读取缓冲区设置为无。

是否有一个简单的示例,可以在Android上配置OpenGL ES FBO以将深度渲染到纹理中?或者是否有一份描述支持和不支持的文档?


感谢评论-我特别需要适用于ES 1.1的解决方案,如果可以在Android上找到并工作的话。我也想查看ES 2-我不确定将深度信息打包到颜色缓冲区的想法-您有可以让我更好地理解这个想法的参考资料吗?

关于代码-我的源码几乎与我上面发布的链接没有什么不同。Framebuffer的状态是不完整的。


感谢片段着色器的建议-我现在明白了。如果我无法得到另一个解决方案,我将看看它是否可行。我的理想情况是同时获取深度和颜色,如果可能的话,不想分别渲染颜色和深度。


1
由于无法直接评论Android对深度缓冲区附加的支持(因此无法提供实际答案),如果您愿意依赖ES2.0,那么一种解决方法是将深度信息打包进颜色缓冲区,然后在相关时刻进行解包。同类深度始终在0到1之间,因此固定点方案并不太麻烦。 - Tommy
你应该发布代码。当它失败时,它意味着什么?它生成了GL错误吗?帧缓冲状态是什么? - Dr. Snoopy
将深度打包到颜色缓冲区中,只需编写一个片段着色器,将片段的Z位置写入颜色通道即可。如果您使用Windows并想要一个示例,请下载RenderMonkey并尝试一下,我相信其中一个示例会这样做。 - Gareth Davidson
2个回答

17

好的,某种程度上回答了问题。我在 Android 2.2 上使用 OpenGL ES 2 让它正常运行:

    // Create a frame buffer
    glGenFramebuffers( 1, &(frame_buffer ) );

    // Generate a texture to hold the colour buffer
    glGenTextures(1, &(colour_texture) );
    glBindTexture(GL_TEXTURE_2D, colour_texture);
    // Width and height do not have to be a power of two
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
            pixelWidth, pixelHeight,
            0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    // Probably just paranoia
    glBindTexture(GL_TEXTURE_2D, 0);

    // Create a texture to hold the depth buffer
    glGenTextures(1, &(depth_texture) );
    glBindTexture(GL_TEXTURE_2D, depth_texture);

    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
            pixelWidth, pixelHeight,
            0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

    glBindTexture(GL_TEXTURE_2D, 0);        

    glBindFramebuffer(GL_FRAMEBUFFER, frame_buffer);

    // Associate the textures with the FBO.

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                    GL_TEXTURE_2D, colour_texture, 0);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
                    GL_TEXTURE_2D, depth_texture, 0);

    // Check FBO status.    
    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);

    if ( status == GL_FRAMEBUFFER_COMPLETE )
    {
        // Success
    }

非常简单,遵循OpenGL ES2手册并按正确顺序执行所有操作。

我尝试在OpenGL ES 1.1中这样做,添加了OES到必要的函数调用和常量后缀_OES,因为帧缓冲对象是一个扩展。任何尝试将深度纹理附加到帧缓冲区都会导致不完整的帧缓冲对象。

因此,目前我的结论是,在Android上,这无法使用OpenGL ES 1.1实现,但在ES 2.2上显然可以实现。

如果有人对ES 1.1有解决方案,那么看到它是很有趣的。


1
说到 ES 1.1,我发现有些例子使用渲染缓冲区来处理深度,而不是纹理。 - NebulaFox
1
请注意,在Lollipop+上,可能需要先创建一个GL上下文并将其设置为当前上下文,然后再执行任何离屏GL代码 - 否则所有的GL调用都会返回错误代码。在Lollipop之前,当应用程序代码被调用时,框架的内部上下文是活动的。(对于屏幕上的GL不是问题,因为在视图附加到显示器时,会为您创建一个上下文。)我仍在努力寻找一些简单的方法来创建该上下文... - ToolmakerSteve

0

在许多设备上,不支持将渲染输出到深度纹理。您需要为深度缓冲区附加一个渲染缓冲区。


1
谢谢 - 这很有用。你能提供一些代码或链接来说明“如何为深度缓冲区附加渲染缓冲区”吗?(如果没有这样的细节,这将更适合作为现有答案的评论,而不是单独的答案。) - ToolmakerSteve

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接