移动端大规模草渲染的实现
先上最终效果:
在群里经常看到草的问题,也会和他们一起讨论。结果现在不得不自己也开始做了,就想把一些东西给汇总一下, 然后看做出来效果如何。
按照做拼接地表的经验,我一开始就打算使用程序生成网格,通过尽量多的顶点去做,尽量不适用alpha test.原因在于使用了alphatest之后,early z就 无效了,但对于草来说,early z应该是特别重要的可以提升性能的点。
不过为了看效果,一开始还是用最简单的方式,用程序生成了一个大网格,放上贴图,看上去是这样:
首先在手机上测试了一下,法线帧率堪忧,如果视角再平一点,估计就卡了,目前这样子大概有8w个面,还可以接受。因为后面本来就有优化策略,所以打算还是继续先做效果。草肯定不会这么均匀,我先打乱下草的分布。
感觉有点差强人意,真实的草不应该是这么杂乱,而且打乱之后变稀疏了,就更丑了。调整下疏密度,稍微舒服了点, 这里觉得颜色太单一,但又不想通过额外的参数来控制颜色变化,想了一下其实可以通过顶点色或者顶点索引。顶点索引需要在shader里多几步计算,考虑到性能,还是先往顶点色里塞,如果后续需要做其他东西,我觉得可以通过uv2来塞额外数据。
考虑到自然风,打算模仿一个dx 草下面的一个算法:
然后开始优化性能,首当其中的就是alpha test,因为为了风场动画,顶点本来就不少了,于是干脆直接用硬边。
性能从10帧跳到24帧,确实提高很多,硬边也还可以接受,然后发现另一个问题,就是手机上跑久了很抖,应该是数值过大引起的,需要将大数值取余。这样做了之后基本可以达到要求了。暂时先不考虑性能的进一步优化,因为我发现是我的手机太差了,换了台手机其实帧率可以到60帧。我更想处理的是和草的交互,因为图中这个球其实是压着草的,但因为没有交互,看上去很奇怪。
但在这之前还是需要处理一个问题,就是草是单面的,从其他方向看就会是一条线,一般是用billboard技术,但对我这种做法却不适用,因为billboard的重点是中心点,而我这么一大片网格,中心点和草是没啥关系的。于是我就换了一种做法,堆了两层草。用十字星的形式,这样的坏处是增加了面数,但好处也很明显,让整个草看上去更加自然。
接下来要处理交互了。
想了一下方案,首先草根据对应rt里的坐标读取像素,根据像素确定歪的方向,并且做歪曲。那么如何得到这张rt呢?
第一步是球的正面下压,我的想法是根据不同朝向,分别转成颜色值并显示出来,最终渲染到rt中。
shader代码如下:
然后是运动轨迹,原理一样,只不过需要通过运动动态创建网格,效果如下:
这样rt就是用摄像机从正上方去看它,一切都很完美了。
实际测试的时候发现一个大问题,就是如果草只有一部分顶点被压住,那么草会扭曲成很难看的样子,解决方案是把草的位置浓缩成一个点,草上面的所有顶点都用浓缩的这个点来判断,这样草的位置就一致了。
最后是插件地址:
https://www.assetstore.unity3d.com/en/?stay#!/content/132241