移动端草海的渲染方案(二)

书接上文

前文介绍了Unity内置 Terrain 刷草的一些缺陷,并且介绍了3款插件:

  1. uNature

  2. Advanced Terrain Grass

  3. Nature Renderer

下面就简单介绍一下这几款插件的做法,以及我们的选择。

如何刷草

Unity内置的刷草工具还是很好用的,Advanced Terrain GrassNature Renderer 沿用 Terrain 的刷草,只是接管了渲染。

参考一下 TerrainData 的API,我们可以通过脚本获取刷草信息,然后自己来做渲染。

沿用 Terrain 的刷草方式有兼容性上的好处,但是这里就强迫你必须选择 Terrain 来做地表了。

uNature 和上面两个插件不太一样,作者自己提供了刷草工具,刷草的对象不局限于 Terrain,也可以是 普通模型

比如下图,我不但在地表刷了草,也在Cube上刷了草。

image

GPU Instancing

渲染大面积草,GPU Instancing 是非常合适的。

然而,Unity的渲染方案是把地表分成一个一个的 Patch,每个 Patch 的草合并成一个大的Mesh,以此来降低 Drawcall,但是 多个Patch 的渲染是无法通过 GPU Instancing 提速的。

我们看一下 GPU Instancing 需要满足的条件:

Use GPU Instancing to draw (or render) multiple copies of the same Mesh
at once, using a small number of draw calls. It is useful for drawing objects such as buildings, trees and grass, or other things that appear repeatedly in a Scene.

这里每个 Patch 生成的Mesh显然是不同的......

当然,我们可以突破这个限制。

既然要求 相同的Mesh,那我们可以 把Mesh的计算从CPU移到GPU:把影响 Mesh差异 的因素 ( 比如 Noise高度 ) 编码到纹理,然后在 顶点着色器 采样纹理再把这些差异应用到顶点。

这样我们就可以用相同的Mesh来渲染,即满足 GPU Instancing 的开启条件,又可以满足表现上的多样性,顺带把前文提到的 运行时合并Mesh产生的CPU峰值 也优化掉了。

uNature 为例,场景依然会被栅格化,如下图:

image

这里的 蓝色格子 类似 TerrainPatch,处于同一个 紫色格子 内的蓝色格子是可以通过 GPU Instancing 来渲染提速的。

如果不考虑 LOD密度 的差异,每个 蓝色格子 的Mesh是一样的,最终表现上的差异被编码到了 顶点uv 以及 GrassMapHeightMap 这2张纹理中去了。

HeightMap 一览:

image

具体的编码方式我就不细说了,大家可以参考源码。

事实上,Unity在 2018.3 及以后的版本,对 Terrain 的渲染也加了 GPU Instancing 的支持,原理和我上面说的差不多:

When enabled, Unity transforms all of the heavy terrain data, like height maps and splat maps, into textures on the GPU. Instead of constructing a custom mesh for each terrain patch on the CPU, we can use GPU instancing to replicate a single mesh and sample the height map texture to produce the correct geometry. This reduces the terrain CPU workload by orders of magnitude, as a few instanced draw calls replace potentially thousands of custom mesh draws.

不过,一直到我目前在用的版本 2019.3,Unity对于 地形草(Terrain Detail) 的渲染方式还是老样子......

GPU Instancing 的 API

关于 GPU Instancing,如果通过脚本来操作,Unity提供了如下2个接口:

  • Graphics.DrawMeshInstanced

  • Graphics.DrawMeshInstancedIndirect

考虑到移动设备的兼容性,我们一般会选择 Graphics.DrawMeshInstanced 这个接口,不过 Graphics.DrawMeshInstanced 有一个最大数量 1023 的限制:

Note: You can only draw a maximum of 1023 instances at once.

如果我们以每一株草为单位来渲染,很容易就会突破这个限制。

Advanced Terrain Grass 就是这么做的,所以最后他用了 Graphics.DrawMeshInstancedIndirect 接口。

uNature 则是对草先做一定程度的 Mesh合并,回想一下下图的 蓝色格子,我们可以通过控制格子的粒度,从而把每个 紫色格子 内的 蓝色格子 数控制在 1023 以内,然后就可以通过 Graphics.DrawMeshInstanced 接口一次完成渲染。

image

Nature Renderer 的作者并没提供源码,不过从反编译的结果来看,他也是用了 Graphics.DrawMeshInstanced 这个接口,只是对 GPU InstancingDrawcall 做了更细致的管理,如下图:

image

每个相同颜色的格子属于同一个 Drawcall,和 uNature9宫格 管理方式并不相同。

我们的选择

好了,插件就介绍到这里。

最后,说一下我们的选择:基于 uNature 做改进。

  • 不选择 Advanced Terrain Grass,主要因为它是基于 Graphics.DrawMeshInstancedIndirect 的实现。此外,如果你想实现类似 塞尔达的割草 效果,整个 ComputeBuffer 的数据都要重建,这个开销在运行时难以承受。

  • 不选择 Nature Renderer 的原因则更简单,作者并不提供源码。

不过 uNature 本身的问题也不少,如果大家要用这个插件,你得有心里准备:

  • 作者已经很久没有更新了。
  • 代码有不少bug。
  • 针对移动端还要做很多优化。

无论如何,二次开发是必不可少的。

不过,有了 GPU Instancing,大面积的草海已经变得可行了。下面会继续介绍草海的其他渲染技巧以及模仿 塞尔达 的一些好玩的效果。

个人主页

本文的个人主页链接:https://baddogzz.github.io/2020/01/16/Unity-Grass-02/

好了,拜拜。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,784评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,745评论 2 378
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,702评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,229评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,245评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,376评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,798评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,471评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,655评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,485评论 2 318
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,535评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,235评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,793评论 3 304
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,863评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,096评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,654评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,233评论 2 341

推荐阅读更多精彩内容