Unity挑战大世界刷草(三)

阶段整理

到这里,知识点已经积累了不少,在这里我想做个简单的总结,梳理下眼下的信息,串一串流程:

一开始先让变化少一点,假设模型美术大大只丢了一株草的 Mesh 给我们,让我们以此为模板绘制草海;同时场景美术大大也上传了一张可以覆盖整个游戏世界的密度纹理(额外说明下,密度纹理的每一个 texel(或者叫纹素)代表了游戏世界中与之对应的每个一平米大小的地块,texel 里记录的数值,代表了这块地皮上草的密度)。

手握这两份资源,我们刷草海的基本思路也就明确了,那就是:不断复制草的 Mesh,查询密度图,选一个有密度值的 texel 出来,找到这个纹素对应的游戏世界上的地皮,把复制出来的草不断移动上去,直到满足密度要求,接着换上下一个需要填充草的地皮,循环往复,直到所有带有密度值的地皮都被填充上了足量的草模型为止。注意,这只是基本思路,不会有人真的这么干,因为还有很多地方可以优化。接下来我们会在时间和空间的维度上,对这套算法瘦瘦身,做做减法:

简化流程图

加速

(1)首先也是最明显的一点,我们没有必要一次性把整个世界的草都渲染一遍,只要考虑摄像机四周一定范围内的区域即可,因为更远处的草,在透视投影的影响下,可能大小已经小于一个像素,也可能已经和地表贴图色块融合一体,分辨不出了,核心区域之外的绝大部分草的渲染性价比极低,可以略去。

如何剔除远处的草呢?解决方案可以很简单,比如在之前展示过的逻辑流程中,新增一个条件判断分支,满足在视距内的草执行正常流程,所有不满足的直接放弃,虽然low了点,但确实能提高效率。也许有人会觉得对世界范围内每一株都执行一次距离判断还是太费了,所以更近一步,索性维护一个视距范围内的存量,比如说摄像机四周一个矩形范围内的草海的信息已经在内存里了,倘若下一帧摄像机没有移动,那么我们还渲染这块区域里的草海,什么都不需要改变;倘若摄像机移动了一个delta距离,那么我们只要补齐前进方向远处新纳入的一块草海信息,同时剔除掉反方向超出视距的那部分草海信息即可,这么做的好处显而易见,既只过滤需要改变的最小差量,从而避免了大量低效率重复计算。

视距内缓存

(2)一旦决定了只显示视距内草海,存放在内存中的那张全局密度图就越发碍眼了,占用空间不说,大部分数据在大部分时间内用不到是一件很浪费的事情。怎么办呢?使用 Mipmap 么?我个人觉得就密度纹理而言没有创建 LOD 层级的必要。但是把整个世界空间拆分一下,化成一块块整齐排列的地块似乎挺有必要,思路是把完整的密度图拆分到每块地块上,使用时只需要取用摄像机周围一定范围内的地块数据,从而简化运算。具体来说,我们是把整个密度纹理沿着x轴和z轴切割成等大小的子一级的单位(这边统称chunk)每个chunk上存储了属于它那部分密度信息,密度信息的形式可以是像纹理那样的二维数组,也可以是四叉树的根节点。以四叉树为例,形象的说,我们原本的全局密度图,现在变成了由一颗颗四叉树组成的森林,当然每个chunk地块上只种一颗。最后,在运行时我们读取摄像机周围一圈chunk(也就是9宫格),再辅以几个额外的chunk作为缓冲,让9宫格中心chunk始终对准玩家,如此一来,就保证了在不导入所有密度信息的前提下,我们能够顺畅的获取视野周围区域的密度信息。

环绕的9宫格结构

(3)视野一般说来不是360度的,而是一个叫做View Frustrum(中文叫视椎体)的空间,如果希望任意时刻都只显示落在视锥体围成的空间内的植被,就要有做视锥体裁剪的逻辑。幸运的是,就Unity这类游戏引擎,走正常渲染流程时就已经自动帮忙剔除了;但是也有例外,假如利用了某些比较底层的渲染接口,走了不一样的渲染流程,视锥体裁剪的步骤可能就被跳过了。为了弥补这种缺陷,我们需要准备一套逻辑去剔除那些肯定不在视锥中的密度单元,注意这里是密度单元(相当于1平米大小的地砖),不是草,这算是一种提高效率的方法,毕竟视锥裁剪基本上每帧都要执行,而且涉及大量顶点位置的变换和判断,现在变成一平米一平米的判断,而不用一株一株的来计算,能极大提高计算效率。也许有的同学会担心视场边缘会不会出现锯齿状的割裂感,不用担心,只要适当放大一下两侧的视锥包线,多放进来点地砖,问题就解决了,至于多塞入的那些草的渲染开销,个人感觉可以忽略不计。

视锥裁剪

到目前为止,我们拆分了密度图,做到只读入附近chunk中的密度信息,我们还在摄像机周围虚拟了一个缓存,用来存放一个矩形范围内的草海信息(或者叫视场范围也行),最后我们利用摄像机自己的视锥体裁剪掉了所有脑后的草海。。。似乎很完美,该删的删了,该拆分的拆分了,该缓存的缓存了,我们可以向GPU提交余下的草海信息来渲染了么?可惜并不是,下一篇博文会探讨数据的余量,以及如何想办法在CPU和GPU间接高效的存储和传递。

你可能感兴趣的:(Unity挑战大世界刷草(三))