1. 噪声纹理动态扭曲的核心原料第一次接触2D扭曲特效时我被一个简单问题困扰了很久为什么静态图片加上噪声纹理就能产生流动的波纹后来在项目里踩过几次坑才明白噪声纹理本质上就是一张记录随机值的灰度图它的每个像素点存储着0到1之间的随机数。在Cocos Creator中我们可以用这张数字砂纸来打磨UV坐标。选择噪声纹理时有三个关键点无缝平铺必须使用Repeat模式的Wrap设置否则边缘会出现明显接缝。实测用Photoshop生成噪声图时记得勾选拼贴选项分辨率适配1024x1024的噪声图适合全屏特效但手机端建议压缩到512x512。我曾用2048x2048的图导致低端机帧率直接腰斩通道分离RGBA四个通道可以独立使用比如用R通道控制水平扭曲G通道控制垂直扭曲// 基础噪声采样代码 uniform sampler2D noisetex; vec4 noise texture2D(noisetex, v_uv0);提示Cocos内置的cc-noise纹理是个不错的起点但自定义噪声图能实现更独特的扭曲风格2. UV扰动让静态纹理动起来UV坐标就像贴在模型表面的邮票扰动就是让这些邮票产生微小位移。这里有个新手容易忽略的细节直接修改v_uv0会导致材质实例共享变形效果正确做法应该用临时变量vec2 distortedUV v_uv0 noise.xy * strength; vec4 color texture2D(mainTexture, distortedUV);通过调节strength参数可以实现不同强度的扭曲效果0.01-0.05轻微热浪效果0.1-0.3强烈水波纹0.5以上抽象艺术风格我在最近的项目中发现对UV进行分层扰动能增强立体感。比如用大尺度噪声做整体形变叠加小尺度噪声制造细节vec2 largeNoise texture2D(noise1, v_uv0*0.5).xy * 0.2; vec2 smallNoise texture2D(noise2, v_uv0*3.0).xy * 0.05; vec2 finalUV v_uv0 largeNoise smallNoise;3. 时间变量注入动态灵魂静态噪声只能产生固定扭曲引入cc_time才真正让特效活起来。这里有个性能优化技巧不要直接使用cc_time.x应该通过uniform传入速度系数uniform float speed; vec2 scrollingUV v_uv0 vec2(cc_time.x * speed, 0);不同运动方向会产生迥异的效果水平滚动模拟横向水流垂直滚动创造上升蒸汽效果对角线运动适合魔法漩涡特效在实现角色受热扭曲时我开发了个速度曲线控制器// 脉冲式波动公式 float pulse sin(cc_time.x * 2.0) * 0.5 0.5; vec2 pulseUV v_uv0 noise.xy * strength * pulse;4. 完整Shader实现与参数调试把上述技术组合起来这是个经过项目验证的完整实现方案CCEffect %{ techniques: [{ passes: [{ vert: vs, frag: fs, properties: { mainTexture: { value: white }, noiseTexture: { value: gray }, speedX: { value: 0.1, range: [0, 1] }, speedY: { value: 0.05, range: [0, 1] }, strength: { value: 0.1, range: [0, 0.5] } } }] }] }% CCProgram fs %{ void frag() { vec2 scrollUV v_uv0 vec2(cc_time.x * speedX, cc_time.x * speedY); vec4 noise texture2D(noiseTexture, scrollUV); vec2 distortedUV v_uv0 (noise.xy * 2.0 - 1.0) * strength; gl_FragColor texture2D(mainTexture, distortedUV); } }%调试时有几个实用技巧先调速度0.1-0.3范围测试再调强度从0.01开始逐步增加最后尝试不同噪声图柏林噪声效果更自然记得在Cocos编辑器中给材质暴露调节参数material.setProperty(strength, 0.2); material.setProperty(speedX, 0.15);5. 实战案例三套经典特效配方水波纹特效使用蓝噪波纹理Y轴速度设为X轴的1/2强度参数动画0.03 → 0.1 → 0.03vec2 rippleUV v_uv0 vec2( sin(cc_time.x v_uv0.y * 20.0) * 0.02, cos(cc_time.x v_uv0.x * 20.0) * 0.01 );热浪扭曲红噪波纹理高温区域增加垂直扰动配合颜色偏移更逼真float heatWave smoothstep(0.3, 0.7, v_uv0.y); vec2 heatUV v_uv0 noise.xz * strength * heatWave;魔法传送门多层噪声混合径向UV变形添加扭曲边缘光vec2 centerVec v_uv0 - 0.5; float radius length(centerVec) * 2.0; vec2 warpUV v_uv0 centerVec * sin(radius * 10.0 - cc_time.x * 3.0) * 0.1;6. 性能优化指南在低端设备上测试时我总结了这些优化经验减少采样次数合并噪声通道避免多次texture2D调用控制渲染区域对局部物体使用扭曲而非全屏后处理精度选择移动端用mediump代替highp动态降级根据帧率自动降低strength值特别要注意的是Android设备上sin/cos函数开销较大可以用噪声贴图预存波形// 替代直接计算 // float wave sin(cc_time.x * 10.0); float wave texture2D(noiseTex, vec2(cc_time.x * 0.1, 0.5)).r * 2.0 - 1.0;7. 常见问题排查问题1扭曲边缘出现接缝检查噪声图Wrap Mode是否为Repeat确保UV坐标在[0,1]范围内使用fract函数问题2扭曲效果时强时弱确认cc_time传递正确检查是否有多余的材质实例化问题3移动端显示异常测试不同GPU厂商设备检查OpenGL ES版本兼容性尝试关闭抗锯齿最近帮团队解决过一个棘手问题扭曲效果在iOS上正常但在某些Android设备失效。最后发现是噪声图的mipmap生成导致采样异常关闭mipmap后问题解决。这也提醒我们真机测试环节绝对不能省略。
Cocos Creator - 2D扭曲Shader进阶:UV扰动动画与噪声纹理实战
发布时间:2026/7/5 11:01:29
1. 噪声纹理动态扭曲的核心原料第一次接触2D扭曲特效时我被一个简单问题困扰了很久为什么静态图片加上噪声纹理就能产生流动的波纹后来在项目里踩过几次坑才明白噪声纹理本质上就是一张记录随机值的灰度图它的每个像素点存储着0到1之间的随机数。在Cocos Creator中我们可以用这张数字砂纸来打磨UV坐标。选择噪声纹理时有三个关键点无缝平铺必须使用Repeat模式的Wrap设置否则边缘会出现明显接缝。实测用Photoshop生成噪声图时记得勾选拼贴选项分辨率适配1024x1024的噪声图适合全屏特效但手机端建议压缩到512x512。我曾用2048x2048的图导致低端机帧率直接腰斩通道分离RGBA四个通道可以独立使用比如用R通道控制水平扭曲G通道控制垂直扭曲// 基础噪声采样代码 uniform sampler2D noisetex; vec4 noise texture2D(noisetex, v_uv0);提示Cocos内置的cc-noise纹理是个不错的起点但自定义噪声图能实现更独特的扭曲风格2. UV扰动让静态纹理动起来UV坐标就像贴在模型表面的邮票扰动就是让这些邮票产生微小位移。这里有个新手容易忽略的细节直接修改v_uv0会导致材质实例共享变形效果正确做法应该用临时变量vec2 distortedUV v_uv0 noise.xy * strength; vec4 color texture2D(mainTexture, distortedUV);通过调节strength参数可以实现不同强度的扭曲效果0.01-0.05轻微热浪效果0.1-0.3强烈水波纹0.5以上抽象艺术风格我在最近的项目中发现对UV进行分层扰动能增强立体感。比如用大尺度噪声做整体形变叠加小尺度噪声制造细节vec2 largeNoise texture2D(noise1, v_uv0*0.5).xy * 0.2; vec2 smallNoise texture2D(noise2, v_uv0*3.0).xy * 0.05; vec2 finalUV v_uv0 largeNoise smallNoise;3. 时间变量注入动态灵魂静态噪声只能产生固定扭曲引入cc_time才真正让特效活起来。这里有个性能优化技巧不要直接使用cc_time.x应该通过uniform传入速度系数uniform float speed; vec2 scrollingUV v_uv0 vec2(cc_time.x * speed, 0);不同运动方向会产生迥异的效果水平滚动模拟横向水流垂直滚动创造上升蒸汽效果对角线运动适合魔法漩涡特效在实现角色受热扭曲时我开发了个速度曲线控制器// 脉冲式波动公式 float pulse sin(cc_time.x * 2.0) * 0.5 0.5; vec2 pulseUV v_uv0 noise.xy * strength * pulse;4. 完整Shader实现与参数调试把上述技术组合起来这是个经过项目验证的完整实现方案CCEffect %{ techniques: [{ passes: [{ vert: vs, frag: fs, properties: { mainTexture: { value: white }, noiseTexture: { value: gray }, speedX: { value: 0.1, range: [0, 1] }, speedY: { value: 0.05, range: [0, 1] }, strength: { value: 0.1, range: [0, 0.5] } } }] }] }% CCProgram fs %{ void frag() { vec2 scrollUV v_uv0 vec2(cc_time.x * speedX, cc_time.x * speedY); vec4 noise texture2D(noiseTexture, scrollUV); vec2 distortedUV v_uv0 (noise.xy * 2.0 - 1.0) * strength; gl_FragColor texture2D(mainTexture, distortedUV); } }%调试时有几个实用技巧先调速度0.1-0.3范围测试再调强度从0.01开始逐步增加最后尝试不同噪声图柏林噪声效果更自然记得在Cocos编辑器中给材质暴露调节参数material.setProperty(strength, 0.2); material.setProperty(speedX, 0.15);5. 实战案例三套经典特效配方水波纹特效使用蓝噪波纹理Y轴速度设为X轴的1/2强度参数动画0.03 → 0.1 → 0.03vec2 rippleUV v_uv0 vec2( sin(cc_time.x v_uv0.y * 20.0) * 0.02, cos(cc_time.x v_uv0.x * 20.0) * 0.01 );热浪扭曲红噪波纹理高温区域增加垂直扰动配合颜色偏移更逼真float heatWave smoothstep(0.3, 0.7, v_uv0.y); vec2 heatUV v_uv0 noise.xz * strength * heatWave;魔法传送门多层噪声混合径向UV变形添加扭曲边缘光vec2 centerVec v_uv0 - 0.5; float radius length(centerVec) * 2.0; vec2 warpUV v_uv0 centerVec * sin(radius * 10.0 - cc_time.x * 3.0) * 0.1;6. 性能优化指南在低端设备上测试时我总结了这些优化经验减少采样次数合并噪声通道避免多次texture2D调用控制渲染区域对局部物体使用扭曲而非全屏后处理精度选择移动端用mediump代替highp动态降级根据帧率自动降低strength值特别要注意的是Android设备上sin/cos函数开销较大可以用噪声贴图预存波形// 替代直接计算 // float wave sin(cc_time.x * 10.0); float wave texture2D(noiseTex, vec2(cc_time.x * 0.1, 0.5)).r * 2.0 - 1.0;7. 常见问题排查问题1扭曲边缘出现接缝检查噪声图Wrap Mode是否为Repeat确保UV坐标在[0,1]范围内使用fract函数问题2扭曲效果时强时弱确认cc_time传递正确检查是否有多余的材质实例化问题3移动端显示异常测试不同GPU厂商设备检查OpenGL ES版本兼容性尝试关闭抗锯齿最近帮团队解决过一个棘手问题扭曲效果在iOS上正常但在某些Android设备失效。最后发现是噪声图的mipmap生成导致采样异常关闭mipmap后问题解决。这也提醒我们真机测试环节绝对不能省略。