626

OpenGL stencil (Clip Entity)

Question:

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

<img alt="enter image description here" class="b-lazy" data-src="https://i.stack.imgur.com/1W0T8.png" data-original="https://i.stack.imgur.com/1W0T8.png" src="https://etrip.eimg.top/images/2019/05/07/timg.gif" />

Answer1:

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:

<blockquote>

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.

</blockquote>

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.

Recommend

  • OpenGL Stenciling, separating ref from value written?
  • “Frame not in module” when using glTexImage2D
  • The truth value of a Series is ambiguous in dataframe
  • WebGL VBO error in Firefox
  • Undefined reference to “function name from external library”
  • Mapbox how to set up the menu so that only the “visible” layers are in an “On” state
  • How to paste custom field values from the AR Invoice and AP Bill details directly into GL Transactio
  • Cant find the header when I linka .lib in visual studio 2012
  • Compiling GLUI library, VS2010 gives me a weird namespace error
  • Crash in program using OpenMP, x64 only
  • Document.body doesn't exist. Modernizr hyphens test needs it [closed]
  • FBO: render to texture, wrong texture mapping when drawing rendered texture
  • LibGDX: Android SpriteBatch not drawing
  • Trying to Graph a Simple Square in pyOpenGL
  • how to extract text from a html element by id and assign to a php variable?
  • How do encryption algorithms know if they have the right key
  • GLSL texture2D() always returns (0, 0, 0, 1)
  • GLUT compile errors with Code::Blocks
  • ggplot2: Plotting regression lines with different intercepts but with same slope
  • Reading comments from .proto files using a Protocol Buffers descriptor object
  • Retrieve List of Cells in Excel Where Column Equals Something
  • Recreate Apple Watch fitness tracker ‘progress’ bar - gradient on CAShapeLayer stroke
  • C++ String tokenisation from 3D .obj files
  • Determining the length of a read stream in node js
  • incomplete type 'struct' error in C
  • Receive mouse move even cursor is outside control
  • Request response issues in biztalk
  • Overlapping controls in Windows XP
  • Using a canvas object in a thread to do simple animations - Java
  • Problems compiling files using JOGL
  • How to do unit test for HttpContext.Current.Server.MapPath
  • C# - Serializing and deserializing static member
  • Opengl-es onTouchEvents problem or a draw problem? [closed]
  • Incrementing object id automatically JS constructor (static method and variable)
  • Symfony2: How to get request parameter
  • Timeout for blocking function call, i.e., how to stop waiting for user input after X seconds?
  • Do create extension work in single-user mode in postgres?
  • log4net write single file for each call to log.info
  • Getting error when using KSoap library to consume .NET web services
  • How does Linux kernel interrupt the application?