zoukankan      html  css  js  c++  java
  • Terrain Reandering, Again !

     Terrain Reandering, Again !

    作者:clayman
    仅供个人学习使用,转载请保留作者以及原文链接,勿用于任何商业用途。

           前段时间修改了一个基于roam的古老地形系统,于是有了此文。
           首先,关于roam,虽然早已经忘了具体算法,也从来没有自己实现过基于roam的地形,但和以前blog里说的一样,roam已经完完全全过时了,原因有以下几点:
    1.roam需要在CPU端实现,需要使用dynamic buffer,bad to gpu :(
    2.
    roam对视点位置太敏感,微小的移动都会导致重新镶嵌,而重新镶嵌出的模型常常只在局部有微小变化,不但对性能提升无益,还导致视点连续改变时,popping现象严重:(
    3.
    roam计算量太大。本人没有做具体性能分析,但同事告知,如果镶嵌密度提高一倍,即使i5的cpu算起来也很吃力,况且我们游戏的视野并不算远:(

         由于以上几点原因,我希望新的地形1,提高性能,对CPU和GPU都相对友好;2,算法简单;3,减少popping现象。最终,我们有了一个chunk lod + interlocking tile的方案。有趣的是完成新系统前,我都没有看过<<Simplified Terrain Using Interlocking Tiles>>,而是从wow的实现得到了很多灵感。有没有搞错Chunk lod + interlocking tile?? 高端前沿开发者在鄙视我了,确实,这并不是什么新技术。但下面我就告诉你为什么它已经足够好了!!

           首先,geo clipmap,dynamic tessellation之类的方案一开始就被否决了,原因很简单,对GPU不友好。我希望新系统在dx9 sm2.0级别的硬件上也能跑。此外,一直以来我都认为通过动态计算来实现地形这类相对“静态”的物体太不值得。即使目标平台是DX11,也不值得通过tessellator计算地形,这两种技术虽然只需要非常少的vertex buffer,但计算过程所消耗的带宽和计算量远远超过小buffer带来的好处。

         Chunk lod对地形来说是非常理想的算法,对整个地形块进行lod改变,避免了roam过度敏感的问题,此外,算法非常简单,甚至可以说不需要算法:每个chunk使用固定的vertex buffer,预先计算好几个不同LOD下的索引数据,选择不同的index就完成了lod变换,static vertex buffer,static index buffer,没有运行时计算,并且index可以被所有相同lod的chunk共享。最经典的例子莫过于wow的地形(不熟悉的赶紧google)。Chunk lod的问题在于如何与相邻不同lod的chunk相连接,避免出现T-junctions。这个问题初看起来很复杂,但如果我们限制第n层lod的chunk只能与n+1层的chunk相连接,那问题就变得非常简单,我们只需要为每层LOD创建9种不同的索引,保证边缘的顶点一致就可以,如下图所示:

           对于有n层lod的地形,需要n*10种不同索引,听起来似乎有些多,但考虑到同层的所有chunk都能够共享这10块buffer,其实数据量并没有多少。有什么没考虑到的吗?

     要对地形打洞怎么办?
    很常见的需求。如何从顶点级的层面来考虑,似乎完全无法和目前的方法兼容;但如果从像素级的层面考虑,地形上的洞其实就是透明像素而已,完全可以使用贴图或者添加顶点数据实现特定部分的透明:)

    精度最高的层是每个顶点之间2个单位的距离,大部分情况下很好,但在某些山尖的地方稍微有些粗糙,不把最高lod增加到1个单位间距的情况下,有什么方法可以改进?
    注意观察上图,interlocking tile的精髓就在于只要边缘保持和邻接层一致,内部可以任意镶嵌。如何你觉得0级的lod在某些情况下精度还不够,可以再创建0+级,边缘和0级的保持一致,内部精度可以再提高n倍,对于有需要的特定chunk使用0+级索引,其余大部分chunk仍使用0级:)

    Chunk lod改变时还是会出现popping现象,有什么解决方案吗?
    方案1,让你的第0级chunk范围足够大,当远处的chunk lod改变时,不太容易发现popping :)
    方案2,所有地面都覆盖上草地,就算有popping你也看不到了:)
    方案3,使用Geo-Morphing,我们可以得到完美的lod转变。比如每个顶点都保存了在不同LOD层下的高端,当LOD变化时,插值变换到正确的高度。
    方案4,把以上3种方案结合起来,让0级范围足够大,对0到1级之间的转变使用morphing,植树种草,你基本看不到popping了:)

    那我的顶点数据不是要多很多?
    压缩,压缩,压缩。地形数据并不需要32位float精度。通常16位就足够了,尝试使用short,ubyte,udec3之类的格式保存位置,法线和纹理坐标。

    如何管理组织地形?
    每个chunk不管处于任何lod状态,大小都是固定的,基本上二位数组就够了,对,完全没有必要使用四叉树!

    如何实现无限大地形?
    你大概需要把刚才的二位数组改为环形二维数组,当视线移动时,删除看不到的chunk,并且把新chunk加载到之前删除的空间,类似这样

    对于wow类型的游戏,多少级lod才够,每个chunk多大,多少三角形合适?
    如果你看过介绍wow地形的文章,大都会告诉你wow使用的了2级lod。下图的场景中,大部分地形都处于0级,从有雾的区域开始,非常远的地形才会使用1级。0级Lod每个chunk512个三角形,1级256个。下图的场景大概有250~300个chunk,每个chunk一次DP!三个,不要超过三个LOD,不能再多了:)

    地形渲染的瓶颈在什么地方?multipass纹理性能如何。
    根据上一个问题,chunk/DP数量其实都不是问题,顶点/三角形数量对性能的影响非常小。曾经在perfhud的测试中发现不同lod但覆盖近似大小屏幕区域的chunk渲染费时几乎一样,主要计算都花费在pixel shader,因此,shader lod也很重要。比如对只对最近的n个tile使用normal map,对远端的chunk直接用一张预计算的纹理或者雾的颜色,尽量避免multipass。

    关于texture blend有什么要说的吗?
    1, 最大四层纹理对于大多数游戏都足够了。我们的古老地形系统使用multipass理论上可以支持无限层纹理,但最终很少有一个chunk会使用4层以上,并且multipass最终成了最大瓶颈。2,如果你觉得普通线性混合出的纹理效果不好,那么可以参考泰坦之旅的方法。3. 通常把4层纹理的权重保存在一个ubyte4中,如果保证权重总和为一,那么可以通过x-rgb计算第四层纹理的权重,在r通道中保存一些其他东西:)

    好吧,还有什么更高级的技术吗?
    类wow游戏中,基于height map的技术已经非常成熟,由于硬件的发展,lod已经变的越来越不太重要。现有技术就可以完全满足需要。如果想有突破,那么09年GDC《HALO WARS: The Terrain of Next-Gen》中基于vector field的地形解决了height map不能出现高度重叠的问题,非常值得尝试(一直没明白他们如何解决碰撞检测,求高人指点)

     

     

  • 相关阅读:
    轻松搭建CAS 5.x系列(7)-在CAS Server使用第三方帐号做认证
    轻松搭建CAS 5.x系列(6)-在CAS Server上增加OAuth2.0协议
    轻松搭建CAS 5.x系列(5)-增加密码找回和密码修改功能
    CAS 5.x搭建常见问题系列(3).Failure to find org.apereo.cas:cas-server-support-pm-jdbc:jar:5.1.9
    CAS 5.x搭建常见问题系列(2).PKIX path building failed
    CAS 5.x搭建常见问题系列(1).未认证的授权服务
    轻松搭建CAS 5.x系列(4)-Java客户端程序接入CAS单点登录,Hello World版
    轻松搭建CAS 5.x系列文章
    CAS实现SSO单点登录-CAS Server 5.3搭建 cas5.3搭建 cas5.3去除https cas 去除https cas 5.x 去除https
    互联网大咖都要收藏的几个网站,纯干货
  • 原文地址:https://www.cnblogs.com/clayman/p/2810702.html
Copyright © 2011-2022 走看看