最近研究了一下Unity官方的BoatAttack案例,他们模拟的海浪效果很厉害,用的是Gerstner波来模拟水面起伏和波峰的白浪还有浮力系统,还做加入了焦散效果(Caustics)和平面反射(Planar Reflection)。
Unity 官方也提供了初步的水体着色教程,主要谈到了水体颜色的过渡以及基于两个噪声图的波浪动画。在此基础上我加入了反射和折射:
平面反射(Planar Reflection)
首先要像OpaqueTexture一样,让camera准备好一张场景处于反射空间的图像,实现的代码在Unity的standard assets里面就有包含,BoatAttack案例里面也有(见PlanarReflections.cs脚本),然后在shader里面取出这张准备好了的反射贴图给水面着色:
反射强度是跟视角有关的,投向水面的视线与水面法线夹角越大,反射程度越强,这恰恰就是Fresnel Effect的特征,于是我加入了一个Fresnel Effect节点来控制反射程度:
折射(Refraction)
折射其实只是把OpaqueTexture做扭曲,关键点是要“过滤”出那些不可以被扭曲的点,即当物体是在水面上方,是不能发生折射扭曲的,这点在catlikecoding大神的流体模拟之Looking Through Water里面有详细说明:
与Looking Through Water不同,我用Shader Graph Node来实现“过滤” 。先回到“扭曲”效果的本质,其实就是取旁边的点的颜色。先看看旁边的点是不是可以取,如果不可以取,就用回自己本来的颜色,即达到过滤的目的。旁边的点的深度值如果比自己的小,说明旁边的点是前景,自己是背景:
浮力模拟(Bobbing)
由于不是做复杂的类似BoatAttack的水面交互,于是浮力模拟我用的是简单的PerlinNoise动画来模拟,即并没有真正的模拟浮力,只是看起来像是浮力在作用。UnityAPI文档在讲述Mathf.PerlinNoise这个API的时候,恰恰给出了一个Bobbing Animation的例子:
// "Bobbing" animation from 1D Perlin noise. public class Example : MonoBehaviour { ... void Update() { float height = heightScale * Mathf.PerlinNoise(Time.time * xScale, 0.0f); Vector3 pos = transform.position; pos.y = height; transform.position = pos; } }
焦散效应( Caustics )
在真机上运行效果不佳,待日后研究:

大佬,请问一下PlanarReflections.cs脚本要怎么才能使用,我挂载到相机上面,然后Target也选了,unity报警报Renderer at index 1 is missing for camera Planar Reflections, falling back to Default Renderer. UniversalRenderPipelineAsset_Renderer
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)