OGRE可以通过两个接口来生成地形,分别是void TerrainSceneManager::setWorldGeometry( const String& filename )以及void TerrainSceneManager::setWorldGeometry(DataStreamPtr& stream, const String& typeName ),两者的根本区别就是一个是传递地形信息文件名一个是传递地形信息数据流,设计两个接口的目的是可以让用户使用自己的地形信息配置文件,而不必局限于 OGRE定义的地形信息配置文件格式。在分析流程之前,先说明一点,为了提高渲染性能以及地形查找性能,OGRE把整个地形分成若干个地形页,每个地形页又分成了多个地形小块,到最后会把地形页及地形小块tile挂接到场景节点上。以下是生成地形的主要流程:
一:清除地形分级索引缓冲及地形分页,根据地形信息数据流加载地形信息配置文件,
void TerrainSceneManager::loadConfig(DataStreamPtr& stream),其先将地形配置信息从数据流中逐一读出到map中,然后通过void TerrainSceneManager::selectPageSource(const String& typeName, TerrainPageSourceOptionList& optionList)设置地形数据源(目前只有高度图数据源)。在地形信息配置文件中可以配置多个地形数据源,然后根据一种数据源类型生成地形,参数 typeName就用来指定数据源类型,目前就是HeightMap,找到指定的数据源后,对指定的数据源进行初始化,
void HeightmapTerrainPageSource::initialise(TerrainSceneManager* tsm, ushort tileSize, ushort pageSize, bool asyncLoading, TerrainPageSourceOptionList& optionList)。初始化的过程主要是调用void HeightmapTerrainPageSource::loadHeightmap(void)将高度图灰度图像数据加载到内存中,如果是Raw数据,就加载到mRawData中,否则加载到mImage中。整个加载过程其实完成了两大工作,首先加载地形配置信息,然后加载高度图数据。
二:初始化分级索引缓冲,void TerrainSceneManager::initLevelIndexes();
三:void OctreeSceneManager::resize( const AxisAlignedBox &box )
四:设置地形材质,void TerrainSceneManager::setupTerrainMaterial(void);
五:设置地形分页, void TerrainSceneManager::setupTerrainPages(void)
首先创建一个名为Terrain的场景根节点的子节点
mTerrainRoot = getRootSceneNode() -> createChildSceneNode( "Terrain" );
然后初始化TerrainPage2D mTerrainPages;
最后调用 void HeightmapTerrainPageSource::requestPage(ushort x, ushort y)requestPage只支持一个Page,首先将图像数据进行缩放
然后调用 “TerrainPageSource::firePageConstructed()”通知Listener;然后调用“TerrainPage* TerrainPageSource::buildPage(Real*heightData, const MaterialPtr& pMaterial)”创建一个新的TerrainPage对象。
buildPage()是一个比较核心的函数。它首先构造一个 TerrainPage对象,然后创建一个用于容纳该TerrainPage对象的场景节点:“page->pageSceneNode = mSceneManager->createSceneNode(name);”,然后根据对地形的分割,循环创建子SceneNode,并且创建子场景节点对应的可渲染体TerrainRenderable,将该可渲染体attach到这个子节点上。通过 “TerrainRenderable::initialise()”来创建顶点数据、渲染方式等。
然后调用void TerrainSceneManager::attachPage(ushort pageX, ushort pageZ, TerrainPage* page)加入到mTerrainPages中;
然后在attachPage中调用“mTerrainRoot->addChild(page->pageSceneNode);”加入到SceneGraph中。
注:当前只支持一个Page,该分页被挂接到一个称谓Terrain的场景节点上,该场景节点下面又创建了很多子场景节点,每一个子场景节点对应一个tile,也就是一个独立的可渲染体TerrainRenderable