osgEarth 的地形分页流程,我大致的写一下,感兴趣的话,大家可以去代码中看看,以
MPEngine 为例:
osgEarth 的加载,就不说了(有感兴趣的可以以后再写),从 TerrainEngine 的初始化开始,
TerrainEngine 的 初 始 化 后 根 据 选 择 的 地 形 引 擎 , 会 调 用 MPTerrainEngineNode 中 的
dirtyTerrain,我就从这里开始走一下 Tile 的生成过程。
dirtyTerrain 中有个 getAllKeysAtLOD,大概的意思是根据 LOD 的级别计算 TileKey,作用是.earth
文件中可以配置地球的 first_lod 可以通过这个函数从 first_lod 计算 TileKey 作为地形 Tile 的
根 TileKey。具体的计算过程在 Profile 里,Profile 包含地理范围和空间参考。把地球人为的
分了 Tile(具体分的方法可以看代码,也很简单)。
然后最关键的代码如下:
TilePagedLOD* plod = new TilePagedLOD( _engineUID, _liveTiles, _deadTiles );
plod->setCenter ( bs.center() );
plod->addChild ( tileNode );
plod->setFileName( 1, Stringify() << tileNode->getKey().str() << "." << _engineUID <<
".osgearth_engine_mp_tile" );
TilePagedLOD 是 PagedLOD,这样 plod 的序列号为 1 子节点,在到达可视范围的时候,会加
载 Stringify() << tileNode->getKey().str() << "." << _engineUID << ".osgearth_engine_mp_tile"。这
个“可视范围”是在 PagedLOD::traverse 这里计算的,这里的“加载”也不单纯是把这个节
点直接放进场景中,这里是 PagedLOD 的机制(关于 PagedLOD 的加载,这里不说了,很多
资料都有)。这里就先理解为到达可视范围后,加载了 Stringify() << tileNode->getKey().str() <<
"." << _engineUID << ".osgearth_engine_mp_tile"。这个是根据 TileKey 生成的一个字符串,有
两点需要说明:1、之前说了 TileKey 是人为定的,这样它就和唯一的地理范围对应,这样根
据 TileKey 就能去 GIS 数据中取指定的影像数据、高程数据等;2、".osgearth_engine_mp_tile"
这个带“.”的是 osg 的数据加载机制,还记得.ive、.osg 等是怎么起作用的吧,以“osgdb_”
的 dll,加载 readNode。这里也一样,去寻找以“osgearth_engine_mp_tile”为后缀的插件,
这样在调用 MPTerrainEngineDriver 的 readNode 时,调用了:
if ( "osgearth_engine_mp_tile" == ext )
{
node = engineNode->createNode(key, progress);
}
MPTerrainEngineNode::createNode
中又调用了 SingleKeyNodeFactory::createNode,在这里根据上一层的 TileKey 计算出 4 个子
TileKey。创建“四叉”节点,加载到场景中(并不是直接加进去的, 用的 PagedLOD)。这
样就完成了一个“四叉”的划分。
接下来过程同上。
这里回答了以下几个问题:
1、TileKey 是如何获取的?
答:是人为划分的,与指定的地理范围一一对应,具体代码看 Profile::getAllKeyAtLOD。
2、“四叉树”是如何创建的?
答:通过以上的流程,用了 PagedLOD,采用了分页的机制,可以动态调度海量数据。
加载时用了 osg 的插件机制,在 MPTerrainEngineDriver::readNode 中创建子节点。
YunGIS