Using stencils [Solved]

Hello, I am so green I need mowing!
Trying to see what exactly a ‘stencil’ is. I hacked this together from the manual, but running it shows a gray screen. If I remove the loadPrcFileData line it shows the panda. What is one supposed to see?

Specs:
Kubuntu Jaunty 64 bit. Nvidia driver. Blender and company all work quite well (glsl too). Panda 1.6.2

from pandac.PandaModules import *

loadPrcFileData("", "framebuffer-stencil #t")

import direct.directbase.DirectStart

constantOneStencil = StencilAttrib.make(1,StencilAttrib.SCFAlways,StencilAttrib.SOZero,StencilAttrib.SOReplace,StencilAttrib.SOReplace,1,0,1)
 
stencilReader = StencilAttrib.make(1,StencilAttrib.SCFEqual,StencilAttrib.SOKeep, StencilAttrib.SOKeep,StencilAttrib.SOKeep,1,1,0)

cm = CardMaker("cardmaker")
cm.setFrame(-.5,.5,-.5,.5)
viewingSquare = render.attachNewNode(cm.generate())
viewingSquare.node().setAttrib(constantOneStencil)
viewingSquare.node().setAttrib(ColorWriteAttrib.make(0))
viewingSquare.setBin('background',0)
viewingSquare.setDepthWrite(0)

view = loader.loadModel("/usr/share/panda3d/models/panda")
view.reparentTo(render)
view.setScale(3)
view.setY(150)
view.node().setAttrib(stencilReader)

run()

[/code]

A stencil is a special invisible buffer that overlays the screen. You can write values to it while you’re drawing one object, and then test against those values while you’re drawing another object. It’s usually used to mask out parts of the screen that you don’t want certain objects to draw into; for instance, you could use it to draw reflections of the sky only within the surface of a lake, and not on the boat that’s floating on top of the lake.

The stencil buffer is not very exciting by itself. You would normally use it in conjunction with other tricks in order to achieve a very specific effect. It’s rather an advanced feature of 3-D graphics rendering. If you don’t know of any specific effects that require a stencil buffer, then you probably don’t need to mess with it. :slight_smile:

David

Thanks, I think it’s what I might be looking for: a way to ‘mask’ objects behind the stencil.

I have written a python animation animation API which I am (call me crazy) thinking of moving across to Panda. Part of what it can do is ‘clipping’ where sub-things go into a parent which defines a clip shape – so I was hoping to replicate something like it in Panda.

Do you have any clues as to why the above code did not work? Is it an advanced GL driver thing? Perhaps my card is not up to it. If it’s fairly common, then I would want to use it. If not, then I will probably skip the clipping part of the API.

Thanks.
\d
BTW: The API is here:
2D vector animation : savannah.nongnu.org/projects/things/

I think you intended your constantOneStencil card to be drawn overlaying the whole screen, so that it will fill the stencil buffer to 1 everywhere, but you didn’t quite do that–your card is actually parented to render, which means it is laying flat on the floor beneath the panda model. So almost no pixels get the stencil buffer set to 1, which is why you can’t see anything.

You could parent your card to render2d, but render2d is normally drawn after render, so it still won’t help. You should maybe parent your card directly to the camera, something like this:

viewingSquare.reparentTo(base.camera)
viewingSquare.setPos(0, 5, 0)

I set it to pos (0, 5, 0) to put it a little in front of the camera so it will be visible. Of course, the card itself is invisible, due to the ColorWriteAttrib, but its stencil effect will be applied anywhere the card would have been drawn.

Note that another approach would be to parent it to render2d anyway, and change the sort of render2d to be drawn before render. Or to create a new DisplayRegion to be drawn before render just for this purpose. It all depends on precisely what effect you are trying to achieve. (If you really just wanted to initialize every stencil value to 1, it would be better to set that as the clear value, rather than drawing a big polygon overlaying everything. But I suspect that isn’t your final goal.)

David

I gave your code a go, but I still get either the Panda or nothing at all. I changed the background to yellow, so I could spot anything grey (I’d hoped.)

Here is the code with your changes. Any help would be magic.

from pandac.PandaModules import *

loadPrcFileData("", "framebuffer-stencil #t")

import direct.directbase.DirectStart

constantOneStencil = StencilAttrib.make(1,StencilAttrib.SCFAlways,StencilAttrib.SOZero,StencilAttrib.SOReplace,StencilAttrib.SOReplace,1,0,1)
 
stencilReader = StencilAttrib.make(1,StencilAttrib.SCFEqual,StencilAttrib.SOKeep, StencilAttrib.SOKeep,StencilAttrib.SOKeep,1,1,0)

cm = CardMaker("cardmaker")
cm.setFrame(-.1,.1,-.1,.1)

viewingSquare = render.attachNewNode(cm.generate())
viewingSquare.reparentTo(base.camera)
viewingSquare.setPos(0, 5, 0)

viewingSquare.node().setAttrib(constantOneStencil)
viewingSquare.node().setAttrib(ColorWriteAttrib.make(0))
viewingSquare.setBin('background',0)
viewingSquare.setDepthWrite(0)
viewingSquare.setH(90)

view = loader.loadModel("/usr/share/panda3d/models/panda")
view.reparentTo(render)
view.setScale(3)
view.setY(150)
view.node().setAttrib(stencilReader)


base.setBackgroundColor(1,1,0)

run()

Are you seeing a partially clipped Panda on your end?

\d

You made the card smaller, so now it’s not obscuring the Panda any more. Try removing the ColorWriteAttrib, so you can see the card. That will make it much easier to debug.

David

Bingo!
And this line should be removed (which was my addition):
viewingSquare.setH(90) (I was trying to flip it up, think I got the wrong axis. I am not used to HPR terms.)

Do you think the docs should be updated? I got the original code directly from there:
panda3d.org/manual/index.php/S … _Attribute

Thx for you help.

Could that ‘card’ be any arbitrary shape? Like a star (flat) or a letter like “W”, or something?

\d

Hmm, you’re right, that sample code doesn’t actually do much. If you wanted to update the manual a bit, that would be fine. :slight_smile:

Yep, that’s the whole point of a stencil buffer. If you really just wanted to mask out a rectangular region of the screen, there are much easier ways to do it.

David

Took me a mo to find the ‘.’ but I made an account and changed the page. Hope it’s okay.

\d