osgEarth数据加载及组织解析 联系客服

发布时间 : 星期五 文章osgEarth数据加载及组织解析更新完毕开始阅读2c81f29fec3a87c24028c4a2

第二步便是在osgviewer开始渲染,创建漫游,相机开始添加场景时,进行后续的添加,并使用TileKey管理构建四叉树组织。此时根据视点范围及距离,通过OSG的PagedLOD分页机制,动态调度选择加载区域瓦片节点。关于数据如何按四叉树进行组织,分页LOD如何动态调度选择加载数据将在后文进行详细解读。此处主要关注构建mapNode的流程和最后mapNode的逻辑节点树。如图3.7所示。

创建地形节点创建第一层TileKey创建根节点以分页lod加入瓦片模型影像图层:以设置纹理贴图创建瓦片模型高程图层图3.7 构建mapNode第二步逻辑

下面便来解读每一步的详细流程。

地形引擎需要一个Container来设置光照状态,而不能直接在引擎上来设置_terrainEngineContainer = new osg::Group();_terrainEngineContainer->setDataVariance( osg::Object::DYNAMIC );this->addChild( _terrainEngineContainer.get() );MapNode.cpp_terrainInterface = new Terrain( this, map->getProfile(), map->isGeocentric() );开启一个地形功能界面_map->getProfile()->getSRS()->populateCoordinateSystemNode( this );根据_map的空间参考坐标系设置的TerrainEngineNode的坐标系和椭球模型,其中WKT及PROJ4等有默认值开始只是球体与底图显示,所以此时只用添加底图MapFrame mapf(map, Map::IMAGE_LAYERS);_texCompositor->applyMapModelChange( MapModelChange( MapModelChange::ADD_IMAGE_LAYER, mapf.getRevision(), mapf.getImageLayerAt(i), i ) );首先加入事先存在的影像图层,即底图,此处调用image的driver进行加载数据,主要是因为在applymapModelChange函数中,首先getProfile,因影像先未进行初始化,故需调用相应driver去读取数据信息,获取其profile。// 创建模型节点:_models = new osg::Group();_models->setName( \addChild( _models.get() );// 创建overlay模型节点:_overlayModels = new osg::Group();_overlayModels->setName( \ // 创建overlay models decorator_overlayDecorator = new OverlayDecorator();addTerrainDecorator( _overlayDecorator.get() ); // 加载预先存在的模型图层ModelLayerVector modelLayers;_map->getModelLayers( modelLayers );for(){ onModelLayerAdded( k_>get(), modelLayerIndex };_mapCallback = new MapNodeMapCallbackProxy(this); // 注册MapNodeMapCallback回调函数_map->addMapCallback( _mapCallback.get() );获取状态设置属性和模式MapNode.cpposgearth::MapNode : public osg::Grouposg::Group()地形节点_map->addMapCallback( new TerrainEngineNodeCallbackProxy( this ) )注册回调函数,这样就够处理map模型改变的事件开启背面剔除获取状态设置属性和模式增加Uniform cameraElevationUniform获取Osgearth_ImageLayerAttenuation 并设置TerrainEngineNode.cpp osgEarth:MPTerrainEngineNode******osg::Group()osg::Group()模型节点Overlay模型节点此时MapNode节点结构

图3.8 构建mapNode第一步详细流程

图3.8展示的是构建mapNode第一步的详细流程,最后生成包含了地形节点、模型节点和overlay模型节点的子树。其中,在根据map的空间参考坐标系设置TerrainEngineNode的坐标系和椭球模型时,map对象有获取profile属性。Profile是确定数据的空间信息重要属性,其如何确定数据的空间信息将在后文进行详细说明。若map对象的options中没有设置profile,默认将其中的SRS(空间参考系)设置为WGS84坐标系。

实质调用createTerrain()if (_tileModelFactory) _tileModelFactory->getHeightFieldCache()->clear();_terrain = new TerrainNode( _deadTiles.get() ); this->addChild( _terrain );创建地形的第一层(LOD为0)收集包括地形根瓦片的tile keysstd::vector< TileKey > keys; _update_mapf->getProfile()->getAllKeysAtLOD( *_terrainOptions.firstLOD(), keys )osg::Node* node = factory->createRootNode( keys[i] )If(node) _terrain->addChild(node);为每个root tile key创建一个root节点,在其中读取具体影像与高程,并放置在正确的位置osgearth::MapNode : public osg::Grouposg::Group()地形节点osgEarth:MPTerrainEngineNodeTerrainNodeRootNode(TileNodeGroup)……osg::Group()osg::Group()模型节点Overlay模型节点此时MapNode节点结构MPTerrainEngineNode.cpp图3.9 构建mapNode第二步详细流程

图3.9展示的是构建mapNode第二步详细流程。此处只挑出了重点的函数,主要创建了第一层的TileKey和根节点。每个rootNode包含四叉树索引组织的key,包括范围信息等,然后还包含这块范围的各种数据,所以,创建根节点的createRootNode将是我们下面分析的重点。

确定空间位置并配置其TIleKey创建瓦片模型读取影像,创建纹理贴图读取高程 创建根节点以pagedLOD形式将模型加入根节点

图3.10 创建根节点的逻辑流程

图3.10展示的是创建根节点的逻辑流程。由图可知,归纳为做了两件事,第一件即创建了包含影像图层、高程图层及TileKey的瓦片模型,第二件事是将这个模型以PagedLOD形式加入根节点。其中TileKey包含模型的空间信息,能正确确定数据在三维球上的正确位置,且以四叉树形式被组织起来。PagedLOD即分页LOD,能根据视点范围动态选择加载哪些节点。这两个技术将在后文详细解读。

createRootNode(const TileKey& key)_modelFactory->createTileModle(key,model,real,lodBlending)real指是否含有real data(real data指直接关联到key的数据,相反的称为fallback data,从低一级的LOD key中衍伸的数据),lodBlending指是否含有lodBending一个瓦片节点group必须只能放一个单独的瓦片osg::Group* root = new TileNodeGroup();addTile( model.get(), real, lodBlending, root );return root;SerialKeyNodeFactory.cppreturn root;SerialKeyNodeFactory.cpposgearth::MapNode : public osg::Grouposg::Group()地形节点MapFrame mapf( _map, Map::MASKED_TERRAIN_LAYERS ); const MapInfo& mapInfo = mapf.getMapInfo();osg::ref_ptr model = new TileModel();model->_map = _map;model->_tileKey = key;model->_tileLocator = GeoLocator::createForKey(key, mapInfo);BuildColorData build;build.init( key, layer, order, mapInfo, _terrainOptions, model.get() );bool addedToModel = build.execute();BuildElevationData build;build.init( key, mapf, _terrainOptions, model.get(), _hfCache );build.execute();osgEarth:MPTerrainEngineNodeTerrainNodeosg::PagedLODRootNode(TileNodeGroup)ColorLayerElevationLayerosg::Group()osg::Group()模型节点Overlay模型节点此时MapNode节点结构execute()返回一个bool,实际创建图片加载上图层读取高程,并构建四叉树的key核心函数与image相同,此处可以好好分析key如何分层.其中execute无返回TileModelFactory.cpp

图3.11 createRootNode流程

图3.11展示了创建根节点的详细流程。其中,在创建影像图层和高程图层中,相应的execute函数里分别调用了createImage()函数和createHeightfields()函数,这两个函数根据数据中的option属性,调用了相应driver的插件,而进行了实际具体的数据读取。如果需要写自己的插件读取影像数据或高程数据,则必须重载这两个函数。