OpenGL stencil (Clip Entity)

核能气质少年 提交于 2020-01-06 19:49:24

问题


I am trying to use a sprite as clip-entity. This means I want that all it's child entities are clipped so that only the parts of the children that overlap the clip-entity (parent) are visible.

I'm trying to do that using the OpenGL stencil function. On my emulator I got it working, but on my Android phone it doesn't. What am I doing wrong?

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);


回答1:


Using a stencil buffer for what you're describing sounds like a good approach.

You need to make sure that you request a framebuffer configuration with a stencil buffer. When using GLSurfaceView on Android, this is done with one of the overloaded setEGLConfigChooser() methods. The simplest form is the one that takes a bit depth for Red, Green, Blue, Alpha, Depth, and Stencil. If you also need a depth buffer, you can try combinations like these to get a config with stencil:

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);

To be even more thorough, you can also use the setEGLConfigChooser() override that lets you register your own EGLConfigChooser implementation. Using that, you can enumerate configuration, and implement your own logic to choose the one that best meets your need.

To verify that you indeed got a stencil buffer, you can use:

GLint stencilBits = 0;
glGetIntegerv(GL_STENCIL_BITS, &stencilBits);

I thought that stencil support was standard, but the way I read the ES 2.0 spec, it's not required:

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.

I believe at least relatively recent GPUs support stencil. If you have to get this working on a GPU that indeed does not provide stencil after you tried all of the above, things get more difficult. For the example you sketched, where you clip by a rectangle, that could of course simply be done by using a scissor rectangle. But I'm sure that you only used that for illustration.

Depending how much you use the depth buffer for your actual rendering, you could play some tricks with the depth buffer instead. For example, it could look like this:

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

The downside of this is that you need to disable depth testing for part of your drawing, which might be completely unacceptable if that drawing needs depth testing to render properly.



来源:https://stackoverflow.com/questions/24540373/opengl-stencil-clip-entity

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!