Unity ShaderGraph Input节点实战:用UV和Time节点5分钟做出流动水面效果
Unity ShaderGraph实战:5分钟打造动态水面效果
水面效果是游戏开发中最常见的自然元素之一。想象一下,当玩家走过湖边,看到微风拂过水面泛起的涟漪,或是暴风雨中汹涌的波涛,这些动态效果都能极大提升游戏的沉浸感。传统的水面着色器编写需要深厚的图形学知识,而ShaderGraph让这一切变得可视化且直观。本文将带你用UV和Time这两个核心Input节点,快速实现一个基础但效果出众的动态水面。
1. 准备工作与环境搭建
在开始制作水面效果前,我们需要确保开发环境配置正确。首先创建一个新的URP项目(Universal Render Pipeline),这是Unity推荐的现代渲染管线,对ShaderGraph有更好的支持。
- 在Unity Hub中新建项目时选择URP模板
- 创建完成后,在项目窗口中右键选择Create > Shader Graph > URP > Unlit Shader Graph(因为我们先实现基础效果,后续可升级为PBR水面)
- 将新建的ShaderGraph命名为"WaterSurface"
提示:如果找不到ShaderGraph创建选项,请确保已安装ShaderGraph包(Window > Package Manager中搜索安装)
接下来我们需要准备一张基础水面纹理。可以在任何素材网站搜索"water normal map"找到合适的法线贴图,这将作为我们水面波纹的基础。将下载的贴图导入Unity后,记得在Inspector中将Texture Type设置为Normal map。
2. UV动画:创造水面流动感
UV动画是Shader中实现动态效果的核心技术之一。原理很简单:通过随时间改变UV坐标,让贴图"移动"起来。
打开刚创建的WaterSurface ShaderGraph,我们先建立基础的UV流动:
- 在空白处右键创建UV节点(Input > Geometry > UV)
- 添加Time节点(Input > Basic > Time)
- 创建Multiply节点,将Time与一个Vector2常量连接(如(0.02, 0.02)控制速度)
- 使用Add节点将UV和乘后的Time相加
此时你的网络应该类似这样:
UV -> Add Time -> Multiply -> Add Vector2(0.02,0.02) -> Multiply这种基础UV动画会让整个贴图朝右下角匀速移动。但真实的水面运动更加复杂,我们需要更丰富的层次感。
3. 多层纹理混合:增加水面细节
单一方向的流动看起来会很假。专业的水面效果通常使用多层纹理以不同速度和方向混合:
- 复制刚才的UV动画网络,创建第二套(建议将速度改为(0.03, -0.01))
- 为两套UV网络分别采样不同的法线贴图(可使用同一张贴图但缩放不同)
- 添加Blend节点(Normal Blend或Height Blend模式)混合两个法线结果
// 第一层UV动画 UV -> Add1 Time -> Multiply1 -> Add1 Vector2(0.02,0.02) -> Multiply1 // 第二层UV动画 UV -> Add2 Time -> Multiply2 -> Add2 Vector2(0.03,-0.01) -> Multiply2 // 采样与混合 Add1 -> SampleTexture2D1 -> Blend Add2 -> SampleTexture2D2 -> Blend注意:纹理采样时,建议将Wrap Mode设置为Repeat,这样UV超出1.0时会自动平铺而非拉伸
4. 添加顶点动画:模拟波浪起伏
仅有表面法线变化还不够,真实水面会有高度起伏。我们可以用顶点位移来模拟:
- 创建Position节点(Input > Geometry > Position)
- 使用之前混合的法线贴图的R或G通道(代表水平方向的高度变化)
- 通过Remap节点将法线值从[0,1]映射到[-0.1,0.1]作为位移幅度
- 将结果与原始Position相加后输出到Master节点的Position端口
Blend -> Split -> R通道 -> Remap(0,1,-0.1,0.1) -> Add Position -> Add -> Master_Position为增强效果,可以再添加一个基于世界XZ坐标的Sine波:
Position -> Split -> XZ -> Multiply(0.5) -> Sine -> Multiply(0.05) -> Add这样水面会有基础的大波浪运动,配合之前的细节法线,效果立即生动起来。
5. 镜面反射与边缘光:提升视觉质感
基础动画完成后,我们需要添加光学特性使水面更真实:
- 创建Normal Vector节点(使用之前混合的法线结果)
- 添加View Direction节点并归一化
- 使用Dot Product节点计算视角与法线的夹角
- 通过Power节点控制高光强度(如Power=50)
- 输出到Master节点的Smoothness和Specular
Blend -> NormalVector -> DotProduct ViewDirection -> Normalize -> DotProduct DotProduct -> Power(50) -> Master_Specular边缘光(Fresnel效应)可以通过类似方式实现:
NormalVector -> FresnelEffect -> Master_Emission6. 参数优化与性能考量
现在我们的水面已经具备基本所有元素,最后需要调整参数并考虑性能:
- 速度控制:建议将Time乘数设为可调参数(右键Create Property)
- 幅度控制:顶点位移和法线强度也应暴露为参数
- LOD处理:远处水面可以简化计算
- 纹理压缩:确保法线贴图使用适当压缩格式(如BC5/DXT5nm)
参数建议值:
| 参数 | 建议值 | 说明 |
|---|---|---|
| 速度1 | (0.02,0.02) | 基础层流动速度 |
| 速度2 | (0.03,-0.01) | 细节层流动速度 |
| 位移幅度 | [-0.1,0.1] | 波浪高度范围 |
| 高光强度 | 50-100 | 水面反光程度 |
在项目中使用时,可以根据相机距离动态调整这些参数,远处水面可以减少纹理层数或禁用顶点动画。
7. 进阶扩展思路
基础效果实现后,可以考虑以下增强方向:
- 焦散效果:添加Caustics纹理动画模拟水下光斑
- 泡沫系统:在水体边缘或物体周围添加泡沫痕迹
- 交互波纹:通过脚本传递物体位置信息生成局部涟漪
- 天气影响:根据风雨强度参数化控制波浪幅度
- 深度渐变:浅水区更透明且波浪更明显
实现交互波纹的简单方法:
- 在C#脚本中定义可交互物体位置数组
- 通过Material.SetVectorArray传递到Shader
- 在Shader中计算每个位置的距离并叠加波纹
// C#脚本 public Transform[] interactObjects; private Vector4[] positions; void Update() { positions = interactObjects.Select(t => (Vector4)t.position).ToArray(); material.SetVectorArray("_InteractPositions", positions); }// Shader中 for(int i=0; i<_Count; i++) { float dist = distance(_InteractPositions[i].xyz, worldPos); float wave = saturate(1-dist/_Radius) * sin(dist*_Frequency - _Time.y*_Speed); height += wave * _Amplitude; }这种技术可以让角色走过水面时产生真实的涟漪扩散效果。
