风格化草地树木的实现

概述

很早就想尝试风格化渲染,正好看到了一个使用Blender的教程,顺便就试了一下,移植到Unity上。

草地

先看草地,概括原版教程

Blender

  • 首先创建单株草Mesh,
  • 利用Blender中的几何节点,在平面上随机分布草Mesh
  • 预生成不同层级的颜色贴图,用于在平面上赋予草颜色
  • 利用同一张贴图,当作高度图,生成法线,同样按照世界坐标UV来采样,给每个草Mesh都加上法线
  • 最后用简单的lambert光照模型来渲染,lerp下颜色,阴影地方给个深色来模拟阴影
  • 然后是风的动画,用顶点偏移,采样了两次噪声,一次频率低,模拟风浪,一次频率高,模拟草叶的抖动
  • 因为风倒伏大的地方会有阴影,所以在风浪的地方,给个深色来模拟阴影
Blender效果

Unity

重点来看Unity的实现

首先是导出草的mesh。这里为了之后处理风,给mesh加上了UV。

草mesh

在Unity6中,地形上的草地是用GPU实例化的,所以我们可以直接把草的mesh放到地形上,使用GPU实例化来渲染。

GPU实例化的草

然后是渲染了。
首先准备预渲染的贴图。
这里本来想程序化生成的,但后续再用程序化的贴图取计算法线,需要模糊,采样消耗比较高,所以还是在预处理下。

首先是一张类似高度图的用来颜色分级的贴图

颜色贴图

然后把这张图再模糊一下,当作高度图来用。
模糊高度图

这里直接用Unity从高度图生成法线的功能,直接生成法线贴图。
法线贴图

然后就ShaderGraph一通连连看,
首先是颜色

ShaderGraph
颜色

然后是顶点动画

ShaderGraph
风动画

改进

这里的散布是使用的Unity的地形,后续剔除、hiz等不好实现了,最好改用ComputeShader来实现。

然后是法线完全取决于预先生成的贴图,不能根据刷的疏密来动态调整。

草的颜色这里是用的中心点位置来采样的,

然后来看看树

Blender

总体思路是用球体来模拟一簇树叶。
在球体基础上,使用几何节点,放置若干密度的面片,然后面片使用广告牌,每个面片依照球体上的位置来充当法线,
然后用lambert光照模型来渲染,用得到的颜色来分级采样预定的色带,每个面片再采样预先绘制的贴图充当alpha,再裁切一下就行了。

Blender树

Unity

这里有多种实现方式,首先是最灵活的,用VFX来实现(普通的Cpu粒子应该也行)

这里就没必要局限于球体了,可以采样任意Mesh。

单簇

粒子图很简单,就采样Mesh的位置和法线,传给粒子,最后渲染要面向相机。
粒子图

然后是渲染

附带的alpha图
alpha图

shader就半兰伯特,用最后的颜色来采样一个色带
shader

不足与改进

使用SG来写shader目前还是有很多局限的,比如这里要采样阴影就很麻烦了。

这里面向相机的方式,静态或者角度不太刁钻时都还好,但特定角度下旋转相机,叶片也会跟着转动,导致看起来不太自然。


风格化草地树木的实现
https://www.kuanmi.top/2025/05/06/ToonShadingGrassTree/
作者
KuanMi
发布于
2025年5月6日
许可协议