在 OpenGL ES 中为帧缓冲区使用深度和模板渲染缓冲区附件
Posted
技术标签:
【中文标题】在 OpenGL ES 中为帧缓冲区使用深度和模板渲染缓冲区附件【英文标题】:Using a depth and stencil renderbuffer attachment for framebuffer in OpenGL ES 【发布时间】:2015-03-11 20:30:38 【问题描述】:我想在 OpenGL ES 2 中创建一个带有颜色纹理和深度以及模板渲染缓冲区的帧缓冲区。但是,OpenGL ES 似乎没有GL_DEPTH24_STENCIL8
或GL_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);
【问题讨论】:
【参考方案1】:打包深度/模板表面不是 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 中添加),但您可以将相同的渲染缓冲区附加到一个或两个单个附加点。请注意,如果您已将打包深度/模板表面连接到另一个(即,如果您将打包深度/模板连接到一个连接点,则不允许将两个不同深度或模板表面连接到深度和模板连接点)其他可以连接到相同的包装表面或未使用)。
【讨论】:
【参考方案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_5
、GL_UNSIGNED_SHORT_4_4_4_4
或 GL_UNSIGNED_SHORT_5_5_5_1
作为类型。好吧,理论上设备可以拒绝支持几乎任何格式。唯一的严格要求是它至少支持一种格式组合。
作为OES_rgb8_rgba8 扩展的一部分,许多设备都可以渲染为RGBA8
格式。
正如在另一个答案中已经指出的那样,组合的深度/模板格式不是基本 ES 2.0 的一部分,并且仅适用于 OES_packed_depth_stencil 扩展。
【讨论】:
以上是关于在 OpenGL ES 中为帧缓冲区使用深度和模板渲染缓冲区附件的主要内容,如果未能解决你的问题,请参考以下文章
OpenGL如何在模板测试失败且深度测试成功时写入模板缓冲区?