osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthDrivers/model_feature_stencil/StencilUtils.cpp

Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines