Cocos Creator 2.4.2 2D扭曲Shader:3种噪声图实现水波与热浪特效实战指南
在2D游戏开发中,动态视觉特效是提升游戏沉浸感的关键要素。本文将深入探讨如何利用三种不同类型的噪声图(Perlin、Simplex、Value)在Cocos Creator 2.4.2中实现专业级的2D扭曲效果,包括水波荡漾、热浪扭曲等常见特效场景。
1. 扭曲Shader核心原理与基础实现
2D扭曲效果的本质是通过对纹理坐标(UV)进行有规律的扰动来实现的。与传统直接修改顶点位置不同,这种技术能在不增加几何复杂度的情况下创造丰富的动态视觉效果。
核心算法流程:
- 采样噪声图获取扰动值
- 根据时间变量动态更新扰动
- 将扰动应用于原始UV坐标
- 使用扰动后的UV采样主纹理
基础实现代码框架如下:
CCProgram fs %{ precision highp float; uniform sampler2D noiseTex; // 噪声纹理 uniform float speed; // 扰动速度 uniform float strength; // 扰动强度 void main() { // 动态噪声采样(加入时间变量) vec2 noiseUV = v_uv0 + cc_time.x * speed; vec4 noise = texture2D(noiseTex, noiseUV); // UV扰动计算 vec2 distortedUV = v_uv0 + (noise.xy * 2.0 - 1.0) * strength; // 最终纹理采样 gl_FragColor = texture2D(texture, distortedUV); } }%关键提示:噪声图的Wrap Mode必须设置为Repeat模式,否则在边界处会出现不自然的接缝
2. 三种噪声图特性对比与选择
不同类型的噪声图会产生截然不同的扭曲效果。我们重点分析Perlin、Simplex和Value三种经典噪声的视觉特征与性能表现。
2.1 Perlin噪声
视觉特征:
- 自然有机的波纹图案
- 中等频率细节丰富
- 适合模拟自然现象(水波、云朵)
// Perlin噪声实现示例 float perlinNoise(vec2 uv) { vec2 i = floor(uv); vec2 f = fract(uv); // 哈希函数生成随机梯度 vec2 grad[4]; grad[0] = random2(i); grad[1] = random2(i + vec2(1.0, 0.0)); grad[2] = random2(i + vec2(0.0, 1.0)); grad[3] = random2(i + vec2(1.0, 1.0)); // 双线性插值 float n = mix( mix(dot(grad[0], f), dot(grad[1], f - vec2(1.0, 0.0)), smoothstep(0.0, 1.0, f.x)), mix(dot(grad[2], f - vec2(0.0, 1.0)), dot(grad[3], f - vec2(1.0, 1.0)), smoothstep(0.0, 1.0, f.x)), smoothstep(0.0, 1.0, f.y) ); return n * 0.5 + 0.5; // 归一化到[0,1] }2.2 Simplex噪声
视觉特征:
- 更均匀的能量分布
- 计算效率高于Perlin噪声
- 适合需要高性能的场景
// Simplex噪声简化实现 float simplexNoise(vec2 v) { const float K1 = 0.366025404; // (sqrt(3)-1)/2 const float K2 = 0.211324865; // (3-sqrt(3))/6 vec2 i = floor(v + (v.x+v.y)*K1); vec2 a = v - i + (i.x+i.y)*K2; float m = step(a.y,a.x); vec2 o = vec2(m,1.0-m); vec2 b = a - o + K2; vec2 c = a - 1.0 + 2.0*K2; vec3 h = max(0.5-vec3(dot(a,a), dot(b,b), dot(c,c)), 0.0); vec3 n = h*h*h*h*vec3( dot(a,hash22(i)), dot(b,hash22(i+o)), dot(c,hash22(i+1.0)) ); return dot(n, vec3(70.0)); }2.3 Value噪声
视觉特征:
- 明显的网格状结构
- 计算最简单
- 适合需要明确方向性的效果
| 噪声类型 | 视觉特征 | 计算复杂度 | 适用场景 | 动态效果平滑度 |
|---|---|---|---|---|
| Perlin | 自然有机 | 中等 | 水波、云朵 | ★★★★☆ |
| Simplex | 均匀分布 | 较低 | 高性能需求 | ★★★★★ |
| Value | 网格明显 | 最低 | 机械/人工效果 | ★★☆☆☆ |
3. 完整Effect实现与参数优化
下面提供一个完整的扭曲特效Effect实现,包含三种噪声模式切换和详细的参数控制:
CCEffect %{ techniques: - passes: - vert: vs frag: fs properties: texture: { value: white } noiseTex: { value: white } noiseType: { value: 0, editor: { tooltip: "0=Perlin, 1=Simplex, 2=Value", range: [0, 2] } } speed: { value: 0.5, editor: { tooltip: "扰动速度", range: [0, 2] } } strength: { value: 0.1, editor: { tooltip: "扰动强度", range: [0, 0.5] } } direction: { value: [1,1], editor: { tooltip: "扰动方向向量" } } }% CCProgram fs %{ // ... 包含前面介绍的噪声函数 ... void main() { vec2 noiseUV = v_uv0 + cc_time.x * speed * direction; float noiseValue; // 根据类型选择噪声算法 switch(noiseType) { case 0: noiseValue = perlinNoise(noiseUV * 5.0); break; case 1: noiseValue = simplexNoise(noiseUV * 8.0); break; case 2: noiseValue = valueNoise(noiseUV * 10.0); break; } vec2 noiseVec = vec2( noiseValue, noiseValue // 可改为使用噪声图的RG通道 ); vec2 distortedUV = v_uv0 + (noiseVec * 2.0 - 1.0) * strength; gl_FragColor = texture2D(texture, distortedUV) * v_color; } }%性能优化建议:在移动设备上,建议优先使用Simplex噪声,其计算效率比Perlin噪声高约30%
4. 进阶技巧与实战应用
4.1 多层噪声混合
通过叠加不同尺度的噪声可以创造出更丰富的视觉效果:
// 多层噪声混合示例 float fractalNoise(vec2 uv) { float total = 0.0; float frequency = 1.0; float amplitude = 1.0; float persistence = 0.5; for(int i=0; i<4; i++) { total += perlinNoise(uv * frequency) * amplitude; frequency *= 2.0; amplitude *= persistence; } return total; }4.2 方向性控制
通过分离X/Y方向的扰动强度,可以实现更灵活的效果控制:
uniform vec2 strengthXY; // 分别控制XY方向强度 void applyDistortion(inout vec2 uv) { vec2 noise = texture2D(noiseTex, uv + cc_time.x * speed).xy; uv.x += (noise.x * 2.0 - 1.0) * strengthXY.x; uv.y += (noise.y * 2.0 - 1.0) * strengthXY.y; }4.3 热浪特效实现
典型的热浪效果需要结合扭曲和颜色偏移:
void heatWaveEffect() { // 基础扭曲 vec2 distortedUV = getDistortedUV(v_uv0); // 颜色通道偏移(模拟光折射) float offset = strength * 0.02; vec4 colorR = texture2D(texture, distortedUV + vec2(offset, 0)); vec4 colorB = texture2D(texture, distortedUV - vec2(offset, 0)); gl_FragColor = vec4(colorR.r, v_color.g, colorB.b, v_color.a); }在实际项目中,我发现将Perlin噪声用于水波效果时,配合0.3-0.5的速度参数和0.05-0.1的强度参数能产生最自然的效果。而对于热浪扭曲,Simplex噪声配合颜色偏移技术往往能获得更好的视觉表现。