Shader:基于相机深度的简易卡通水

刷 Youtube 的时候偶然看到了一个卡通水的实现,原 Shader 是手撸的,而我使用 Unity ShaderGraph 来复现它。

原理

  • 通过 Camera 深度图获取不透明队列的场景深度,其与水面片元深度的差作为水深依据
  • 通过噪声图渲染波浪,通过 UV 扰动实现波浪动画

实现

1. 获取水的“深度”

需要说明的是,这里的“深度”要打引号,因为这是 Camera 视角的深度差,会随视角变化而变化,并不是真正的深度。

此时可以将“深度”输出到 Color,查看数值状态:

2. 水颜色插值

根据上文的“深度”,对水进行插值上色,并使用最大深度阈值做颜色限制:

效果:

3. 浪花斑点

通过噪声图成浪花斑点,并通过阈值限制浪花的“区域”。

此处通过内置噪声图生成仅为调试效果,后续的动画步骤将把它替换为外部固定的噪声图。

通过合理的数值调整,有如下效果:

4. 边缘浪花

通过“深度”阈值判断是否为岸边、物体交界边缘,并酌情展示浪花:

合理设置相关参数,如:

效果:

5. 浪花动画

为了进行 UV 扰动采样,先将噪声图换成外部的固定噪声图:

之后再通过波浪噪声图叠加 Time 扰动 UV,实现浪花动画:

效果(GIF):

6. 处理边缘差异较大的情况

由于深度值不同,水中悬浮物体的边缘浪花与岸边浪花差异较大。通过场景法线与水片元法线点乘,控制宽度,使浪花尽量保持一致。

首先需要确保 URP 渲染流程中是否开启了场景法线 Camera Texture 渲染(例如当 RenderFeature 声明需要法线时就会渲染法线),如果没有开,可以自定义一个需要 Normal 的 RenderFeature(或采用一个偷懒的方法,把 AO 打开,因为它就是一个需要 Normal 的 RenderFeature)。

为了确保 CameraNormalTexture 没有问题,可以用 ScreenPos 采样并当作颜色输出到片上:

法线没问题,继续连连看:

效果:

7. 其他

原作者还做了半透明 Alpha Blend、浪花边缘平滑等处理,由于相关内容太简单,遂略过。

优缺点

  1. 优点
    1. 不用改动渲染队列和相机,左右眼切换由 URP 管线自动处理,适合 VR;
    2. 若深度图和法线图已生成,那水面只是在此基础上采样两次,比较轻量
  2. 缺点
    1. 采用 URP 管线主相机的深度图和法线图,深度会随着相机位置改变,进而导致水颜色变化
    2. 某些极端情况下,水中漂浮物体的浪花不正确

缺点 2.2 分析

以下图为例,当摄像机完全垂直于漂浮物体时,此处深度值为水面 - 地形而不是水面 - 物体,因此物体周围没有浪花:

对于一个简易 Shader 而言,此现象无伤大雅。

引用资料

梓喵出没博客(azimiao.com)版权所有,转载请注明链接:https://www.azimiao.com/10384.html
欢迎加入梓喵出没博客交流群:313732000

我来吐槽

*

*

0位绅士参与评论

  1. 很棒的教程,学到了