Discussion:
stencil buffer and CSG Boolean operations
Craig Fletcher
2011-07-15 10:15:10 UTC
Permalink
Hi,
I am trying to use the stencil buffer to implement CSG Boolean operations.

As part of this I need to selectively render the front and back faces of the two objects in order to test depth and update the stencil buffer

What I would like to know is how can I enable face culling in OSG ?
(I understand from the quick start guide that attaching an attribute to a stateset is only a desired state and doesn’t issue an OpenGL command, so it may not do it, the code stub below doesn’t seem to have any affect and the whole cylinder is rendered)

osg::StateSet* state = myCylinderGeode->getOrCreateStateSet();
osg::CullFace* cf = new osg::CullFace(osg::CullFace::FRONT);
state->setAttribute( cf );

The second question is how can I selectively render the first object (object a) modify the stencil and face culling then render the second object (object b)?

Should I use a node mask on the cull traversal as mentioned in the node mask tutorial? (if so any pointers on how to do it would be great)

If anyone could help or point me in the right direction it would be greatly appreciated.

The OpenGL code implementation is below.

The openGL function is
firstInsideSecond(void (*a) (void), void (*b) (void), GLenum face, GLenum test)
{
glEnable(GL_DEPTH_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glCullFace(face); /* controls which face of a to use */
a(); /* draw a face of a into depth buffer */

/* use stencil plane to find parts of a in b */
glDepthMask(GL_FALSE);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0, 0);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
glCullFace(GL_BACK);
b(); /* increment the stencil where the front face of b is
drawn */
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
glCullFace(GL_FRONT);
b(); /* decrement the stencil buffer where the back face
of b is drawn */
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

glStencilFunc(test, 0, 1);
glDisable(GL_DEPTH_TEST);

glCullFace(face);
a(); /* draw the part of a that's in b */
}part of a that's in b */
The function call is
firstInsideSecond(a, b, GL_BACK, GL_NOTEQUAL);
with a and b being a box and a cylinder.


Thank you!

Cheers,
Craig

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=41383#41383
Sergey Kurdakov
2011-07-15 14:46:52 UTC
Permalink
Hi Craig,

while I do not respond to your question directly, but concerning real time
CSG booleans I'd suggest to look at papers


http://www.hpi.uni-potsdam.de/fileadmin/hpi/FG_Doellner/publications/2008/TD08a/VolumetricTest.pdf
http://www.hpi.uni-potsdam.de/fileadmin/hpi/FG_Doellner/publications/2008/TD08a/matthias_trapp_volumetric_tests_EG2008_poster.pdf
http://www.hpi.uni-potsdam.de/fileadmin/hpi/FG_Doellner/publications/2008/TD08b/132-Trapp-Efficient-LDI-Representation.pdf



see also http://www.opencsg.org/
and http://arxiv.org/ftp/arxiv/papers/1009/1009.0794.<http://arxiv.org/ftp/arxiv/papers/1009/1009.0794.pdf>
pdf <http://arxiv.org/ftp/arxiv/papers/1009/1009.0794.pdf>
http://www2.mae.cuhk.edu.hk/~<http://www2.mae.cuhk.edu.hk/~cwang/pubs/TVCGMeshBoolean.pdf>
cwang/pubs/TVCGMeshBoolean.pdf<http://www2.mae.cuhk.edu.hk/~cwang/pubs/TVCGMeshBoolean.pdf>

