Read/write Stencil buffer and pass to glsl filter

I am currently working on a stencil buffer to hold shape references 1,2,3…

The idea is to draw a shape like a rect or circle with drawer.isolatedWithRenderTarget(rt) and draw the shapes at different z-values (maybe ?) of 1 or 2 each.
On draw, the stencil buffer gets updated to now hold the unsigned integer reference of that shape.

This would be the uniform input to a glsl filter, something like uniform sampler2D stencil;.
There, I want to update each pixel based on that stencil value.

I have only found depthBuffer(format = DepthFormat.STENCIL8)so far, but most access functions are private and this seems to be “walled off” from me.

Any ideas on how to realize such a stencil buffer with write access ? :thinking:

Kind regards,
Lukas

This sketch illustrates what i try to achieve:

Start with cleared buffer (0 everywhere), draw shape 1 on top, draw shape 2 on top.

I found a decent workaround, which I’d like to share:

I set up a new renderTarget with a single specific colorBuffer holding an 8-bit uint per pixel:

val stencilTarget = renderTarget(width, height) {
    colorBuffer(format = ColorFormat.R, type = ColorType.UINT8)
}
val stencilBuffer = stencilTarget.colorBuffer(0)

On that stencilTarget I draw like on any other renderTarget, … but I cast Ints with a helper function Int.toR() shown below:

drawer.isolatedWithTarget(stencilTarget) {
    clear(0.toR())

    fill = 1.toR()
    stroke = null
    circle(Circle(200.0, 100.0, radius = 50.0))

     fill = 2.toR()
     stroke = 2.toR()
     rectangle(Rectangle(width*0.5, 0.0, width*0.5, height * 1.0))
}

using the mentioned cast:

fun Int.toR(): ColorRGBa = ColorRGBa(r = this / 256.0, g = 0.0, b = 0.0)

I can pass this to my glsl filter just as I wanted, where I define uniform usampler2D stencil;. In my filter main I use it via uint stencilValue = texture(stencil, v_texCoord0).x; with typical control flow if (stencilValue == 1u) ... else if (stencilValue == 2u) ... and so on.

1 Like

Great that you found a workaround, and thank you for sharing it! :slight_smile:

I thought about using renderTargets but didn’t want to suggest that because I was curious about actually using stencils as described in learnopengl. I guess one could directly access the OPENGL driver but that is discouraged as maybe in the future it is switched to a different backend.

With your approach, could you also use ColorType.FLOAT32 and then just round to integers? Then you wouldn’t be limited to 256 levels (in case that’s an issue). Maybe faster to use ints in the shader?

I dabbled with some variations before and found ColorType.FLOAT32 to be tricky.

In my case I want to check for equality (in an iterative procedure so ~100 times per pixel) and writing floats to a buffer where the precision on the glsl end may change (lowp/mediump/highp precision) seemed wasteful.
Also, I have not yet found a robust way to get the exact same floats to the filter :thinking:

As the picture above suggests, I just need a handful of ints. Should I need to scale, I’d opt in for ColorType.SINT16_INT or ColorType.SINT32_INTand go for an int sampler on the glsl side.