《Half Life2 Displacement Terrain System》由会员分享,可在线阅读,更多相关《Half Life2 Displacement Terrain System(5页珍藏版)》请在金锄头文库上搜索。
1、Half Life2 Displacement Terrain System HL2 的地形系统是一个另类的地形系统,它没有使用当前流行的 heightmap 技术,而是完全使用 displacement map 技术来进行处理,使用 displacement map 技术的初衷是为了在框架中和 BSP 技术保持一致,这是因为在 BSP 中最小的渲染图元是surface,surface 的限制是所有的顶点必须位于同一个平面上,实际上从理论上来说在 HL2 这样的引擎中也可以使用 heightmap 来构造地形,那就是将 heightmap 数据也分块保存,但是当前流行的地形技术使用的都是一个整
2、张 heightmap,而且大量的 LOD算法都是基于这个基础上的。使用 displacement map 的另外一个好处是可以构造更加复杂的地形,这是因为它存在法线的缘故。同时使用 displacement map 还有一个好处是在将来,因为当前 MS 已经对 displacement map 技术进行了支持,现在的问题是GPU 在硬件上还不支持,如果一旦硬件支持的话,就有可能将整个地形由 GPU 来处理,那么对地形渲染的速度和精度会有非常大的提高。1、whats Displacement Mapdisplacemtn map 技术是最近几年才出现的一个技术,它出现的初衷是为了解决内存和 G
3、PU 之间的带宽问题,它开始主要用于高 poly 角色模型的渲染,由于模型的高数据量会使内存和 GPU 之间的传输成为瓶颈,因此将其转换为低 poly 模型和一张displacement 传送到 GPU 中,在 GPU 中转换为高 poly 模型进行渲染,可以大大减轻传送的数据量。但是当前这项技术已经获得非常大的发展,它使用的范围非常大,从室外地形、水面、海洋到室内场景的渲染,它为提高场景的真实度提供了一个有力的工具。一个displacement map 通常包含两部分:一张 normal map 用来保存法线,另一张height map 用来保存顶点的偏移。当需要从低 poly 模型转换为高
4、 poly 模型时很简单,首先从模型的一个 face 上获得一个插值点 P1,然后从 displacement map 中获得相应位置的 normal 和 distance,那么新的顶点 P2 为:P2 = P1 + normal*distance关于 displacement map 的参考文章请看 shaderX2 中的Displacement Mapping。2、HL2 Displacement Map Rule在 HL2 中 displacement map 信息被保存在 BSP 文件中,它有以下几个数据块:LUMP_DISP_VERTS 保存 displacement 真实顶点信息L
5、UMP_DISP_TRIS 保存 displacement 三角形标识符信息(walkable or buildable)LUMP_DISPINF 保存 displacement 的连接信息它们保持的信息结构如下:LUMP_DISP_VERTS:class CDispVertpublic:Vector m_vVector;/ Vector field defining displacement volume.float m_flDist; / Displacement distances.float m_flAlpha;/ per vertex alpha values.;LUMP_DISP_
6、TRIS:class CDispTripublic:unsigned short m_uiTags; / Displacement triangle tags.;LUMP_DISPINF:class ddispinfo_tpublic:int NumVerts() const return NUM_DISP_POWER_VERTS(power); intNumTris() const return NUM_DISP_POWER_TRIS(power); public:Vector startPosition;/ start position used for /orientation -(ad
7、ded BSPVERSION 6)int m_iDispVertStart;/ Index into LUMP_DISP_VERTS.int m_iDispTriStart;/ Index into LUMP_DISP_TRIS.int power; / power - indicates size of map /(2power + 1)int minTess; / minimum tesselation allowedfloat smoothingAngle; / lighting smoothing angleint contents; / surface contentsunsigne
8、d short m_iMapFace; / Which map face this/displacement comes from.int m_iLightmapAlphaStart;/ Index into ddisplightmapalpha.int m_iLightmapSamplePositionStart;/ Index into./ LUMP_DISP_LIGHTMAP_SAMPLE_POSITIONS CDispNeighbor m_EdgeNeighbors4;/ Indexed by NEIGHBOREDGE_ defines.CDispCornerNeighbors m_C
9、ornerNeighbors4; / Indexed by CORNER_ defines.enum ALLOWEDVERTS_SIZE = PAD_NUMBER( MAX_DISPVERTS, 32 ) / 32 ;unsigned long m_AllowedVertsALLOWEDVERTS_SIZE; / This is built based on the layout and /sizes of our neighbors/ and tells us which/vertices are allowed to be active.;在 HL2 中规定一个 displacement
10、最大由 17*17 个顶点组成,每一个 displacement都将左下角看作是自身坐标系的原点,并按照顺时针方向进行记数。如下:在 ddispinfo_t 类中我们可以看到为了记录 displacement 的邻接关系,它使用了两个数组,m_EdgeNeighbors 记录四条边的邻接关系,而 m_CornerNeighbors 记录了四个角的邻接关系。必须注意的是在 HL2 中邻接的 displacement 并不一定都是一样大的,也就是说邻接的 displacement 不一定是一个,也可以是两个,如果邻接的为两个的话那么邻接的 displacement 的大小必须小一倍。如下:在 di
11、splacement 和 surface 中都有一个变量来指定它们相互之间的对应关系,你可以这样认为,如果一个 surface 是一个 displacement surface 的话,那么在surface 所保存的顶点信息就是 displacement 所在的基准面信息,实际上就是记录基准面的四角坐标,当产生实际顶点时过程如下:通过这四角的坐标和 displacement 的power 信息可以插值获得每一个真实顶点的基准点坐标,然后通过 CdispVert 所保存的信息获得真实的顶点坐标。3、如何处理地形系统在 HL2 中为了高效的渲染地形定义了大量的类,其中最重要的为 CdispInfo,
12、它几乎包含了地形的大部分处理,还有一个类 CpowerInfo,这是一个予计算的模版类,它预先计算了每一种大小 displacement 的信息,这样做是为了加速地形的渲染,而类CcoreDispInfo 只用来载入数据时使用,它的功能就是将 BSP 文件中的信息转换为程序可以处理数据。其实在 HL2 中比较难懂的是它的 LOD 算法,下面是它具体的算法:首先是它的更新策略,在正常情况下(LOD 的控制台变量为默认值)对displacement 的更新有两种情况,它规定了一个更新半径(由控制台变量r_DispFullRadius 指定)凡是位于此半径内的 displacement 的 LOD
13、等级都为最大。另外在每次更新时每一个 displacement 内部都记录了更新时 camera 的位置,如果当前 camera 的位置减去上一次更新时 camera 位置的大小大于一个规定值(由控制台变量r_DispRadius 指定),对其进行更新,必须注意的是此时更新的是位于更新半径外的displacement。下面是它的 LOD 算法,还是要提醒此时是对更新半径外的 displacement 进行处理。通常现在 LOD 算法都是基于距离进行计算的,但是 HL2 中没有采用这种方法,而是使用一种称为屏幕误差的方法进行。具体方法如下:首先假设将要更新的 displacement 位于屏幕的
14、中心,然后求出此时的 camera变换矩阵,遍历 displacement 中的所有顶点(不包含当前 displacement 的中心点和四个角上的点),对于每一个顶点,用它的坐标和它所在 error edge 的算术中点坐标相减,然后用这个值和当前 displacement 的 AABB 中心点相加,结果通过 camera 矩阵进行变换然后将 X,Y 部分分别除以 Z 值得到的就是这个顶点在屏幕上的视觉误差了。这是一个非常不容易理解的部分,尤其是除以 Z 值的部分,其实这样做是为了将其投影到 Z为 1.0 的平面上,省略了进行投影变换的过程,提高了效率。当这个误差大于预定义值就将这个顶点渲染
15、出来。通过上面的介绍可以看出在 HL2 中并没有象其它 LOD 算法一样对每一个displacement 硬性的规定一个 LOD 级别,而是通过每一个顶点的屏幕误差来确定它是否可以被渲染,这样做在渲染非常大的地形时效率不会太好,但是在处理 HL2 这样的小场景时效率确实非常不错。同时也要注意这种地形方法的优点,它非常适合处理落差非常大的室外场景,如地牢围攻这样比较夸张的地形,不过此时就需要对它的 LOD 算法进行一下改进,另外在 HL2 中地形一般都比较小,如果地图设计良好的话基本上很少会渲染hidden surface,因此上不需要做地形 tile 的 HSR,而将这种地形系统扩展到无限地形系统时,必然需要使用一定 OC 算法来做 HSR 的工作,这可能是将其扩展到无限地形系统的一个非常具有挑战性的工作了。