在之前的几个月中,本人开始着手探索Unity3D引擎在主机PC平台的一套比较高效的渲染和加载方式,到目前为止已经实现了基本的渲染方法,这里先放上主要的实现参考,GDC 2017 Ghost Recon Wildlands Terrain Tools and Technology:
Ghost Recon Wildlands Terrain Tools and Technologywww.youtube.com前排警告:这篇文章,非!常!长!而且因为技术点琐碎,描述难免有些伦无语次!希望诸位看官见谅!
本篇文章我们将会从以下几个方面讲解在Unity3D中搭建一套以高端平台为目标的,理论支持无限大的平坦大地形实现,为什么要特别强调“平坦”呢,因为这里实现的地形是指狭义的使用高度图对平面进行置换的渲染方法,因此类似山洞,峭壁,树木等等暂时不在这套系统的实现范围内,在本文中也将不予讨论。我们将分为以下5个部分讲解这套大地形的原理和表现:
- 基本渲染实现
- 资源的加载和卸载
- 地形着色与生产流程
- 性能表现
- 总结
基本渲染实现:
我们采用了曲面细分 + 高度图的方法进行渲染。先来说曲面细分,每一片地形会经过DX11以后支持的Hull Domain Shader,经过数倍细分,分成一张三角形均匀排布的平面:
比起传统的网格绘制,相同面数下曲面细分的性能表现非常优越,首先其光栅化性能比单独的三角形光栅化要高数倍,在PC平台进行压力测试时,我们发现同屏细分几千万面,每帧的耗时也只有寥寥数毫秒的变动,这令我们感到十分惊喜,并直接决定使用Quad Plane + Tessellation代替传统的GPU Instance方法。同时Tessellation最高支持64级细分,这样每两个三角形就能承担起64 * 64分辨率的高度置换图,这也让高度的精度选择十分灵活,大大增大了制作的自由度。
在LOD方面,我们使用了四叉分割树的方法进行计算:
四叉分割的算法是大学数据结构课里比较基础的部分,这里就不再赘述。从图上不难看出,地形资源的存储趋近于一个金字塔型,与纹理贴图中常用的MipMap非常相似,实际上两者原理本来也是十分接近的,区别只是地形中每个“像素”位置储存的并不是颜色而是这一整块地形的所有信息,四叉分割树的特性对每一部分的影响在我们本篇文章中都会有所涉猎。
目前整个地形用到的所有贴图都是基于Virtual Texture的,我们在上一篇文章中已经讲过Virtual Texture的实现:
MaxwellGeng:Virtual Texture Tools & Practiceszhuanlan.zhihu.com高度图也不例外,所以Shader中读高度图进行置换的方法十分简单粗暴:
地形使用的Fragment Shader中进行着色的部分也和普通Standard PBR Shader几乎没有任何区别,唯一的区别可以说就是把读取普通贴图换成了读取Virtual Texture:
因此可以看到,Shader在渲染中基本没有做任何事情,Virtual Texture的生成才是渲染最主要的部分,Ghost Recon中是用这样的办法进行材质生成的:
首先将32套PBR材质贴图存到Texture Array中,然后用一张8位的Mask Map进行选取采样,采样出的效果大概如此:
进行手动Bilinear,使采样效果变得平滑:
因为Ghost Recon中并不是“同一块”地形,或者说,不同区域的地形美术风格不一样,而所有区域的材质数量加起来远高于32套,因此他们还使用了一个Indirect Buffer做索引跳转,相当于开了一个对象池实时的卸载掉那些在这个区域内不可能用到的材质,并加载这个区域内一定会用到的:
这个实现实际上与游戏逻辑比较耦合,这里我们暂时不实现Indirect Buffer,这方面会在之后的材质流程部分实现。
所以我们这里使用Mask进行混合的实现如下,首先封装一下Mask Texture的Bilinear Interpolation,毕竟Mask也要全图连接,所以也是一张Virtual Texture:
用计算出的权重进行混合:
但是纯线性的Bilinear会让整个地形充满丑陋的