Regards
Sergey
Post by Craig Fletcher
Hi,
I am trying to use the stencil buffer to implement CSG Boolean operations.
As part of this I need to selectively render the front and back faces of
the two objects in order to test depth and update the stencil buffer
What I would like to know is how can I enable face culling in OSG ?
(I understand from the quick start guide that attaching an attribute to a
stateset is only a desired state and doesn’t issue an OpenGL command, so it
may not do it, the code stub below doesn’t seem to have any affect and the
whole cylinder is rendered)
osg::StateSet* state = myCylinderGeode->getOrCreateStateSet();
osg::CullFace* cf = new osg::CullFace(osg::CullFace::FRONT);
state->setAttribute( cf );
The second question is how can I selectively render the first object
(object a) modify the stencil and face culling then render the second object
(object b)?
Should I use a node mask on the cull traversal as mentioned in the node
mask tutorial? (if so any pointers on how to do it would be great)
If anyone could help or point me in the right direction it would be greatly appreciated.
The OpenGL code implementation is below.
The openGL function is
firstInsideSecond(void (*a) (void), void (*b) (void), GLenum face, GLenum test)
{
glEnable(GL_DEPTH_TEST);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glCullFace(face); /* controls which face of a to use */
a(); /* draw a face of a into depth buffer */
/* use stencil plane to find parts of a in b */
glDepthMask(GL_FALSE);
glEnable(GL_STENCIL_TEST);
glStencilFunc(GL_ALWAYS, 0, 0);
glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
glCullFace(GL_BACK);
b(); /* increment the stencil where the front face of b is
drawn */
glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
glCullFace(GL_FRONT);
b(); /* decrement the stencil buffer where the back face
of b is drawn */
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glStencilFunc(test, 0, 1);
glDisable(GL_DEPTH_TEST);
glCullFace(face);
a(); /* draw the part of a that's in b */
}part of a that's in b */
The function call is
firstInsideSecond(a, b, GL_BACK, GL_NOTEQUAL);
with a and b being a box and a cylinder.
Thank you!
Cheers,
Craig
------------------
http://forum.openscenegraph.org/viewtopic.php?p=41383#41383
_______________________________________________
osg-users mailing list
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
Chris 'Xenon' Hanson
2011-07-15 14:56:01 UTC
Permalink
Post by Craig Fletcher
What I would like to know is how can I enable face culling in OSG ?
(I understand from the quick start guide that attaching an attribute to a stateset is only a desired state and doesn’t issue an OpenGL command, so it may not do it, the code stub below doesn’t seem to have any affect and the whole cylinder is rendered)
It should issue the GL command if that state isn't already in effect.
Post by Craig Fletcher
osg::StateSet* state = myCylinderGeode->getOrCreateStateSet();
osg::CullFace* cf = new osg::CullFace(osg::CullFace::FRONT);
state->setAttribute( cf );
If you have to, you could always use a custom Draw callback on your drawable:
http://www.openscenegraph.org/documentation/OpenSceneGraphReferenceDocs/a00190.html#_details

To force issuing the openGL commands you want before and after it is drawn.
Post by Craig Fletcher
The second question is how can I selectively render the first object (object a) modify the stencil and face culling then render the second object (object b)?
Should I use a node mask on the cull traversal as mentioned in the node mask tutorial? (if so any pointers on how to do it would be great)
Seems like this would be a task for Render Bins?
--
Chris 'Xenon' Hanson, omo sanza lettere. ***@AlphaPixel.com http://www.alphapixel.com/
Digital Imaging. OpenGL. Scene Graphs. GIS. GPS. Training. Consulting. Contracting.
"There is no Truth. There is only Perception. To Perceive is to Exist." - Xen
Craig Fletcher
2011-07-15 14:57:39 UTC
Permalink
Hi Sergey,

Thanks for that, i'll take a look at them



Cheers,
Craig

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=41390#41390
Sergey Polischuk
2011-07-15 15:52:09 UTC
Permalink
Hi, Craig

About state part - setAttribute() call by default set attribute off, you should call setAttribute(cf, osg::StateAttribute::ON) + setMode(GL_CULL_FACE, osg::StateAttribute::ON) or setAttributeAndModes(cf) which by default enables attribute.
Also to be able to use stencil you should request visual with stencil or if you use fbo camera you should attach packed depth stencil buffer to it. Dont forget to enable stencil test with setMode(GL_STENCIL_TEST, osg::StateAttribute::ON).

