osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarth/TerrainEngineNode.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 <osgEarth/TerrainEngineNode>
00020 #include <osgEarth/Capabilities>
00021 #include <osgEarth/Registry>
00022 #include <osgEarth/FindNode>
00023 #include <osgEarth/TextureCompositor>
00024 #include <osgDB/ReadFile>
00025 #include <osg/CullFace>
00026 #include <osg/PolygonOffset>
00027 
00028 #define LC "[TerrainEngineNode] "
00029 
00030 using namespace osgEarth;
00031 
00032 //------------------------------------------------------------------------
00033 
00034 namespace osgEarth
00035 {
00036     struct TerrainEngineNodeCallbackProxy : public MapCallback
00037     {
00038         TerrainEngineNodeCallbackProxy(TerrainEngineNode* node) : _node(node) { }
00039         osg::observer_ptr<TerrainEngineNode> _node;
00040 
00041         void onMapInfoEstablished( const MapInfo& mapInfo )
00042         {
00043             osg::ref_ptr<TerrainEngineNode> safeNode = _node.get();
00044             if ( safeNode.valid() )
00045                 safeNode->onMapInfoEstablished( mapInfo );
00046         }
00047 
00048         void onMapModelChanged( const MapModelChange& change )
00049         {
00050             osg::ref_ptr<TerrainEngineNode> safeNode = _node.get();
00051             if ( safeNode.valid() )
00052                 safeNode->onMapModelChanged( change );
00053         }
00054     };
00055 }
00056 
00057 //------------------------------------------------------------------------
00058 
00059 TerrainEngineNode::ImageLayerController::ImageLayerController( const Map* map ) :
00060 _mapf( map, Map::IMAGE_LAYERS, "TerrainEngineNode.ImageLayerController" )
00061 {
00062     //nop
00063 }
00064 
00065 // this handler adjusts the uniform set when a terrain layer's "enabed" state changes
00066 void
00067 TerrainEngineNode::ImageLayerController::onEnabledChanged( TerrainLayer* layer )
00068 {
00069     if ( !Registry::instance()->getCapabilities().supportsGLSL() )
00070         return;
00071 
00072     _mapf.sync();
00073     int layerNum = _mapf.indexOf( static_cast<ImageLayer*>(layer) );
00074     if ( layerNum >= 0 )
00075         _layerEnabledUniform.setElement( layerNum, layer->getEnabled() );
00076     else
00077         OE_WARN << LC << "Odd, updateLayerOpacity did not find layer" << std::endl;
00078 }
00079 
00080 TerrainEngineNode::~TerrainEngineNode()
00081 {
00082     //Remove any callbacks added to the image layers
00083     if (_map.valid())
00084     {
00085         MapFrame mapf( _map.get(), Map::IMAGE_LAYERS, "TerrainEngineNode::~TerrainEngineNode" );
00086         for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
00087         {
00088             i->get()->removeCallback( _imageLayerController.get() );
00089         }
00090     }
00091 
00092 
00093 }
00094 
00095 // this handler adjusts the uniform set when a terrain layer's "opacity" value changes
00096 void
00097 TerrainEngineNode::ImageLayerController::onOpacityChanged( ImageLayer* layer )
00098 {
00099     if ( !Registry::instance()->getCapabilities().supportsGLSL() )
00100         return;
00101 
00102     _mapf.sync();
00103     int layerNum = _mapf.indexOf( layer );
00104     if ( layerNum >= 0 )
00105         _layerOpacityUniform.setElement( layerNum, layer->getOpacity() );
00106     else
00107         OE_WARN << LC << "Odd, onOpacityChanged did not find layer" << std::endl;
00108 }
00109 
00110 //------------------------------------------------------------------------
00111 
00112 TerrainEngineNode::TerrainEngineNode() :
00113 _verticalScale( 1.0f ),
00114 _elevationSamplingRatio( 1.0f ),
00115 _initStage( INIT_NONE )
00116 {
00117     //nop
00118 }
00119 
00120 TerrainEngineNode::TerrainEngineNode( const TerrainEngineNode& rhs, const osg::CopyOp& op ) :
00121 osg::CoordinateSystemNode( rhs, op ),
00122 _verticalScale( rhs._verticalScale ),
00123 _elevationSamplingRatio( rhs._elevationSamplingRatio ),
00124 _map( rhs._map.get() ),
00125 _initStage( rhs._initStage )
00126 {
00127     //nop
00128 }
00129 
00130 void
00131 TerrainEngineNode::preInitialize( const Map* map, const TerrainOptions& options )
00132 {
00133     _map = map;
00134 
00135     // set up the CSN values   
00136     _map->getProfile()->getSRS()->populateCoordinateSystemNode( this );
00137     
00138     // OSG's CSN likes a NULL ellipsoid to represent projected mode.
00139     if ( !_map->isGeocentric() )
00140         this->setEllipsoidModel( NULL );
00141     
00142     // install the proper layer composition technique:
00143     _texCompositor = new TextureCompositor( options );
00144 
00145     // prime the compositor with pre-existing image layers:
00146     MapFrame mapf(map, Map::IMAGE_LAYERS);
00147     for( unsigned i=0; i<mapf.imageLayers().size(); ++i )
00148     {
00149         _texCompositor->applyMapModelChange( MapModelChange(
00150             MapModelChange::ADD_IMAGE_LAYER,
00151             mapf.getRevision(),
00152             mapf.getImageLayerAt(i),
00153             i ) );
00154     }
00155 
00156     // then register the callback so we can process further map model changes
00157     _map->addMapCallback( new TerrainEngineNodeCallbackProxy( this ) );
00158 
00159     // enable backface culling
00160     osg::StateSet* set = getOrCreateStateSet();
00161     set->setAttributeAndModes( new osg::CullFace( osg::CullFace::BACK ), osg::StateAttribute::ON );
00162 
00163     // elevation uniform
00164     _cameraElevationUniform = new osg::Uniform( osg::Uniform::FLOAT, "osgearth_CameraElevation" );
00165     _cameraElevationUniform->set( 0.0f );
00166     set->addUniform( _cameraElevationUniform.get() );
00167     
00168     set->getOrCreateUniform( "osgearth_ImageLayerAttenuation", osg::Uniform::FLOAT )->set(
00169         *options.attentuationDistance() );
00170 
00171     _initStage = INIT_PREINIT_COMPLETE;
00172 }
00173 
00174 void
00175 TerrainEngineNode::postInitialize( const Map* map, const TerrainOptions& options )
00176 {
00177     if ( _map.valid() ) // i think this is always true [gw]
00178     {
00179         // manually trigger the map callbacks the first time:
00180         if ( _map->getProfile() )
00181             onMapInfoEstablished( MapInfo(_map.get()) );
00182 
00183         // create a layer controller. This object affects the uniforms that control layer appearance properties
00184         _imageLayerController = new ImageLayerController( _map.get() );
00185 
00186         // register the layer Controller it with all pre-existing image layers:
00187         MapFrame mapf( _map.get(), Map::IMAGE_LAYERS, "TerrainEngineNode::initialize" );
00188         for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
00189         {
00190             i->get()->addCallback( _imageLayerController.get() );
00191         }
00192 
00193         updateImageUniforms();
00194 
00195         // then register the callback
00196         // NOTE: moved this into preInitialize
00197         //_map->addMapCallback( new TerrainEngineNodeCallbackProxy( this ) );
00198     }
00199 
00200     _initStage = INIT_POSTINIT_COMPLETE;
00201 }
00202 
00203 osg::BoundingSphere
00204 TerrainEngineNode::computeBound() const
00205 {
00206     if ( getEllipsoidModel() )
00207     {
00208         return osg::BoundingSphere( osg::Vec3(0,0,0), getEllipsoidModel()->getRadiusEquator()+25000 );
00209     }
00210     else
00211     {
00212         return osg::CoordinateSystemNode::computeBound();
00213     }
00214 }
00215 
00216 void
00217 TerrainEngineNode::setVerticalScale( float value )
00218 {
00219     _verticalScale = value;
00220     onVerticalScaleChanged();
00221 }
00222 
00223 void
00224 TerrainEngineNode::setElevationSamplingRatio( float value )
00225 {
00226     _elevationSamplingRatio = value;
00227     onElevationSamplingRatioChanged();
00228 }
00229 
00230 void
00231 TerrainEngineNode::onMapInfoEstablished( const MapInfo& mapInfo )
00232 {
00233     // set up the CSN values   
00234     mapInfo.getProfile()->getSRS()->populateCoordinateSystemNode( this );
00235     
00236     // OSG's CSN likes a NULL ellipsoid to represent projected mode.
00237     if ( !mapInfo.isGeocentric() )
00238         this->setEllipsoidModel( NULL );
00239 }
00240 
00241 void
00242 TerrainEngineNode::onMapModelChanged( const MapModelChange& change )
00243 {
00244     if ( _initStage == INIT_POSTINIT_COMPLETE )
00245     {
00246         if ( change.getAction() == MapModelChange::ADD_IMAGE_LAYER )
00247         {
00248             change.getImageLayer()->addCallback( _imageLayerController.get() );
00249         }
00250         else if ( change.getAction() == MapModelChange::REMOVE_IMAGE_LAYER )
00251         {
00252             change.getImageLayer()->removeCallback( _imageLayerController.get() );
00253         }
00254 
00255         if (change.getAction() == MapModelChange::ADD_IMAGE_LAYER ||
00256             change.getAction() == MapModelChange::REMOVE_IMAGE_LAYER ||
00257             change.getAction() == MapModelChange::MOVE_IMAGE_LAYER )
00258         {
00259             updateImageUniforms();
00260         }
00261     }
00262 
00263     // if post-initialization has not yet happened, we need to make sure the 
00264     // compositor is up to date with the map model. (After post-initialization,
00265     // this happens in the subclass...something that probably needs to change
00266     // since this is unclear)
00267     else if ( _texCompositor.valid() )
00268     {
00269         _texCompositor->applyMapModelChange( change );
00270     }
00271 }
00272 
00273 void
00274 TerrainEngineNode::updateImageUniforms()
00275 {
00276     // don't bother if this is a hurting old card
00277     if ( !Registry::instance()->getCapabilities().supportsGLSL() )
00278         return;
00279 
00280     // update the layer uniform arrays:
00281     osg::StateSet* stateSet = this->getOrCreateStateSet();
00282 
00283     // get a copy of the image layer stack:
00284     MapFrame mapf( _map.get(), Map::IMAGE_LAYERS );
00285 
00286     _imageLayerController->_layerEnabledUniform.detach();
00287     _imageLayerController->_layerOpacityUniform.detach();
00288     _imageLayerController->_layerRangeUniform.detach();
00289 
00290 #if 0
00291     if ( _imageLayerController->_layerEnabledUniform.valid() )
00292         _imageLayerController->_layerEnabledUniform->removeFrom( stateSet );
00293 
00294     if ( _imageLayerController->_layerOpacityUniform.valid() )
00295         _imageLayerController->_layerOpacityUniform->removeFrom( stateSet );
00296 
00297     if ( _imageLayerController->_layerRangeUniform.valid() )
00298         _imageLayerController->_layerRangeUniform->removeFrom( stateSet );
00299 #endif
00300 
00301     //stateSet->removeUniform( "osgearth_ImageLayerAttenuation" );
00302     
00303     if ( mapf.imageLayers().size() > 0 )
00304     {
00305         // the "enabled" uniform is fixed size. this is handy to account for layers that are in flux...i.e., their source
00306         // layer count has changed, but the shader has not yet caught up. In the future we might use this to disable
00307         // "ghost" layers that used to exist at a given index, but no longer do.
00308         
00309         _imageLayerController->_layerEnabledUniform.attach( "osgearth_ImageLayerEnabled", osg::Uniform::BOOL,  stateSet, 16 );
00310         _imageLayerController->_layerOpacityUniform.attach( "osgearth_ImageLayerOpacity", osg::Uniform::FLOAT, stateSet, mapf.imageLayers().size() );
00311         _imageLayerController->_layerRangeUniform.attach  ( "osgearth_ImageLayerRange",   osg::Uniform::FLOAT, stateSet, 2 * mapf.imageLayers().size() );
00312 
00313         //_imageLayerController->_layerEnabledUniform  = new ArrayUniform( osg::Uniform::BOOL,  "osgearth_ImageLayerEnabled", 64 ); //mapf.imageLayers().size() );
00314         //_imageLayerController->_layerOpacityUniform  = new ArrayUniform( osg::Uniform::FLOAT, "osgearth_ImageLayerOpacity", mapf.imageLayers().size() );
00315         //_imageLayerController->_layerRangeUniform    = new ArrayUniform( osg::Uniform::FLOAT, "osgearth_ImageLayerRange", 2 * mapf.imageLayers().size() );
00316 
00317         for( ImageLayerVector::const_iterator i = mapf.imageLayers().begin(); i != mapf.imageLayers().end(); ++i )
00318         {
00319             ImageLayer* layer = i->get();
00320             int index = (int)(i - mapf.imageLayers().begin());
00321 
00322             _imageLayerController->_layerOpacityUniform.setElement( index, layer->getOpacity() );
00323             _imageLayerController->_layerEnabledUniform.setElement( index, layer->getEnabled() );
00324             _imageLayerController->_layerRangeUniform.setElement( (2*index), layer->getImageLayerOptions().minVisibleRange().value() );
00325             _imageLayerController->_layerRangeUniform.setElement( (2*index)+1, layer->getImageLayerOptions().maxVisibleRange().value() );
00326         }
00327 
00328         // set the remainder of the layers to disabled 
00329         for( int j=mapf.imageLayers().size(); j<64; ++j )
00330             _imageLayerController->_layerEnabledUniform.setElement( j, false );
00331 
00332         //_imageLayerController->_layerOpacityUniform->addTo( stateSet );
00333         //_imageLayerController->_layerEnabledUniform->addTo( stateSet );
00334         //_imageLayerController->_layerRangeUniform->addTo( stateSet );
00335     }
00336 }
00337 
00338 void
00339 TerrainEngineNode::validateTerrainOptions( TerrainOptions& options )
00340 {
00341     // make sure all the requested properties are compatible, and fall back as necessary.
00342     //const Capabilities& caps = Registry::instance()->getCapabilities();
00343 
00344     // warn against mixing multipass technique with preemptive/sequential mode:
00345     if (options.compositingTechnique() == TerrainOptions::COMPOSITING_MULTIPASS &&
00346         options.loadingPolicy()->mode() != LoadingPolicy::MODE_STANDARD )
00347     {
00348         OE_WARN << LC << "MULTIPASS compositor is incompatible with preemptive/sequential loading policy; "
00349             << "falling back on STANDARD mode" << std::endl;
00350         options.loadingPolicy()->mode() = LoadingPolicy::MODE_STANDARD;
00351     }
00352 }
00353 
00354 void
00355 TerrainEngineNode::traverse( osg::NodeVisitor& nv )
00356 {
00357     if ( nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR )
00358     {
00359         if ( Registry::instance()->getCapabilities().supportsGLSL() )
00360         {
00361             _updateLightingUniformsHelper.cullTraverse( this, &nv );
00362 
00363             osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>( &nv );
00364             if ( cv )
00365             {
00366                 osg::Vec3d eye = cv->getEyePoint();
00367 
00368                 float elevation;
00369                 if ( _map->isGeocentric() )
00370                     elevation = eye.length() - osg::WGS_84_RADIUS_EQUATOR;
00371                 else
00372                     elevation = eye.z();
00373 
00374                 _cameraElevationUniform->set( elevation );
00375             }
00376         }
00377     }
00378 
00379     //else if ( nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR )
00380     //{
00381     //    if ( Registry::instance()->getCapabilities().supportsGLSL() )
00382     //        _updateLightingUniformsHelper.updateTraverse( this );
00383     //}
00384 
00385     osg::CoordinateSystemNode::traverse( nv );
00386 }
00387 
00388 //------------------------------------------------------------------------
00389 
00390 #undef LC
00391 #define LC "[TerrainEngineFactory] "
00392 
00393 TerrainEngineNode*
00394 TerrainEngineNodeFactory::create( Map* map, const TerrainOptions& options )
00395 {
00396     TerrainEngineNode* result = 0L;
00397 
00398     std::string driver = options.getDriver();
00399     if ( driver.empty() )
00400         driver = "osgterrain";
00401 
00402     std::string driverExt = std::string( ".osgearth_engine_" ) + driver;
00403     result = dynamic_cast<TerrainEngineNode*>( osgDB::readObjectFile( driverExt ) );
00404     if ( result )
00405     {
00406         TerrainOptions terrainOptions( options );
00407         result->validateTerrainOptions( terrainOptions );
00408         //result->initialize( map, terrainOptions );
00409     }
00410     else
00411     {
00412         OE_WARN << "WARNING: Failed to load terrain engine driver for \"" << driver << "\"" << std::endl;
00413     }
00414 
00415     return result;
00416 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines