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