在OpenGL ES中为framebuffer使用深度和模板渲染缓冲附件

时间:2015-03-11 20:30:39

标签: android opengl-es opengl-es-2.0

我想在OpenGL ES 2中创建一个带有颜色纹理和深度以及模板渲染缓冲区的帧缓冲区。但是,OpenGL ES似乎没有GL_DEPTH24_STENCIL8GL_DEPTH_STENCIL_ATTACHMENT。使用两个单独的渲染缓冲区会出现错误“Stencil and z buffer surfaces have different formats! Returning GL_FRAMEBUFFER_UNSUPPORTED!” 这在OpenGL ES中是不可能的吗?

我的FBO创建代码:

private int width, height;

private int framebufferID,
            colorTextureID,
            depthRenderBufferID,
            stencilRenderBufferID;

public FBO(int w, int h) {
    width = w;
    height = h;
    int[] array = new int[1];

    //Create the FrameBuffer and bind it
    glGenFramebuffers(1, array, 0);
    framebufferID = array[0];
    glBindFramebuffer(GL_FRAMEBUFFER, framebufferID);

    //Create the texture for color, so it can be rendered to the screen
    glGenTextures(1, array, 0);
    colorTextureID = array[0];
    glBindTexture(GL_TEXTURE_2D, colorTextureID);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (java.nio.ByteBuffer) 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_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    // attach the texture to the framebuffer
    glFramebufferTexture2D( GL_FRAMEBUFFER,       // must be GL_FRAMEBUFFER
                            GL_COLOR_ATTACHMENT0, // color attachment point
                            GL_TEXTURE_2D,        // texture type
                            colorTextureID,       // texture ID
                            0);                   // mipmap level
    glBindTexture(GL_TEXTURE_2D, 0);

    // is the color texture okay? hang in there buddy
    FBOUtils.checkCompleteness(framebufferID);

    //Create the depth RenderBuffer
    glGenRenderbuffers(1, array, 0);
    depthRenderBufferID = array[0];
    glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBufferID);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height);

    //Create stencil RenderBuffer
    glGenRenderbuffers(1, array, 0);
    stencilRenderBufferID = array[0];
    glBindRenderbuffer(GL_RENDERBUFFER, stencilRenderBufferID);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_STENCIL_INDEX8, width, height);

    // bind renderbuffers to framebuffer object
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRenderBufferID);
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, stencilRenderBufferID);

    // make sure nothing screwy happened
    FBOUtils.checkCompleteness(framebufferID);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
}

2 个答案:

答案 0 :(得分:2)

打包深度/模板表面不是OpenGL ES 2.0的标准部分,但是通过此扩展添加:

https://www.khronos.org/registry/gles/extensions/OES/OES_packed_depth_stencil.txt

如果您的平台支持扩展(通常是),则OpenGL中的令牌名称通常会起作用,但请注意,大多数都有_OES后缀,因为它是OES扩展名,例如内部格式标记为GL_DEPTH24_STENCIL8_OES

扩展程序未定义单个组合附着点,例如GL_DEPTH_STENCIL_ATTACHMENT(在OpenGL ES 3.0中添加),但您可以将相同的渲染缓冲区附加到一个或两个单个附着点。请注意,如果您将填充的深度/模板表面连接到另一个(即,如果您将填充的深度/模板附加到一个连接点,则不允许将两个不同的深度或模板表面附加到深度和模板连接点)其他可以连接到相同的包装表面或未使用)。

答案 1 :(得分:2)

简而言之,这取决于实现。您在发布的代码中尝试使用单独的渲染缓冲区进行深度和模板在ES 2.0中基本合法。但是在规范中有这一段:

  

[..]某些实现可能不支持呈现内部格式的特定组合。如果实现不支持附加到帧缓冲对象的图像格式组合,则在标记为FRAMEBUFFER_UNSUPPORTED的子句下帧缓冲不完整。

这正是您所看到的GL_FRAMEBUFFER_UNSUPPORTED错误。您的实现显然不喜欢深度和模板缓冲区的组合,并且可以自由地拒绝支持它,同时仍然符合规范。

还有一个方面会使您的代码设备依赖。您为纹理使用的格式和类型的组合:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0,
             GL_RGBA, GL_UNSIGNED_BYTE, (java.nio.ByteBuffer) null);

基本上对应于RGBA8内部格式(即使ES 2.0规范中未使用该命名)。在基本ES 2.0中,这不是可颜色渲染的格式。如果您需要全面支持的内容,则必须使用GL_UNSIGNED_SHORT_5_6_5GL_UNSIGNED_SHORT_4_4_4_4GL_UNSIGNED_SHORT_5_5_5_1作为类型。好吧,从理论上讲,设备可以拒绝支持几乎任何格式。唯一严格的要求是它至少支持一种格式组合。

OES_rgb8_rgba8扩展程序中,许多设备都可以使用RGBA8格式进行渲染。

正如另一个答案中已经指出的,组合深度/模板格式不是基本ES 2.0的一部分,只有OES_packed_depth_stencil扩展名才可用。