转载自:http://blog.sina.com.cn/s/blog_5e3213f30100zvqp.html
在OGRE的使用中,我们经常会涉及到地形(Terarain)的问题,其中涉及到了很多以前自己没有接触过的内容,其文件组织较其他资源来说比较特殊,所以需要好好的理解一下。
【Terrain.cfg文件理解】
在OGRE的Media文件中,我们可以找到terrain.cfg文件,打开它就可以看到当前地形的相关设置了:
# The main world texture (if you wish the terrain manager to create a material for you)
#--------------指定了地形所用的纹理图
WorldTexture=terrain_texture.jpg
# The detail texture (if you wish the terrain manager to create a material for you)
#--------------指定了terrain所用的细节纹理
DetailTexture=terrain_detail.jpg
PS:一张纹理图伸展开来覆盖整个地形。纹理图一般都是粽、绿、白或者灰间杂的颜色,对应土地、草地、雪或者岩石地形,因为地形纹理一般比要覆盖的地形小的多,所以利用细节纹理来避免近距离观察带来的模糊。与地形纹理相比,细节纹理的伸展要小很多。一个地形被分割为一小块一小块的像地砖一样的地形方块,由场景管理器按照这些地形快的tuopu结构和观察者的举例依照不同的细节层次进行显示(也凑是MinMap啦,还记得在setupResources中设置的么),最后,用一个指定了地形维度的世界坐标空间,将完整的地形投影到一个三维空间中。
Terrain中的坐标系
Terrain Scene Manager把纹理图的左上角作为世界原点(0,0,0),以从左到右为x正方向,从上到下为z正方向,从屏幕里到屏幕外为y正方向,符合右手坐标系。
#number of times the detail texture will tile in a terrain tile
#--------------这个指定细节纹理在每个地形小块中重复的次数,也就是说,如果这个值是n,
#--------------那么细节纹理将在每个地形小块的n*n格中被显示。如果这个值设置过低,
#--------------地形在近看时会模糊,反之则会在观察时候有反复模式
DetailTile=3
# Heightmap source
#--------------指定高度图数据的来源,默认为Heightmap
PageSource=Heightmap
# Heightmap-source specific settings
#--------------指定高度图的名称,尺寸必须是方形,而且要符合2^n+1,高度图越大,
#--------------地形细节就越高,但是程序消耗的资源也越多(包括程序启动时间)
Heightmap.image=terrain.png
# If you use RAW, fill in the below too
#--------------有些高度图保存为raw格式,下列的参数描述了raw格式
# RAW-specific setting - size (horizontal/vertical)
#--------------指定高度图的尺寸,这就决定了地形要有Heightmap.raw.size* Heightmap.raw.size
(后面的PageSize是与此相对的,因为高度要逐像素指定的)那么大,如上所述,必须要符合2^n+1(如65,129,257等等),
#Heightmap.raw.size=513
# RAW-specific setting - bytes per pixel (1 = 8bit, 2=16bit)
#--------------指定文件中每个像素是用多少个字节表示的。
#Heightmap.raw.bpp=2
# How large is a page of tiles (in vertices)? Must be (2^n)+1
#--------------对应于terrain domo中的TERRAIN_SIZE,即一整块地形的顶点数目,
#--------------terrain demo中的TERRAIN_WORLD_SIZE是整个地形的大小,
#--------------TERRAIN_WORLD_SIZE/RERRAIN即缩放值,每个顶点之间距离的缩放值,
#--------------计算代码见Terrain::updateBaseScale()
PageSize=513
# How large is each tile? Must be (2^n)+1 and be smaller than PageSize
#--------------地形小块有TileSize*TileSize顶点,个数必须小于PageSize。
#--------------同时需要符合2^n+1,设的过小会严重影响效果,太大的话会在场景的某些部分
#--------------导致不必要的高细节。
TileSize=65
(地形小块是用来做LOD的可见性剔除的,具体的LOD层次是由下面的LOD相关参数设置的)
LOD(Level of Detail)——顾名思义,意为多细节层次,LOD技术指根据物体模型的节点在显示环境中所处的位置和重要度,决定物体渲染的资源分配,降低非重要物体的面数和细节度,从而获得高效率的渲染运算。
LOD技术在不影响画面视觉效果的条件下,通过逐次简化景物的表面细节来减少场景的几何复杂性,从而提高绘制算法的效率。该技术通常对于每一个原始多面体模型建立几个不同逼近精度的几何模型。与原模型相比,每个模型保留了一定层次的细节,在绘制的时候,根据不同的标准选择适当的层次模型来表示物体。
【LOD模型生成算法的分类】
由于人们通常采用多边形网格(特例为三角形网格)来描述场景中的图形物体,因而LOD模型的生成就转化为三维多边形网格简化问题。网格简化目的是把一个多边形网格表示的模型用一个近似的模型表示,近似模型基本保持了原模型的可视特征,但是顶点数目少于原始网格的顶点数目,典型的LOD模型生成算法有以下几种:
近平面合并法
Hinkler等的几何优化方法,检测出共面或者近似共面的三角面片,将这些三角面片合并为大的多边形,然后用较少数目的三角形将这个多边形重新三角化,但是该方法的误差衡量可以归结全局误差,由于它仅仅依据法线之间的夹角,它的误差评估准确性较差,它不能保证一定误差限制。几何元素(顶点/边/面)删除法
几何元素删除法由局部几何优化机制驱动,要计算每次删除产生的近似误差。
Schoroeder的顶点删除算法通过删除满足距离或者角度标准的顶点来减少小三角网格的复杂度,删除顶点留下的空洞要重新三角化填补,该算法的速度很快,但是不能保证近似误差。它估算局部误差,未考虑新面片同原始网格的联系和误差累计。
Hoppe渐进网格算法包含基于边折叠的网格简化方法、能量函数优化和新的多分辨率表示。算法采用了单步和可逆的边折叠操作,可将将整个简化过程放到一个多分辨率数据结构(称为渐进网格表示(PM))。PM方案由一个简化网格MK和一系列细化记录(通过与从原始网格M0得到简化网格Mk的简化步骤的相反步骤得到)。这些细化记录可以使得网格MK通过逐步求精得到任意精确度的网格Mi,在简化过程中,将每条边按照其折叠的能量代价排序得到一个优先级队列,通过这个队列实现边折叠操作,该算法也是采用全局的度量误差。重新划分算法
Turk的重新划分算法先将一定数量的点分布到原有的网格上面,然后新点与老顶点生成一个中间网格,最后删除中间网格中的老顶点,并对产生的多边形区域进行局部的三角化,形成以新点为顶点的三角形网格,其中分布新点采用排斥力算法,即先随机分布新点,然后计算新点之间的排斥力,根据排斥力在网格上移动这些新点,使它们重新分布,配吃力的大小与新点之间的距离、新点所在的三角形的曲率和面积有关。这种方法对于那些较光滑的模型是很有效的,但是对于那些不光滑的模型,效果较差,由于根据排斥力重新分布新点,设计到平面旋转或者投影,计算量和误差都比较大。聚类算法
Rossignac等的顶点聚类算法通过检测合并相邻顶点的聚类来简化网格。每个聚类被一个代表顶点取代,这个代表顶点可能是顶点聚类的中心或者是聚类中具有最大权值的顶点,(定义顶点的权值是为了强调相对的视觉重要性)。该算法的实现简单、速度快、但是没有考虑到保持原始网格的拓扑和几何结构,有可能生成非常粗糙的近似网格。小波分解算法
Eck等的基于小波变化的分辨率模型使用了带有修正的基本网格,修正项称之为小波系数,用来表示模型在不同分辨率情况下的细节特征算法的三个主要步骤:分割:输入网格M被分成一些(数目较少)三角形的区域T1,……,Tn, 由此构成的低分辨率三角网格称为基本网格K0。参数化:对于每个三角区域Ti,根据它在基本网格K0上相应的表面进行局部参数化。重新采样:对基本网格进行j次递归细分就得到网格Kj,并且通过使用参数化过程中建立的参数将Kj的顶点映射到3维空间中得到网格Kj的坐标。此算法可以处理任意拓扑结构的网格,而且可以提供:有界误差、紧凑的多分辨率表示多分辨率尺度下的网格编辑。
# The maximum error allowed when determining which LOD to use
#------指定当决定使用LOD时候的最大容错值,设置过高导致地形有接缝,过低则会影响效果。
MaxPixelError=3
# The size of a terrain page, in world units
#------在世界坐标内的地形的大小
PageWorldX=1500
PageWorldZ=1500
# Maximum height of the terrain
#------地形的最大高度。高度图中的0..255缩放到世界坐标系中的0..MaxHeight
MaxHeight=100
# Upper LOD limit
#------指定了细节层次的上限,地形的远处和平坦部分会以低细节层次渲染。
MaxMipMapLevel=5
#------是否让TerrianSceneManager在缓冲中计算顶点法线,计算机光照或者GPU程序用到时打开
#VertexNormals=yes
#------是否让TerrainSceneManager 在缓冲中设置顶点颜色,假如有GPU程序需要时打开
#VertexColors=yes
#------是否优化地形三角形送入GPU的顺序,以便减少送入的顶点个数(对于大所属新款显卡来说帧率不会有很大的变化)。
#------因为在某些显卡上可能产生“裂缝”,并且很少甚至没有什么性能的提升,所以关掉比较好。
#UseTriStrips=yes
# Use vertex program to morph LODs, if available
#------是否使用顶点程序进行LOD融合处理
VertexProgramMorph=yes
# The proportional distance range at which the LOD morph starts to take effect
# This is as a proportion of the distance between the current LODs effective range,
# and the effective range of the next lower LOD
#------LOD融合开始点:这是当前的LODs作用范围和笑一个更低级别的LODs作用范围之间距离的一个比例。
LODMorphStart=0.2
# This following section is for if you want to provide your own terrain shading routine
#------下面的参数在你想要提供你自己的地形着色例程的时候使用
# Note that since you define your textures within the material this makes the
# WorldTexture and DetailTexture settings redundant
#------这标志着你会提供自己的material,那么先前定义的WorldTexture与DetailTexture的设置不再用到。
# The name of the vertex program parameter you wish to bind the morph LOD factor to
# this is 0 when there is no adjustment (highest) to 1 when the morph takes it completely
# to the same position as the next lower LOD
# USE THIS IF YOU USE HIGH-LEVEL VERTEX PROGRAMS WITH LOD MORPHING
#------假设使用了LOD的顶点混合程序,那么定制的material中包括一个高级顶点程序。
#------它指定了一个顶点程序的参数名,这个参数用于融合LOD,参数值从0-1,
#------0表示不调整,1表示完全调整到下一级LOD
#MorphLODFactorParamName=morphFactor
# The index of the vertex program parameter you wish to bind the morph LOD factor to
# this is 0 when there is no adjustment (highest) to 1 when the morph takes it completely
# to the same position as the next lower LOD
# USE THIS IF YOU USE ASSEMBLER VERTEX PROGRAMS WITH LOD MORPHING
#------用于material中包含低级顶点程序的情况
#MorphLODFactorParamIndex=4
# The name of the material you will define to shade the terrain
#------指定的Material的名字。
#CustomMaterialName=TestTerrainMaterial
上面的所有的这些参数可以划分为两类:
Ogre使用第一类从高度图产生地形与mesh材质。
第二类是定制材质与GPU顶点程序,这可以代替ogre自动产生的着色程序。
PS:TerrainSceneManager会把高度图分为多个page,每个page由几个tile组成,它们都定义了在产生的mesh中一组构成正方形的顶点集,world texture定义的纹理不必与目标地形一样大。PageWorldX,PageWorldZ可以缩放世界中的地形,MaxHeight在Y方向缩放地形。DetailTexture只使用一个纹理,要使用多层纹理只能使用自定的material。
【Ogre如何实现通过cfg文件载入地形的】
首先,我们要明确Ogre中的场景管理器有以下四种类型:
ST_GENERIC //普通场景
ST_EXTERIOR_CLOSE //室外封闭场景
ST_EXTERIOR_FAR //室外无限场景
ST_INTERIOR //室内场景
除了第一种普通场景之外,其它及中共都是处理复杂场景的专用场景管理器。OGRE引擎中有一个SceneManagerEnumerator类,其作用是管理已经实现的场景管理器。在Ogre的Root类里就聚合了一个SceneManagerEnumerator对象,以供选择需要的场景管理器。你在选择场景管理器的时候,可以利用原有的框架利用如下的代码来选择你的场景管理器:
Virtual void chooseSceneManager(void)
{
//Get the SceneManager ,in this case a generic one
mSceneMgr=mRoot->getSceneManager(ST_GENERIC);
}
可以看到,在普通的情况下使用的是普通场景管理器,如果要使用特殊的场景管理器,通过mRoot->getSceneManager()函数做出选择就可以了。
在OGRE 的SceneManager类中有函数setWorldGeometry,它的作用是读入世界信息(复杂场景中的大楼、野外地形等不变场景内容,区别于程序员手动加入的可以控制的场景元素),并将其管理起来。对于普通的场景管理器来讲,没有“World Surface(Terrain,Room)”这个概念,调用这个函数将只会抛出一个i“World Geometry is not supported by the generic SceneManager的异常,而OGRE 在其引起提供的plugin_BSPSceneManager.dll中提供了通过BSP算法实现的ST_INTERIOR室内场景管理器,它重新实现了setWorldGeometry函数,使其可以读入一个.bsp的室内场景文件并管理之。.bsp是QUAKE和CS等室内游戏中使用的场景文件类型。OGRE还可以在其引起提供的Plugin_OctreeSceneManager.dll插件中,通过八叉树算法实现ST_EXTERIOR_CLOSE室外封闭场景管理器,它同样重新实现了setWorldGeometry函数,使得其可以读入一个.cfg室外场景配置文件,并载入一灰度图形式表达的地形高度图。
由此可知,我们在使用.cfg文件定义的地形的时候,需要将SceneManager修改为支持其加载方式的室外封闭场景管理器,同时在createscene中添加如下的语句即可:
std::string terrain_cfg("terrain.cfg");
mSceneMgr->setWorldGeometry(terrain_cfg);
我们用上面的语句可以加载自己设置的地形文件,但是你要保证你的插件中有八叉树,不然Ogre只会使用二叉空间分割树。