Cheers,
Sergey.
Post by Craig Fletcher
Hi,
I am trying to use the stencil buffer to implement CSG Boolean operations.
As part of this I need to selectively render the front and back faces of the two objects in order to test depth and update the stencil buffer
What I would like to know is how can I enable face culling in OSG ?
(I understand from the quick start guide that attaching an attribute to a stateset is only a desired state and doesn’t issue an OpenGL command, so it may not do it, the code stub below doesn’t seem to have any affect and the whole cylinder is rendered)
osg::StateSet* state = myCylinderGeode->getOrCreateStateSet();
osg::CullFace* cf = new osg::CullFace(osg::CullFace::FRONT);
state->setAttribute( cf );
The second question is how can I selectively render the first object (object a) modify the stencil and face culling then render the second object (object b)?
Should I use a node mask on the cull traversal as mentioned in the node mask tutorial? (if so any pointers on how to do it would be great)
If anyone could help or point me in the right direction it would be greatly appreciated.
The OpenGL code implementation is below.
The openGL  function is
firstInsideSecond(void (*a) (void), void (*b) (void), GLenum face, GLenum test)
{
  glEnable(GL_DEPTH_TEST);
  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  glCullFace(face);     /* controls which face of a to use */
  a();                  /* draw a face of a into depth buffer */
  /* use stencil plane to find parts of a in b */
  glDepthMask(GL_FALSE);
  glEnable(GL_STENCIL_TEST);
  glStencilFunc(GL_ALWAYS, 0, 0);
  glStencilOp(GL_KEEP, GL_KEEP, GL_INCR);
  glCullFace(GL_BACK);
  b();                  /* increment the stencil where the front face of b is
                           drawn */
  glStencilOp(GL_KEEP, GL_KEEP, GL_DECR);
  glCullFace(GL_FRONT);
  b();                  /* decrement the stencil buffer where the back face
                           of b is drawn */
  glDepthMask(GL_TRUE);
  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  glStencilFunc(test, 0, 1);
  glDisable(GL_DEPTH_TEST);
  glCullFace(face);
  a();                  /* draw the part of a that's in b */
}part of a that's in b */
The function call is
firstInsideSecond(a, b, GL_BACK, GL_NOTEQUAL);
with a and b being a box and a cylinder.
Thank you!
Cheers,
Craig
------------------
http://forum.openscenegraph.org/viewtopic.php?p=41383#41383
_______________________________________________
osg-users mailing list
http://lists.openscenegraph.org/listinfo.cgi/osg-users-openscenegraph.org
Craig Fletcher
2011-07-18 07:51:14 UTC
Permalink
Hi
Thanks alot for your comments Sergey and Chris.

I have tried to implement the algorithm, code and comments below but it doesn't work as I had hoped.

What I expected to see is the back wall of a cylinder (which intersects a box). What I actually see is the whole back wall of a cylinder rendered and the image flickers.

Perhaps I have approached this the wrong way regarding loading the depth buffer and then creating the stencil mask or have just misunderstood how to do it? Any comments or pointers on the code would be very welcome.

#include "stdafx.h"
#include <osg/Geode>
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
#include <osgViewer/ViewerEventHandlers>
#include <osg/ShapeDrawable>

#include <osg/Depth>
#include <osg/Stencil>
#include <osg/CullFace>

#include <time.h>

osg::ref_ptr<osg::Group> root;
osg::ref_ptr<osg::Geode> myBoxGeode;
osg::ref_ptr<osg::Geode> myCylinderGeode;

void loadCylinder()
{

osg::ref_ptr<osg::Cylinder> myCylinder = new osg::Cylinder(osg::Vec3(0,0,0),0.1,1.0);
osg::ref_ptr<osg::ShapeDrawable> myCylinderDrawable = new osg::ShapeDrawable(myCylinder);
myCylinderGeode = new osg::Geode();
myCylinderGeode->addDrawable(myCylinderDrawable);
root->addChild(myCylinderGeode);


}

void loadBox()
{
//create a box
osg::ref_ptr<osg::Box> myBox = new osg::Box(osg::Vec3(0,0,0),0.5);
osg::ref_ptr<osg::ShapeDrawable> myBoxDrawable = new osg::ShapeDrawable(myBox);
myBoxGeode = new osg::Geode();
myBoxGeode->addDrawable(myBoxDrawable);
root->addChild(myBoxGeode);

}



