osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthSymbology/StencilVolumeNode.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003  * Copyright 2008-2010 Pelican Mapping
00004  * http://osgearth.org
00005  *
00006  * osgEarth is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 #include <osgEarthSymbology/StencilVolumeNode>
00020 #include <osgEarth/Registry>
00021 #include <osgEarth/FindNode>
00022 #include <osg/Stencil>
00023 #include <osg/StencilTwoSided>
00024 #include <osg/Depth>
00025 #include <osg/Drawable>
00026 #include <osg/CopyOp>
00027 #include <osg/CullFace>
00028 #include <osg/MatrixTransform>
00029 #include <osg/Projection>
00030 #include <osg/GLExtensions>
00031 #include <osg/Geode>
00032 #include <osg/Notify>
00033 #include <osgUtil/Tessellator>
00034 #include <algorithm>
00035 
00036 #define ON_AND_PROTECTED  osg::StateAttribute::ON | osg::StateAttribute::PROTECTED
00037 #define OFF_AND_PROTECTED osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED
00038 
00039 using namespace osgEarth;
00040 using namespace osgEarth::Symbology;
00041 
00042 /***************************************************************************/
00043 
00044 #define OFF_PROTECTED osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED
00045 
00046 osg::Node*
00047 StencilVolumeNode::createFullScreenQuad( const osg::Vec4f& color )
00048 {
00049     // make a full screen quad:
00050     osg::Geometry* quad = new osg::Geometry();
00051     osg::Vec3Array* verts = new osg::Vec3Array(4);
00052     (*verts)[0].set( 0, 1, 0 );
00053     (*verts)[1].set( 0, 0, 0 );
00054     (*verts)[2].set( 1, 0, 0 );
00055     (*verts)[3].set( 1, 1, 0 );
00056     quad->setVertexArray( verts );
00057     quad->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4 ) );
00058     osg::Vec4Array* colors = new osg::Vec4Array(1);
00059     (*colors)[0] = color;
00060     quad->setColorArray( colors );
00061     quad->setColorBinding( osg::Geometry::BIND_OVERALL );
00062     osg::Geode* quad_geode = new osg::Geode();
00063     quad_geode->addDrawable( quad );
00064 
00065     osg::StateSet* quad_ss = quad->getOrCreateStateSet();
00066     quad_ss->setMode( GL_CULL_FACE, OFF_PROTECTED );
00067     quad_ss->setMode( GL_DEPTH_TEST, OFF_PROTECTED );
00068     quad_ss->setMode( GL_LIGHTING, OFF_PROTECTED );
00069     osg::MatrixTransform* abs = new osg::MatrixTransform();
00070     abs->setReferenceFrame( osg::Transform::ABSOLUTE_RF );
00071     abs->setMatrix( osg::Matrix::identity() );
00072     abs->addChild( quad_geode );
00073 
00074     osg::Projection* proj = new osg::Projection();
00075     proj->setMatrix( osg::Matrix::ortho(0, 1, 0, 1, 0, -1) );
00076     proj->addChild( abs );
00077 
00078     proj->getOrCreateStateSet()->setMode( GL_BLEND, 1 );    
00079 
00080     return proj;
00081 }
00082 
00083 
00084 /***************************************************************************/
00085 
00086 StencilVolumeNode::StencilVolumeNode( bool preRenderChildrenToDepthBuffer, bool inverted ) :
00087 osgEarth::MaskNode(),
00088 _stencilGroup1( 0L ),
00089 _stencilGroup2( 0L ),
00090 _depthPass( 0L ),
00091 _renderPass( 0L ),
00092 _inverted( inverted ),
00093 _preRenderChildrenToDepthBuffer( preRenderChildrenToDepthBuffer )
00094 {
00095     init();
00096 }
00097 
00098 StencilVolumeNode::StencilVolumeNode(const StencilVolumeNode& rhs,
00099                                      const osg::CopyOp& op) :
00100 osgEarth::MaskNode( rhs, op ),
00101 _root( rhs._root.get() ),
00102 _stencilGroup1( rhs._stencilGroup1 ),
00103 _stencilGroup2( rhs._stencilGroup2 ),
00104 _depthPass( rhs._depthPass ),
00105 _renderPass( rhs._renderPass ),
00106 _inverted( rhs._inverted ),
00107 _preRenderChildrenToDepthBuffer( rhs._preRenderChildrenToDepthBuffer )
00108 {
00109     //nop
00110 }
00111 
00112 int
00113 StencilVolumeNode::setBaseRenderBin( int bin )
00114 {
00115     if ( _depthPass )
00116     {
00117         _depthPass->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" );
00118     }
00119     if ( _stencilGroup1 )
00120     {
00121         _stencilGroup1->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" );
00122     }
00123     if ( _stencilGroup2 )
00124     {
00125         _stencilGroup2->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" );
00126     }
00127     if ( _renderPass )
00128     {
00129         _renderPass->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" );
00130     }
00131     return bin;
00132 }
00133 
00134 void
00135 StencilVolumeNode::addVolumes( osg::Node* node, bool onNextUpdate )
00136 {
00137     if ( onNextUpdate )
00138     {
00139         Threading::ScopedMutexLock lock( _addVolumesMutex );
00140         _volumesToAdd.push( node );
00141         ADJUST_UPDATE_TRAV_COUNT( this, 1 );
00142     }
00143     else
00144     {
00145         if ( _stencilGroup1 )
00146             _stencilGroup1->addChild( node );
00147         if ( _stencilGroup2 )
00148             _stencilGroup2->addChild( node );
00149     }
00150 }
00151 
00152 void
00153 StencilVolumeNode::addQueuedVolumes()
00154 {
00155     Threading::ScopedMutexLock lock( _addVolumesMutex );
00156     while( !_volumesToAdd.empty() )
00157     {
00158         osg::Node* node = _volumesToAdd.front().get();
00159 
00160         if ( _stencilGroup1 )
00161             _stencilGroup1->addChild( node );
00162         if ( _stencilGroup2 )
00163             _stencilGroup2->addChild( node );        
00164 
00165         _volumesToAdd.pop();
00166     }
00167     
00168     ADJUST_UPDATE_TRAV_COUNT( this, -1 );
00169 }
00170 
00173 bool 
00174 StencilVolumeNode::addChild( Node *child ) {
00175     if ( !child ) return false;
00176     dirtyBound();
00177     if ( _depthPass )  _depthPass->addChild( child );
00178     return _renderPass->addChild( child );
00179 }
00180 bool 
00181 StencilVolumeNode::insertChild( unsigned int index, Node *child ) {
00182     if ( !child ) return false;
00183     dirtyBound();
00184     if ( _depthPass ) _depthPass->insertChild( index, child );
00185     return _renderPass->insertChild( index, child );
00186 }
00187 bool 
00188 StencilVolumeNode::removeChildren(unsigned int pos,unsigned int numChildrenToRemove) {
00189     dirtyBound();
00190     if ( _depthPass ) _depthPass->removeChildren( pos, numChildrenToRemove );
00191     return _renderPass->removeChildren( pos, numChildrenToRemove );
00192 }
00193 bool 
00194 StencilVolumeNode::replaceChild( Node *origChild, Node* newChild ) {
00195     dirtyBound();
00196     if ( _depthPass ) _depthPass->replaceChild( origChild, newChild );
00197     return _renderPass->replaceChild( origChild, newChild );
00198 }
00199 bool 
00200 StencilVolumeNode::setChild( unsigned  int i, Node* node ) {
00201     dirtyBound();
00202     if ( _depthPass ) _depthPass->setChild( i, node );
00203     return _renderPass->setChild( i, node );
00204 }
00205 
00206 osg::BoundingSphere
00207 StencilVolumeNode::computeBound() const {
00208     if ( _depthPass ) return _depthPass->computeBound();
00209     else return _renderPass->computeBound();
00210 }
00211 
00212 
00213 void
00214 StencilVolumeNode::traverse( osg::NodeVisitor& nv )
00215 {
00216     if ( nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR && _volumesToAdd.size() > 0 )
00217     {
00218         addQueuedVolumes();
00219     }
00220 
00221     _root->accept( nv );
00222 }
00223 
00224 void
00225 StencilVolumeNode::init()
00226 {
00227     _root = new osg::Group();
00228     int baseBin = 100;
00229 
00230     // First, if we need to render the children to the depth buffer, create a depth
00231     // buffer only pass. This is necessary if we are masking out terrain, for example. We have
00232     // to populate the depth buffer before this algoritm can work.
00233     if ( _preRenderChildrenToDepthBuffer )
00234     {
00235         _depthPass = new osg::Group();
00236         _depthPass->setName( "StencilVolumeNode::depth_pass" );
00237         osg::StateSet* ss = _depthPass->getOrCreateStateSet();
00238         ss->setAttributeAndModes(new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
00239         //ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::BACK), ON_AND_PROTECTED);
00240         ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS), ON_AND_PROTECTED);
00241         ss->setRenderBinDetails( baseBin++, "RenderBin" );
00242 
00243         _root->addChild( _depthPass );
00244     }
00245 
00246     // Create the stenciled geometry pass:
00247 
00248     // For now we are hard-coding these to what are hopefully "safe" values.
00249     // In the future we hope to rewrite this as a custom StencilVolumeNode that 
00250     // will automatically detect extension availability at draw time and choose
00251     // the optimal GL rendering path.
00252     const Capabilities& caps = osgEarth::Registry::instance()->getCapabilities();
00253     bool s_EXT_stencil_wrap     = caps.supportsStencilWrap(); //true;
00254     bool s_EXT_stencil_two_side = caps.supportsTwoSidedStencil(); //false;
00255 
00256 
00257     // zFail=true if more compute intensive, but lets you get inside the volume.
00258     // Again, a custom node will give us a better opportunity to choose between zFail and zPass based on
00259     // the eye location (you only need zFail if you camera is inside the volume).
00260     bool zFail = true;
00261 
00262     OE_DEBUG << "Stencil buffer wrap = " << s_EXT_stencil_wrap << std::endl;
00263 
00264     if ( s_EXT_stencil_two_side )
00265     {
00266         OE_DEBUG << "Two-sided stenciling" << std::endl;
00267 
00268         osg::StencilTwoSided::Operation incrOp = s_EXT_stencil_wrap ? osg::StencilTwoSided::INCR_WRAP : osg::StencilTwoSided::INCR;
00269         osg::StencilTwoSided::Operation decrOp = s_EXT_stencil_wrap ? osg::StencilTwoSided::DECR_WRAP : osg::StencilTwoSided::DECR;
00270         _stencilGroup1 = new osg::Group();
00271         //osg::Group* stencil_group = new osg::Group();
00272         osg::StateSet* ss = _stencilGroup1->getOrCreateStateSet();
00273         ss->setRenderBinDetails( baseBin++, "RenderBin" );
00274 
00275         if ( zFail )
00276         {
00277             osg::StencilTwoSided* stencil = new osg::StencilTwoSided();
00278             stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS, 1, ~0u); 
00279             stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, incrOp, osg::StencilTwoSided::KEEP);
00280 
00281             stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS, 1, ~0u); 
00282             stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, decrOp, osg::StencilTwoSided::KEEP);
00283             ss->setAttributeAndModes( stencil, ON_AND_PROTECTED );
00284         }
00285         else
00286         {
00287             osg::StencilTwoSided* stencil = new osg::StencilTwoSided();
00288             stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS, 1, ~0u); 
00289             stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, incrOp);
00290 
00291             stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS, 1, ~0u); 
00292             stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, decrOp);
00293             ss->setAttributeAndModes( stencil, ON_AND_PROTECTED );
00294         }
00295 
00296         ss->setAttributeAndModes(new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
00297         ss->setAttributeAndModes(new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);
00298 
00299         _root->addChild( _stencilGroup1 );
00300     }
00301     else
00302     {
00303         OE_INFO << "One-sided stenciling" << std::endl;
00304 
00305         if ( !zFail )  // Z-Pass
00306         {
00307             _stencilGroup1 = new osg::Group();
00308             osg::StateSet* front_ss = _stencilGroup1->getOrCreateStateSet();
00309             front_ss->setRenderBinDetails( baseBin++, "RenderBin" );
00310 
00311             // incrementing stencil op for front faces:
00312             osg::Stencil* front_stencil = new osg::Stencil();
00313             front_stencil->setFunction( osg::Stencil::ALWAYS, 1, ~0u );
00314             osg::Stencil::Operation incrOp = s_EXT_stencil_wrap ? osg::Stencil::INCR_WRAP : osg::Stencil::INCR;
00315             front_stencil->setOperation( osg::Stencil::KEEP, osg::Stencil::KEEP, incrOp );
00316             front_ss->setAttributeAndModes( front_stencil, ON_AND_PROTECTED );
00317 
00318             front_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
00319             front_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::BACK), ON_AND_PROTECTED);
00320             front_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);
00321 
00322             _root->addChild( _stencilGroup1 );
00323 
00324             // decrementing stencil op for back faces:
00325             _stencilGroup2 = new osg::Group();
00326             osg::StateSet* back_ss = _stencilGroup2->getOrCreateStateSet();
00327             back_ss->setRenderBinDetails( baseBin++, "RenderBin" );
00328 
00329             osg::Stencil* back_stencil = new osg::Stencil();
00330             back_stencil->setFunction( osg::Stencil::ALWAYS, 1, ~0u );
00331             osg::Stencil::Operation decrOp = s_EXT_stencil_wrap ? osg::Stencil::DECR_WRAP : osg::Stencil::DECR;
00332             back_stencil->setOperation( osg::Stencil::KEEP, osg::Stencil::KEEP, decrOp );
00333             back_ss->setAttributeAndModes( back_stencil, ON_AND_PROTECTED );
00334 
00335             back_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
00336             back_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::FRONT), ON_AND_PROTECTED);
00337             back_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);
00338 
00339             _root->addChild( _stencilGroup2 );    
00340         }
00341         else
00342         {
00343             // incrementing stencil op for back faces:
00344             {
00345                 _stencilGroup1 = new osg::Group();
00346                 osg::StateSet* front_ss = _stencilGroup1->getOrCreateStateSet();
00347                 front_ss->setRenderBinDetails( baseBin++, "RenderBin" );
00348 
00349                 osg::Stencil* front_stencil = new osg::Stencil();
00350                 front_stencil->setFunction( osg::Stencil::ALWAYS ); //, 1, ~0u );
00351                 osg::Stencil::Operation incrOp = s_EXT_stencil_wrap ? osg::Stencil::INCR_WRAP : osg::Stencil::INCR;
00352                 front_stencil->setOperation( osg::Stencil::KEEP, incrOp, osg::Stencil::KEEP );
00353                 front_ss->setAttributeAndModes( front_stencil, ON_AND_PROTECTED );
00354 
00355                 front_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
00356                 front_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::FRONT), ON_AND_PROTECTED);
00357                 front_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);
00358 
00359                 _root->addChild( _stencilGroup1 );
00360             }
00361 
00362             // decrementing stencil buf for front faces
00363             {
00364                 _stencilGroup2 = new osg::Group();
00365                 osg::StateSet* back_ss = _stencilGroup2->getOrCreateStateSet();
00366                 back_ss->setRenderBinDetails( baseBin++, "RenderBin" );
00367 
00368                 osg::Stencil* back_stencil = new osg::Stencil();
00369                 back_stencil->setFunction( osg::Stencil::ALWAYS ); //, 1, ~0u );
00370                 osg::Stencil::Operation decrOp = s_EXT_stencil_wrap ? osg::Stencil::DECR_WRAP : osg::Stencil::DECR;
00371                 back_stencil->setOperation( osg::Stencil::KEEP, decrOp, osg::Stencil::KEEP );
00372                 back_ss->setAttributeAndModes( back_stencil, ON_AND_PROTECTED );
00373 
00374                 back_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED);
00375                 back_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::BACK), ON_AND_PROTECTED);
00376                 back_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED);
00377 
00378                 _root->addChild( _stencilGroup2 );
00379             }
00380         }
00381     }
00382     
00383 
00384     // NOW build the full-screen quad mask that will paint the volume:
00385 
00386     _renderPass = new osg::Group();
00387     _renderPass->setName( "StencilVolumeNode::render_pass" );
00388 
00389     osg::Stencil* quad_stencil = new osg::Stencil();
00390     osg::Stencil::Function func = _inverted ? osg::Stencil::EQUAL : osg::Stencil::NOTEQUAL;
00391     quad_stencil->setFunction( func, 128, (unsigned int)~0 );
00392     // this will conveniently re-clear the stencil buffer in prep for the next pass:
00393     quad_stencil->setOperation( osg::Stencil::REPLACE, osg::Stencil::REPLACE, osg::Stencil::REPLACE );
00394 
00395     osg::StateSet* renderSS = _renderPass->getOrCreateStateSet();
00396     renderSS->setAttributeAndModes( quad_stencil, ON_AND_PROTECTED );
00397     renderSS->setRenderBinDetails( baseBin++, "RenderBin" );
00398 
00399     // if we did a pre-render depth pass, adjust the depth buffer function to account for that
00400     if ( _preRenderChildrenToDepthBuffer )
00401     {
00402         renderSS->setAttributeAndModes( new osg::Depth( osg::Depth::LEQUAL ), osg::StateAttribute::ON );
00403     }
00404 
00405     // testing
00406     //renderSS->setMode( GL_DEPTH_TEST, OFF_AND_PROTECTED );
00407     //renderSS->setAttributeAndModes( new osg::Depth( osg::Depth::ALWAYS ), ON_AND_PROTECTED );
00408 
00409     _root->addChild( _renderPass );
00410 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines