我正在尝试使用 Sprite 作为剪辑实体。这意味着我希望剪切所有子实体,以便只有与剪切实体(父实体)重叠的子实体部分可见。
我正在尝试使用 OpenGL 模板函数来做到这一点。在我的模拟器上我可以正常工作,但在我的 Android 手机上却不能。我做错了什么?
GLES20.glEnable(GLES20.GL_STENCIL_TEST);
GLES20.glClearStencil(0);
GLES20.glStencilMask(1);
GLES20.glClear(GLES20.GL_STENCIL_BUFFER_BIT);
// pre draw
GLES20.glStencilFunc(GLES20.GL_NEVER, 1, 1);
GLES20.glStencilOp(GLES20.GL_REPLACE, GLES20.GL_KEEP, GLES20.GL_KEEP);
// draw clip-entity (this) (sprite)
this.draw();
// post draw
GLES20.glStencilFunc(GLES20.GL_LESS, 2, 1);
GLES20.glStencilOp(GLES20.GL_KEEP, GLES20.GL_KEEP, GLES20.GL_KEEP);
// draw children of clip-entity (this) which should now be clipped
this.drawChildren();
GLES20.glDisable(GLES20.GL_STENCIL_TEST);
最佳答案
针对您所描述的内容使用模板缓冲区听起来是一个不错的方法。
您需要确保请求带有模板缓冲区的帧缓冲区配置。在 Android 上使用 GLSurfaceView 时,这是通过重载的 setEGLConfigChooser() 方法之一来完成的。最简单的形式是需要一点红色、绿色、蓝色、Alpha、深度和模板深度的形式。如果您还需要深度缓冲区,您可以尝试这样的组合来获取带有模板的配置:
setEGLConfigChooser(8, 8, 8, 8, 24, 8);
setEGLConfigChooser(8, 8, 8, 8, 16, 8);
setEGLConfigChooser(8, 8, 8, 0, 24, 8);
setEGLConfigChooser(8, 8, 8, 0, 16, 8);
setEGLConfigChooser(5, 6, 5, 0, 24, 8);
setEGLConfigChooser(5, 6, 5, 0, 16, 8);
为了更彻底,您还可以使用 setEGLConfigChooser()
重写来注册您自己的 EGLConfigChooser
实现。使用它,您可以枚举配置,并实现您自己的逻辑以选择最能满足您的需求的配置。
要验证您确实有模板缓冲区,您可以使用:
GLint stencilBits = 0;
glGetIntegerv(GL_STENCIL_BITS, &stencilBits);
我认为模板支持是标准的,但根据我阅读 ES 2.0 规范的方式,它不是必需的:
Further, an implementation or context may not provide depth or stencil buffers. However, an OpenGL ES implementation must support at least one config with a depth bit depth.
我相信至少最近的 GPU 支持模板。如果在尝试了上述所有方法后,您必须在确实不提供模板的 GPU 上实现此操作,事情就会变得更加困难。对于您绘制的示例,您可以通过矩形进行剪切,这当然可以简单地通过使用剪刀矩形来完成。但我确信您只是用它来说明。
根据您在实际渲染中使用深度缓冲区的程度,您可以使用深度缓冲区来玩一些技巧。例如,它可能如下所示:
glClearDepthf(0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_DEPTH_TEST);
// draw clip entity
glEnable(GL_DEPTH_TEST);
// draw children
这样做的缺点是您需要禁用部分绘图的深度测试,如果该绘图需要深度测试才能正确渲染,这可能是完全 Not Acceptable 。
关于java - OpenGL 模板(剪辑实体),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24540373/