int _tmain(int argc, _TCHAR* argv[])
{
root = new osg::Group;
loadCylinder();
loadBox();

osg::StateSet* cylState = myCylinderGeode->getOrCreateStateSet();
osg::CullFace* cfCyl = new osg::CullFace();
cylState->setAttributeAndModes(cfCyl);

osg::StateSet* boxState = myBoxGeode->getOrCreateStateSet();
osg::CullFace* cfBox = new osg::CullFace();
boxState->setAttributeAndModes(cfBox);

osg::StateSet* state = root->getOrCreateStateSet();

osg::ColorMask* colorMask = new osg::ColorMask();
osg::Depth* depth = new osg::Depth();
osg::Stencil* stencil = new osg::Stencil();

state->setAttribute(stencil);
state->setAttribute(colorMask);
state->setAttribute(depth);


osgViewer::Viewer viewer;
viewer.addEventHandler(new osgViewer::StatsHandler());
viewer.setUpViewInWindow( 50, 50, 1024, 768 );
viewer.setSceneData( root );
viewer.setCameraManipulator(new osgGA::TrackballManipulator());

osg::DisplaySettings::instance()->setMinimumNumStencilBits(8);



while( !viewer.done() )
{
/*****************************************************************
* Turn off writing to the colour buffer, so nothing is rendered
* to the screen yet
*
*******************************************************************/
colorMask->setMask(false, false,false,false);

/*****************************************************************
* Clear stencil buffer to O ??
*
*
*******************************************************************/



/*****************************************************************
* Turn on depth testing
*
*
*******************************************************************/
state->setAttribute(depth, osg::StateAttribute::ON );



/***************************************************************
* Render the back face of cylinder (object a) into depth buffer
* Ensure the box (object b ) isn't rendered
*
*****************************************************************/
cfCyl->setMode(osg::CullFace::FRONT);
cfBox->setMode(osg::CullFace::FRONT_AND_BACK);
viewer.frame();

/***************************************************************
* Disable writing to the depth buffer
*
*
*****************************************************************/
depth->setWriteMask( false );



/*****************************************************************
* Set the stencil buffer to increment if the depth test passes
*
*
******************************************************************/
//enable the stencil test
stencil->setWriteMask(true);
state->setAttribute( stencil, osg::StateAttribute::ON );

//set the stencil functions
stencil->setFunction(osg::Stencil::ALWAYS,0,0);
stencil->setOperation(osg::Stencil::KEEP,osg::Stencil::KEEP,osg::Stencil::INCR);

/*****************************************************************
* Render the front faces of the box object b
*
*
******************************************************************/
cfCyl->setMode(osg::CullFace::FRONT_AND_BACK);
cfBox->setMode(osg::CullFace::BACK);
viewer.frame();


/*****************************************************************
* Set the stencil buffer to decrement if the depth test passes
*
*
******************************************************************/
stencil->setOperation(osg::Stencil::KEEP,osg::Stencil::KEEP,osg::Stencil::DECR);

/****************************************************************************
* Render the back face of the box (object b)
*
*
*****************************************************************************/
cfBox->setMode(osg::CullFace::FRONT);
viewer.frame();


/*******************************************************************************
* Set the stencil buffer to pass where values aren't equal to 0
*
*
********************************************************************************/
stencil->setFunction(osg::Stencil::NOTEQUAL,0,1);

/*******************************************************************************
* Turn off writing to the stencil buffer
*
*
********************************************************************************/
stencil->setWriteMask(false);

/*******************************************************************************
* Turn on writing to the colour buffer
*
*
********************************************************************************/
colorMask->setMask(true, true,true,true);

/*******************************************************************************
* Turn off depth testing
*
*
********************************************************************************/
state->setAttribute(depth,osg::StateAttribute::OFF);

/*******************************************************************************
* Render back faces of cylinder object a
*
*
********************************************************************************/
cfCyl->setMode(osg::CullFace::FRONT);
cfBox->setMode(osg::CullFace::FRONT_AND_BACK);

viewer.frame();

}

return 0;
}





Thank you!

Cheers,
Craig

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=41421#41421




Attachments:
http://forum.openscenegraph.org//files/stencil_buffer_171.cpp

Loading...