
水波纹
在 Unity URP 中实现多层法线贴图叠加的动态水面,是让水体看起来“灵动”且具有层次感的关键。如果只用一张法线贴图,水面看起来就像是在传送带上移动的塑料片。(TODO 没有试)
以下是实现这一效果的原理分析与具体实操指南。
1. 核心原理:波纹的干涉与叠加
实现自然水波纹的核心在于:利用物理上的干涉现象,打破单一纹理的周期性。
A. 叠加原理 (Blending)
我们通常使用两层(甚至更多)法线贴图。如果只是简单地将两个法线的 RGB 相加,会导致结果超出 [-1, 1] 范围,使光影畸变。
- 线性叠加 (Linear Blending): 将法线从 [0, 1] 重映射到 [-1, 1],相加后再归一化。效果一般,容易丢失细节。
- RNM 叠加 (Reoriented Normal Mapping): 这是目前主流的高级算法,它能旋转第二层法线使其贴合在第一层法线的表面上,完美保留两者的细节。
B. 动画原理 (Panner)
通过改变 UV 坐标的偏移值(Offset),让两张纹理以不同的方向、不同的速度和不同的缩放(Tiling)进行平移。
- 方向差异: 比如一层向西北,一层向正东,交汇处会产生错落感。
- 频率差异: 一层大波纹(低 Tiling),一层小碎波(高 Tiling)。
2. Unity URP 实现步骤 (Shader Graph 方案)
在 URP 中,使用 Shader Graph 是最直观、高效的方式。
第一步:基础属性定义
创建以下变量以便在材质球上调节:
- Main Normal & Second Normal (Texture2D)
- Normal Strength (Float)
- Wave Speed A & Wave Speed B (Vector2)
- Tiling A & Tiling B (Vector2)
第二步:让法线“动起来”
- 使用 Time 节点。
- 将 Time 乘以 Wave Speed A。
- 接入 Tiling And Offset 节点的 Offset 槽位。
- 将对应的 Tiling A 接入 Tiling 槽位。
- 使用 Sample Texture 2D 采样法线贴图(记得 Type 选为 Normal)。
- 对第二层法线重复上述步骤,但使用不同的速度和缩放。
第三步:法线混合 (The Magic)
在 Shader Graph 中,不需要自己写复杂的数学公式:
- 搜索并添加 Normal Blend 节点。
- 将第一层法线连入 In,第二层法线连入 Detail。
- 注意: 模式通常选 Default(即 RNM 算法)。
- 如果你想控制整体强度,在输出前加一个 Normal Strength 节点。
第四步:结合光照与 Fresnel (菲涅尔)
水面不仅仅有波纹,还需要反射和透明度:
- 将混合后的法线连入 Fragment 阶段的 Normal (Tangent Space)。
- Fresnel Effect: 使用 Fresnel 节点控制边缘反射。由于法线在动,菲涅尔效果也会随之抖动,产生波光粼粼的真实感。
- Smoothness: 调高平滑度(如 0.95 以上)。
3. 进阶 HLSL 代码实现 (可选)
如果你更喜欢写代码(Custom Function),核心的叠加代码如下:
// 1. UDN Blending (最简单)
float3 BlendNormals_UDN(float3 n1, float3 n2) {
return normalize(n1 + n2);
}
// 2. Whiteout Blending
float3 BlendNormals_Whiteout(float3 n1, float3 n2) {
n1 = n1 * 2.0 - 1.0;
n2 = n2 * 2.0 - 1.0;
return normalize(float3(n1.xy + n2.xy, n1.z * n2.z));
}
// 3. RNM (需要更多数据)
float3 BlendNormals_RNM(float3 n1, float3 n2, float3 tangent, float3 bitangent) {
n1 = n1 * 2.0 - 1.0;
n2 = n2 * 2.0 - 1.0;
// 构建旋转矩阵 [tangent, bitangent, n1]
float3x3 rotation = float3x3(tangent, bitangent, n1);
// 旋转n2到n1的坐标系
return normalize(mul(n2, rotation)); // 注意矩阵乘法顺序取决于坐标系定义
}
4. 优化小技巧
- UV 旋转: 除了平移,给其中一层增加微小的旋转,可以彻底消除纹理重复感。
- 深度衰减: 结合 Scene Depth,让浅水区透明,深水区深邃,配合动起来的法线,效果直接翻倍。
- 计算开销: 移动端建议只用两层法线;PC 端可以考虑三层(底层大浪 + 中层波纹 + 顶层微波)。
你想尝试把这个效果应用在特定场景(比如湖面还是大海)吗?我可以帮你针对性地调整参数设置。