osgEarth 2.1.1
|
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 }