osgEarth 2.1.1
|
00001 /* -*-c++-*- */ 00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph 00003 * Copyright 2008-2009 Pelican Ventures, Inc. 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 "StencilUtils.h" 00020 #include <osg/Stencil> 00021 #include <osg/StencilTwoSided> 00022 #include <osg/Depth> 00023 #include <osg/Drawable> 00024 #include <osg/CopyOp> 00025 #include <osg/CullFace> 00026 #include <osg/MatrixTransform> 00027 #include <osg/Projection> 00028 #include <osg/GLExtensions> 00029 #include <osg/Geode> 00030 #include <osg/Notify> 00031 #include <osgUtil/Tessellator> 00032 #include <algorithm> 00033 00034 #define ON_AND_PROTECTED osg::StateAttribute::ON | osg::StateAttribute::PROTECTED 00035 #define OFF_AND_PROTECTED osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED 00036 00037 00038 StencilVolumeNode::StencilVolumeNode() : 00039 _stencilGroup1( 0L ), 00040 _stencilGroup2( 0L ), 00041 _maskGroup( 0L ), 00042 _maskColorArray( 0L ) 00043 { 00044 init(); 00045 } 00046 00047 StencilVolumeNode::StencilVolumeNode(const StencilVolumeNode& rhs, 00048 const osg::CopyOp& op) : 00049 osg::Group( rhs, op ), 00050 _stencilGroup1( rhs._stencilGroup1 ), 00051 _stencilGroup2( rhs._stencilGroup2 ), 00052 _maskGroup( rhs._maskGroup ), 00053 _maskColorArray( rhs._maskColorArray ) 00054 { 00055 //nop 00056 } 00057 00058 int 00059 StencilVolumeNode::setBaseRenderBin( int bin ) 00060 { 00061 if ( _stencilGroup1 ) 00062 { 00063 _stencilGroup1->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" ); 00064 } 00065 if ( _stencilGroup2 ) 00066 { 00067 _stencilGroup2->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" ); 00068 } 00069 if ( _maskGroup ) 00070 { 00071 _maskGroup->getOrCreateStateSet()->setRenderBinDetails( bin++, "RenderBin" ); 00072 } 00073 return bin; 00074 } 00075 00076 void 00077 StencilVolumeNode::setColor( const osg::Vec4f& color ) 00078 { 00079 (*_maskColorArray)[0] = color; 00080 // dirty? 00081 } 00082 00083 void 00084 StencilVolumeNode::addVolumes( osg::Node* node ) 00085 { 00086 if ( _stencilGroup1 ) 00087 _stencilGroup1->addChild( node ); 00088 if ( _stencilGroup2 ) 00089 _stencilGroup2->addChild( node ); 00090 } 00091 00092 void 00093 StencilVolumeNode::init() 00094 { 00095 // FIRST create the stenciled geometry pass: 00096 00097 // For now we are hard-coding these to what are hopefully "safe" values. 00098 // In the future we hope to rewrite this as a custom StencilVolumeNode that 00099 // will automatically detect extension availability at draw time and choose 00100 // the optimal GL rendering path. 00101 static bool s_EXT_stencil_wrap = true; //osg::isGLExtensionSupported(0, "GL_EXT_stencil_wrap"); 00102 static bool s_EXT_stencil_two_side = false; //osg::isGLExtensionSupported(0, "GL_EXT_stencil_two_side"); 00103 00104 00105 // zFail=true if more compute intensive, but lets you get inside the volume. 00106 // Again, a custom node will give us a better opportunity to choose between zFail and zPass based on 00107 // the eye location (you only need zFail if you camera is inside the volume). 00108 bool zFail = true; 00109 int baseBin = 100; 00110 00111 osg::notify(osg::INFO) << "[osgEarth] Stencil buffer wrap = " << s_EXT_stencil_wrap << std::endl; 00112 00113 if ( s_EXT_stencil_two_side ) 00114 { 00115 osg::notify(osg::INFO) << "[osgEarth] Two-sided stenciling" << std::endl; 00116 00117 osg::StencilTwoSided::Operation incrOp = s_EXT_stencil_wrap ? osg::StencilTwoSided::INCR_WRAP : osg::StencilTwoSided::INCR; 00118 osg::StencilTwoSided::Operation decrOp = s_EXT_stencil_wrap ? osg::StencilTwoSided::DECR_WRAP : osg::StencilTwoSided::DECR; 00119 _stencilGroup1 = new osg::Group(); 00120 //osg::Group* stencil_group = new osg::Group(); 00121 osg::StateSet* ss = _stencilGroup1->getOrCreateStateSet(); 00122 ss->setRenderBinDetails( baseBin++, "RenderBin" ); 00123 00124 if ( zFail ) 00125 { 00126 osg::StencilTwoSided* stencil = new osg::StencilTwoSided(); 00127 stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS, 1, ~0u); 00128 stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, incrOp, osg::StencilTwoSided::KEEP); 00129 00130 stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS, 1, ~0u); 00131 stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, decrOp, osg::StencilTwoSided::KEEP); 00132 ss->setAttributeAndModes( stencil, ON_AND_PROTECTED ); 00133 } 00134 else 00135 { 00136 osg::StencilTwoSided* stencil = new osg::StencilTwoSided(); 00137 stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS, 1, ~0u); 00138 stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, incrOp); 00139 00140 stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS, 1, ~0u); 00141 stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, decrOp); 00142 ss->setAttributeAndModes( stencil, ON_AND_PROTECTED ); 00143 } 00144 00145 ss->setAttributeAndModes(new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED); 00146 ss->setAttributeAndModes(new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED); 00147 //stencil_group->addChild( geometry ); 00148 00149 this->addChild( _stencilGroup1 ); 00150 //root->addChild( stencil_group ); 00151 } 00152 else 00153 { 00154 osg::notify(osg::INFO) << "[osgEarth] One-sided stenciling" << std::endl; 00155 00156 if ( !zFail ) // Z-Pass 00157 { 00158 _stencilGroup1 = new osg::Group(); 00159 osg::StateSet* front_ss = _stencilGroup1->getOrCreateStateSet(); 00160 front_ss->setRenderBinDetails( baseBin++, "RenderBin" ); 00161 00162 // incrementing stencil op for front faces: 00163 osg::Stencil* front_stencil = new osg::Stencil(); 00164 front_stencil->setFunction( osg::Stencil::ALWAYS, 1, ~0u ); 00165 osg::Stencil::Operation incrOp = s_EXT_stencil_wrap ? osg::Stencil::INCR_WRAP : osg::Stencil::INCR; 00166 front_stencil->setOperation( osg::Stencil::KEEP, osg::Stencil::KEEP, incrOp ); 00167 front_ss->setAttributeAndModes( front_stencil, ON_AND_PROTECTED ); 00168 00169 front_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED); 00170 front_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::BACK), ON_AND_PROTECTED); 00171 front_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED); 00172 00173 //front_group->addChild( geometry ); 00174 this->addChild( _stencilGroup1 ); 00175 //root->addChild( front_group ); 00176 00177 // decrementing stencil op for back faces: 00178 _stencilGroup2 = new osg::Group(); 00179 osg::StateSet* back_ss = _stencilGroup2->getOrCreateStateSet(); 00180 back_ss->setRenderBinDetails( baseBin++, "RenderBin" ); 00181 00182 osg::Stencil* back_stencil = new osg::Stencil(); 00183 back_stencil->setFunction( osg::Stencil::ALWAYS, 1, ~0u ); 00184 osg::Stencil::Operation decrOp = s_EXT_stencil_wrap ? osg::Stencil::DECR_WRAP : osg::Stencil::DECR; 00185 back_stencil->setOperation( osg::Stencil::KEEP, osg::Stencil::KEEP, decrOp ); 00186 back_ss->setAttributeAndModes( back_stencil, ON_AND_PROTECTED ); 00187 00188 back_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED); 00189 back_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::FRONT), ON_AND_PROTECTED); 00190 back_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED); 00191 00192 //back_group->addChild( geometry ); 00193 this->addChild( _stencilGroup2 ); 00194 //root->addChild( back_group ); 00195 } 00196 else 00197 { 00198 // incrementing stencil op for back faces: 00199 { 00200 _stencilGroup1 = new osg::Group(); 00201 osg::StateSet* front_ss = _stencilGroup1->getOrCreateStateSet(); 00202 front_ss->setRenderBinDetails( baseBin++, "RenderBin" ); 00203 00204 osg::Stencil* front_stencil = new osg::Stencil(); 00205 front_stencil->setFunction( osg::Stencil::ALWAYS ); //, 1, ~0u ); 00206 osg::Stencil::Operation incrOp = s_EXT_stencil_wrap ? osg::Stencil::INCR_WRAP : osg::Stencil::INCR; 00207 front_stencil->setOperation( osg::Stencil::KEEP, incrOp, osg::Stencil::KEEP ); 00208 front_ss->setAttributeAndModes( front_stencil, ON_AND_PROTECTED ); 00209 00210 front_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED); 00211 front_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::FRONT), ON_AND_PROTECTED); 00212 front_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED); 00213 00214 //front_group->addChild( geometry ); 00215 this->addChild( _stencilGroup1 ); 00216 //root->addChild( front_group ); 00217 } 00218 00219 // decrementing stencil buf for front faces 00220 { 00221 _stencilGroup2 = new osg::Group(); 00222 osg::StateSet* back_ss = _stencilGroup2->getOrCreateStateSet(); 00223 back_ss->setRenderBinDetails( baseBin++, "RenderBin" ); 00224 00225 osg::Stencil* back_stencil = new osg::Stencil(); 00226 back_stencil->setFunction( osg::Stencil::ALWAYS ); //, 1, ~0u ); 00227 osg::Stencil::Operation decrOp = s_EXT_stencil_wrap ? osg::Stencil::DECR_WRAP : osg::Stencil::DECR; 00228 back_stencil->setOperation( osg::Stencil::KEEP, decrOp, osg::Stencil::KEEP ); 00229 back_ss->setAttributeAndModes( back_stencil, ON_AND_PROTECTED ); 00230 00231 back_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED); 00232 back_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::BACK), ON_AND_PROTECTED); 00233 back_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED); 00234 00235 //back_group->addChild( geometry ); 00236 this->addChild( _stencilGroup2 ); 00237 //root->addChild( back_group ); 00238 } 00239 } 00240 } 00241 00242 00243 // NOW built the full-screen quad mask that will paint the volume: 00244 00245 _maskGroup = new osg::Group(); 00246 00247 // make a full screen quad: 00248 osg::Geometry* quad = new osg::Geometry(); 00249 osg::Vec3Array* verts = new osg::Vec3Array(4); 00250 (*verts)[0].set( 0, 1, 0 ); 00251 (*verts)[1].set( 0, 0, 0 ); 00252 (*verts)[2].set( 1, 0, 0 ); 00253 (*verts)[3].set( 1, 1, 0 ); 00254 quad->setVertexArray( verts ); 00255 quad->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4 ) ); 00256 _maskColorArray = new osg::Vec4Array(1); 00257 (*_maskColorArray)[0] = osg::Vec4f(1,1,1,1); 00258 quad->setColorArray( _maskColorArray ); 00259 quad->setColorBinding( osg::Geometry::BIND_OVERALL ); 00260 osg::Geode* quad_geode = new osg::Geode(); 00261 quad_geode->addDrawable( quad ); 00262 00263 osg::StateSet* quad_ss = quad->getOrCreateStateSet(); 00264 quad_ss->setMode( GL_CULL_FACE, OFF_AND_PROTECTED ); 00265 quad_ss->setMode( GL_DEPTH_TEST, OFF_AND_PROTECTED ); 00266 quad_ss->setMode( GL_LIGHTING, OFF_AND_PROTECTED ); 00267 00268 osg::Stencil* quad_stencil = new osg::Stencil(); 00269 quad_stencil->setFunction( osg::Stencil::NOTEQUAL, 128, (unsigned int)~0 ); 00270 // this will conveniently re-clear the stencil buffer in prep for the next pass: 00271 quad_stencil->setOperation( osg::Stencil::REPLACE, osg::Stencil::REPLACE, osg::Stencil::REPLACE ); 00272 quad_ss->setAttributeAndModes( quad_stencil, ON_AND_PROTECTED ); 00273 00274 osg::MatrixTransform* abs = new osg::MatrixTransform(); 00275 abs->setReferenceFrame( osg::Transform::ABSOLUTE_RF ); 00276 abs->setMatrix( osg::Matrix::identity() ); 00277 abs->addChild( quad_geode ); 00278 00279 osg::Projection* proj = new osg::Projection(); 00280 proj->setMatrix( osg::Matrix::ortho(0, 1, 0, 1, 0, -1) ); 00281 proj->addChild( abs ); 00282 00283 _maskGroup->addChild( proj ); 00284 _maskGroup->getOrCreateStateSet()->setMode( GL_BLEND, 1 ); 00285 _maskGroup->getOrCreateStateSet()->setRenderBinDetails( baseBin++, "RenderBin" ); 00286 00287 this->addChild( _maskGroup ); 00288 } 00289 00290 00291 00292 //osg::Node* 00293 //StencilUtils::createGeometryPass( osg::Node* geometry, int& ref_renderBin ) 00294 //{ 00295 // // For now we are hard-coding these to what are hopefully "safe" values. 00296 // // In the future we hope to rewrite this as a custom StencilVolumeNode that 00297 // // will automatically detect extension availability at draw time and choose 00298 // // the optimal GL rendering path. 00299 // static bool s_EXT_stencil_wrap = true; //osg::isGLExtensionSupported(0, "GL_EXT_stencil_wrap"); 00300 // static bool s_EXT_stencil_two_side = false; //osg::isGLExtensionSupported(0, "GL_EXT_stencil_two_side"); 00301 // 00302 // // zFail=true if more compute intensive, but lets you get inside the volume. 00303 // // Again, a custom node will give us a better opportunity to choose between zFail and zPass based on 00304 // // the eye location (you only need zFail if you camera is inside the volume). 00305 // bool zFail = true; 00306 // 00307 // osg::Group* root = new osg::Group(); 00308 // 00309 // osg::notify(osg::INFO) << "[osgEarth] Stencil buffer wrap = " << s_EXT_stencil_wrap << std::endl; 00310 // 00311 // if ( s_EXT_stencil_two_side ) 00312 // { 00313 // osg::notify(osg::INFO) << "[osgEarth] Two-sided stenciling" << std::endl; 00314 // 00315 // osg::StencilTwoSided::Operation incrOp = s_EXT_stencil_wrap ? osg::StencilTwoSided::INCR_WRAP : osg::StencilTwoSided::INCR; 00316 // osg::StencilTwoSided::Operation decrOp = s_EXT_stencil_wrap ? osg::StencilTwoSided::DECR_WRAP : osg::StencilTwoSided::DECR; 00317 // osg::Group* stencil_group = new osg::Group(); 00318 // osg::StateSet* ss = stencil_group->getOrCreateStateSet(); 00319 // ss->setRenderBinDetails( ref_renderBin++, "RenderBin" ); 00320 // 00321 // if ( zFail ) 00322 // { 00323 // osg::StencilTwoSided* stencil = new osg::StencilTwoSided(); 00324 // stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS, 1, ~0u); 00325 // stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, incrOp, osg::StencilTwoSided::KEEP); 00326 // 00327 // stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS, 1, ~0u); 00328 // stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, decrOp, osg::StencilTwoSided::KEEP); 00329 // ss->setAttributeAndModes( stencil, ON_AND_PROTECTED ); 00330 // } 00331 // else 00332 // { 00333 // osg::StencilTwoSided* stencil = new osg::StencilTwoSided(); 00334 // stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS, 1, ~0u); 00335 // stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, incrOp); 00336 // 00337 // stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS, 1, ~0u); 00338 // stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, decrOp); 00339 // ss->setAttributeAndModes( stencil, ON_AND_PROTECTED ); 00340 // } 00341 // 00342 // ss->setAttributeAndModes(new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED); 00343 // ss->setAttributeAndModes(new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED); 00344 // stencil_group->addChild( geometry ); 00345 // 00346 // root->addChild( stencil_group ); 00347 // } 00348 // else 00349 // { 00350 // osg::notify(osg::INFO) << "[osgEarth] One-sided stenciling" << std::endl; 00351 // 00352 // if ( !zFail ) // Z-Pass 00353 // { 00354 // osg::Group* front_group = new osg::Group(); 00355 // osg::StateSet* front_ss = front_group->getOrCreateStateSet(); 00356 // front_ss->setRenderBinDetails( ref_renderBin++, "RenderBin" ); 00357 // 00358 // // incrementing stencil op for front faces: 00359 // osg::Stencil* front_stencil = new osg::Stencil(); 00360 // front_stencil->setFunction( osg::Stencil::ALWAYS, 1, ~0u ); 00361 // osg::Stencil::Operation incrOp = s_EXT_stencil_wrap ? osg::Stencil::INCR_WRAP : osg::Stencil::INCR; 00362 // front_stencil->setOperation( osg::Stencil::KEEP, osg::Stencil::KEEP, incrOp ); 00363 // front_ss->setAttributeAndModes( front_stencil, ON_AND_PROTECTED ); 00364 // 00365 // front_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED); 00366 // front_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::BACK), ON_AND_PROTECTED); 00367 // front_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED); 00368 // 00369 // front_group->addChild( geometry ); 00370 // root->addChild( front_group ); 00371 // 00372 // // decrementing stencil op for back faces: 00373 // osg::Group* back_group = new osg::Group(); 00374 // osg::StateSet* back_ss = back_group->getOrCreateStateSet(); 00375 // back_ss->setRenderBinDetails( ref_renderBin++, "RenderBin" ); 00376 // 00377 // osg::Stencil* back_stencil = new osg::Stencil(); 00378 // back_stencil->setFunction( osg::Stencil::ALWAYS, 1, ~0u ); 00379 // osg::Stencil::Operation decrOp = s_EXT_stencil_wrap ? osg::Stencil::DECR_WRAP : osg::Stencil::DECR; 00380 // back_stencil->setOperation( osg::Stencil::KEEP, osg::Stencil::KEEP, decrOp ); 00381 // back_ss->setAttributeAndModes( back_stencil, ON_AND_PROTECTED ); 00382 // 00383 // back_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED); 00384 // back_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::FRONT), ON_AND_PROTECTED); 00385 // back_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED); 00386 // 00387 // back_group->addChild( geometry ); 00388 // root->addChild( back_group ); 00389 // } 00390 // else 00391 // { 00392 // // incrementing stencil op for back faces: 00393 // { 00394 // osg::Group* front_group = new osg::Group(); 00395 // osg::StateSet* front_ss = front_group->getOrCreateStateSet(); 00396 // front_ss->setRenderBinDetails( ref_renderBin++, "RenderBin" ); 00397 // 00398 // osg::Stencil* front_stencil = new osg::Stencil(); 00399 // front_stencil->setFunction( osg::Stencil::ALWAYS ); //, 1, ~0u ); 00400 // osg::Stencil::Operation incrOp = s_EXT_stencil_wrap ? osg::Stencil::INCR_WRAP : osg::Stencil::INCR; 00401 // front_stencil->setOperation( osg::Stencil::KEEP, incrOp, osg::Stencil::KEEP ); 00402 // front_ss->setAttributeAndModes( front_stencil, ON_AND_PROTECTED ); 00403 // 00404 // front_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED); 00405 // front_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::FRONT), ON_AND_PROTECTED); 00406 // front_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED); 00407 // 00408 // front_group->addChild( geometry ); 00409 // root->addChild( front_group ); 00410 // } 00411 // 00412 // // decrementing stencil buf for front faces 00413 // { 00414 // osg::Group* back_group = new osg::Group(); 00415 // osg::StateSet* back_ss = back_group->getOrCreateStateSet(); 00416 // back_ss->setRenderBinDetails( ref_renderBin++, "RenderBin" ); 00417 // 00418 // osg::Stencil* back_stencil = new osg::Stencil(); 00419 // back_stencil->setFunction( osg::Stencil::ALWAYS ); //, 1, ~0u ); 00420 // osg::Stencil::Operation decrOp = s_EXT_stencil_wrap ? osg::Stencil::DECR_WRAP : osg::Stencil::DECR; 00421 // back_stencil->setOperation( osg::Stencil::KEEP, decrOp, osg::Stencil::KEEP ); 00422 // back_ss->setAttributeAndModes( back_stencil, ON_AND_PROTECTED ); 00423 // 00424 // back_ss->setAttributeAndModes( new osg::ColorMask(false,false,false,false), ON_AND_PROTECTED); 00425 // back_ss->setAttributeAndModes( new osg::CullFace(osg::CullFace::BACK), ON_AND_PROTECTED); 00426 // back_ss->setAttributeAndModes( new osg::Depth(osg::Depth::LESS,0,1,false), ON_AND_PROTECTED); 00427 // 00428 // back_group->addChild( geometry ); 00429 // root->addChild( back_group ); 00430 // } 00431 // } 00432 // } 00433 // 00434 // return root; 00435 //} 00436 // 00437 //osg::Node* 00438 //StencilUtils::createMaskPass( const osg::Vec4ub& color, int& ref_renderBin ) 00439 //{ 00440 // osg::Group* result = new osg::Group(); 00441 // 00442 // // make a full screen quad: 00443 // osg::Geometry* quad = new osg::Geometry(); 00444 // osg::Vec3Array* verts = new osg::Vec3Array(4); 00445 // (*verts)[0].set( 0, 1, 0 ); 00446 // (*verts)[1].set( 0, 0, 0 ); 00447 // (*verts)[2].set( 1, 0, 0 ); 00448 // (*verts)[3].set( 1, 1, 0 ); 00449 // quad->setVertexArray( verts ); 00450 // quad->addPrimitiveSet( new osg::DrawArrays( osg::PrimitiveSet::QUADS, 0, 4 ) ); 00451 // osg::Vec4ubArray* maskColorArray = new osg::Vec4ubArray(1); 00452 // (*maskColorArray)[0] = color; 00453 // quad->setColorArray( maskColorArray ); 00454 // quad->setColorBinding( osg::Geometry::BIND_OVERALL ); 00455 // osg::Geode* quad_geode = new osg::Geode(); 00456 // quad_geode->addDrawable( quad ); 00457 // 00458 // osg::StateSet* quad_ss = quad->getOrCreateStateSet(); 00459 // quad_ss->setRenderBinDetails( ref_renderBin++, "RenderBin" ); 00460 // quad_ss->setMode( GL_CULL_FACE, OFF_AND_PROTECTED ); 00461 // quad_ss->setMode( GL_DEPTH_TEST, OFF_AND_PROTECTED ); 00462 // quad_ss->setMode( GL_LIGHTING, OFF_AND_PROTECTED ); 00463 // 00464 // osg::Stencil* quad_stencil = new osg::Stencil(); 00465 // quad_stencil->setFunction( osg::Stencil::NOTEQUAL, 128, (unsigned int)~0 ); 00466 // // this will conveniently re-clear the stencil buffer in prep for the next pass: 00467 // quad_stencil->setOperation( osg::Stencil::REPLACE, osg::Stencil::REPLACE, osg::Stencil::REPLACE ); 00468 // quad_ss->setAttributeAndModes( quad_stencil, ON_AND_PROTECTED ); 00469 // 00470 // osg::MatrixTransform* abs = new osg::MatrixTransform(); 00471 // abs->setReferenceFrame( osg::Transform::ABSOLUTE_RF ); 00472 // abs->setMatrix( osg::Matrix::identity() ); 00473 // abs->addChild( quad_geode ); 00474 // 00475 // osg::Projection* proj = new osg::Projection(); 00476 // proj->setMatrix( osg::Matrix::ortho(0, 1, 0, 1, 0, -1) ); 00477 // proj->addChild( abs ); 00478 // 00479 // result->addChild( proj ); 00480 // result->getOrCreateStateSet()->setMode( GL_BLEND, 1 ); 00481 // return result; 00482 //} 00483 00484 00485 static 00486 void tessellate( osg::Geometry* geom ) 00487 { 00488 osgUtil::Tessellator tess; 00489 tess.setTessellationType( osgUtil::Tessellator::TESS_TYPE_GEOMETRY ); 00490 tess.setWindingType( osgUtil::Tessellator::TESS_WINDING_ODD ); 00491 // tess.setWindingType( osgUtil::Tessellator::TESS_WINDING_POSITIVE ); 00492 tess.retessellatePolygons( *geom ); 00493 } 00494 00495 osg::Geode* 00496 StencilUtils::createVolume(Geometry* geom, 00497 double offset, 00498 double height, 00499 const FilterContext& context ) 00500 { 00501 if ( !geom ) return 0L; 00502 00503 int numRings = 0; 00504 00505 // start by offsetting the input data. 00506 if ( offset != 0.0 ) 00507 { 00508 GeometryIterator i( geom ); 00509 i.traverseMultiGeometry() = true; 00510 i.traversePolygonHoles() = true; 00511 while( i.hasMore() ) 00512 { 00513 Geometry* part = i.next(); 00514 for( osg::Vec3dArray::iterator j = part->begin(); j != part->end(); j++ ) 00515 { 00516 if ( context.isGeocentric() ) 00517 { 00518 osg::Vec3d world = context.toWorld( *j ); 00519 // TODO: get the proper up vector; this is spherical.. or does it really matter for 00520 // stencil volumes? 00521 osg::Vec3d offset_vec = world; 00522 offset_vec.normalize(); 00523 *j = context.toLocal( world + offset_vec * offset ); //(*j) += offset_vec * offset; 00524 } 00525 else 00526 { 00527 (*j).z() += offset; 00528 } 00529 } 00530 00531 // in the meantime, count the # of closed geoms. We will need to know this in 00532 // order to pre-allocate the proper # of verts. 00533 if ( part->getType() == Geometry::TYPE_POLYGON || part->getType() == Geometry::TYPE_RING ) 00534 { 00535 numRings++; 00536 } 00537 } 00538 } 00539 00540 // now, go thru and remove any coplanar segments from the geometry. The tesselator will 00541 // not work include a vert connecting two colinear segments in the tesselation, and this 00542 // will break the stenciling logic. 00543 #define PARALLEL_EPSILON 0.01 00544 GeometryIterator i( geom ); 00545 i.traverseMultiGeometry() = true; 00546 i.traversePolygonHoles() = true; 00547 while( i.hasMore() ) 00548 { 00549 Geometry* part = i.next(); 00550 if ( part->size() >= 3 ) 00551 { 00552 osg::Vec3d prevVec = part->front() - part->back(); 00553 prevVec.normalize(); 00554 00555 for( osg::Vec3dArray::iterator j = part->begin(); part->size() >= 3 && j != part->end(); ) 00556 { 00557 osg::Vec3d& p0 = *j; 00558 osg::Vec3d& p1 = j+1 != part->end() ? *(j+1) : part->front(); 00559 osg::Vec3d vec = p1-p0; vec.normalize(); 00560 00561 // if the vectors are essentially parallel, remove the extraneous vertex. 00562 if ( (prevVec ^ vec).length() < PARALLEL_EPSILON ) 00563 { 00564 j = part->erase( j ); 00565 //osg::notify(osg::NOTICE) << "[osgEarth] removed colinear segment" << std::endl; 00566 } 00567 else 00568 { 00569 ++j; 00570 prevVec = vec; 00571 } 00572 } 00573 } 00574 } 00575 00576 00577 bool made_geom = true; 00578 const SpatialReference* srs = context.profile()->getSRS(); 00579 00580 // total up all the points so we can pre-allocate the vertex arrays. 00581 int num_cap_verts = geom->getTotalPointCount(); 00582 int num_wall_verts = 2 * (num_cap_verts + numRings); // add in numRings b/c we need to close each wall 00583 00584 osg::Geometry* walls = new osg::Geometry(); 00585 osg::Vec3Array* verts = new osg::Vec3Array( num_wall_verts ); 00586 walls->setVertexArray( verts ); 00587 00588 osg::Geometry* top_cap = new osg::Geometry(); 00589 osg::Vec3Array* top_verts = new osg::Vec3Array( num_cap_verts ); 00590 top_cap->setVertexArray( top_verts ); 00591 00592 osg::Geometry* bottom_cap = new osg::Geometry(); 00593 osg::Vec3Array* bottom_verts = new osg::Vec3Array( num_cap_verts ); 00594 bottom_cap->setVertexArray( bottom_verts ); 00595 00596 int wall_vert_ptr = 0; 00597 int top_vert_ptr = 0; 00598 int bottom_vert_ptr = 0; 00599 00600 //double target_len = height; 00601 00602 // now generate the extruded geometry. 00603 GeometryIterator k( geom ); 00604 while( k.hasMore() ) 00605 { 00606 Geometry* part = k.next(); 00607 00608 unsigned int wall_part_ptr = wall_vert_ptr; 00609 unsigned int top_part_ptr = top_vert_ptr; 00610 unsigned int bottom_part_ptr = bottom_vert_ptr; 00611 double part_len = 0.0; 00612 00613 GLenum prim_type = part->getType() == Geometry::TYPE_POINTSET ? GL_LINES : GL_TRIANGLE_STRIP; 00614 00615 for( osg::Vec3dArray::const_iterator m = part->begin(); m != part->end(); ++m ) 00616 { 00617 osg::Vec3d extrude_vec; 00618 00619 if ( srs ) 00620 { 00621 osg::Vec3d m_world = context.toWorld( *m ); //*m * context.inverseReferenceFrame(); 00622 if ( context.isGeocentric() ) 00623 { 00624 osg::Vec3d p_vec = m_world; // todo: not exactly right; spherical 00625 00626 osg::Vec3d unit_vec = p_vec; 00627 unit_vec.normalize(); 00628 p_vec = p_vec + unit_vec*height; 00629 00630 extrude_vec = context.toLocal( p_vec ); //p_vec * context.referenceFrame(); 00631 } 00632 else 00633 { 00634 extrude_vec.set( m_world.x(), m_world.y(), height ); 00635 extrude_vec = context.toLocal( extrude_vec ); //extrude_vec * context.referenceFrame(); 00636 } 00637 } 00638 else 00639 { 00640 extrude_vec.set( m->x(), m->y(), height ); 00641 } 00642 00643 (*top_verts)[top_vert_ptr++] = extrude_vec; 00644 (*bottom_verts)[bottom_vert_ptr++] = *m; 00645 00646 part_len += wall_vert_ptr > wall_part_ptr? 00647 (extrude_vec - (*verts)[wall_vert_ptr-2]).length() : 00648 0.0; 00649 00650 int p; 00651 00652 p = wall_vert_ptr++; 00653 (*verts)[p] = extrude_vec; 00654 00655 p = wall_vert_ptr++; 00656 (*verts)[p] = *m; 00657 } 00658 00659 // close the wall if it's a ring/poly: 00660 if ( part->getType() == Geometry::TYPE_RING || part->getType() == Geometry::TYPE_POLYGON ) 00661 { 00662 part_len += wall_vert_ptr > wall_part_ptr? 00663 ((*verts)[wall_part_ptr] - (*verts)[wall_vert_ptr-2]).length() : 00664 0.0; 00665 00666 int p; 00667 00668 p = wall_vert_ptr++; 00669 (*verts)[p] = (*verts)[wall_part_ptr]; 00670 00671 p = wall_vert_ptr++; 00672 (*verts)[p] = (*verts)[wall_part_ptr+1]; 00673 } 00674 00675 walls->addPrimitiveSet( new osg::DrawArrays( 00676 prim_type, 00677 wall_part_ptr, wall_vert_ptr - wall_part_ptr ) ); 00678 00679 top_cap->addPrimitiveSet( new osg::DrawArrays( 00680 osg::PrimitiveSet::LINE_LOOP, 00681 top_part_ptr, top_vert_ptr - top_part_ptr ) ); 00682 00683 // reverse the bottom verts so the front face is down: 00684 std::reverse( bottom_verts->begin()+bottom_part_ptr, bottom_verts->begin()+bottom_vert_ptr ); 00685 00686 bottom_cap->addPrimitiveSet( new osg::DrawArrays( 00687 osg::PrimitiveSet::LINE_LOOP, 00688 bottom_part_ptr, bottom_vert_ptr - bottom_part_ptr ) ); 00689 } 00690 00691 // build solid surfaces for the caps: 00692 tessellate( top_cap ); 00693 tessellate( bottom_cap ); 00694 00695 osg::Geode* geode = new osg::Geode(); 00696 geode->addDrawable( walls ); 00697 geode->addDrawable( top_cap ); 00698 geode->addDrawable( bottom_cap ); 00699 00700 return geode; 00701 }