第9.1章:2D渐变精灵着色器
在2D游戏开发中,视觉效果是创造吸引力的重要手段。本章将详细介绍如何在Cocos Creator中实现各种2D精灵特效,包括线性渐变、径向渐变和动态渐变。
🎯 学习目标
通过本章学习,你将掌握:
- 2D渐变的数学原理和实现方法
- 在Cocos Creator中创建各种类型的渐变着色器
- 各种渐变类型的实现(线性、径向、角度渐变)
- 动态渐变和动画效果控制
💡 渐变效果原理
渐变的基本类型
2D渐变主要包含以下几种类型:
线性渐变(Linear Gradient)
径向渐变(Radial Gradient)
角度渐变(Angular Gradient)
动态渐变(Animated Gradient)
📐 渐变数学原理
线性渐变计算
1 2 3 4 5 6 7 8 9 10 11
| float linearGradient(vec2 uv, vec2 direction, vec2 offset) { vec2 normalizedDir = normalize(direction); float projection = dot(uv - offset, normalizedDir); return clamp(projection, 0.0, 1.0); }
|
径向渐变计算
1 2 3 4 5 6 7 8
| float radialGradient(vec2 uv, vec2 center, float radius) { float distance = length(uv - center); return clamp(1.0 - distance / radius, 0.0, 1.0); }
|
角度渐变计算
1 2 3 4 5 6 7 8 9 10 11 12
| float angularGradient(vec2 uv, vec2 center, float rotation) { vec2 dir = uv - center; float angle = atan(dir.y, dir.x); angle += rotation; return (angle + PI) / (2.0 * PI); }
|
🔧 基础线性渐变着色器
简单线性渐变实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| CCEffect: techniques: - name: opaque passes: - vert: sprite-vs frag: linear-gradient-fs properties: mainTexture: { value: white } startColor: { value: [1, 0, 0, 1], editor: { type: color } } endColor: { value: [0, 0, 1, 1], editor: { type: color } } gradientDir: { value: [1, 0], editor: { tooltip: "渐变方向" } } gradientOffset: { value: [0, 0], editor: { tooltip: "渐变偏移" } } gradientPower: { value: 1.0, range: [0.1, 5.0], editor: { tooltip: "渐变强度" } }
CCProgram sprite-vs %{ precision highp float; #include <builtin/uniforms/cc-global> #include <builtin/uniforms/cc-local> in vec3 a_position; in vec2 a_texCoord; in vec4 a_color; out vec2 v_uv; out vec4 v_color; vec4 vert() { vec4 pos = vec4(a_position, 1); pos = cc_matWorld * pos; pos = cc_matViewProj * pos; v_uv = a_texCoord; v_color = a_color; return pos; } }%
CCProgram linear-gradient-fs %{ precision highp float; #include <builtin/uniforms/cc-global> in vec2 v_uv; in vec4 v_color; uniform sampler2D mainTexture; uniform GradientUniforms { vec4 startColor; vec4 endColor; vec2 gradientDir; vec2 gradientOffset; }; vec4 frag() { vec4 texColor = texture(mainTexture, v_uv); vec2 normalizedDir = normalize(gradientDir); float gradientFactor = dot(v_uv - gradientOffset, normalizedDir); gradientFactor = clamp(gradientFactor, 0.0, 1.0); vec4 gradientColor = mix(startColor, endColor, gradientFactor); vec4 finalColor = texColor * gradientColor * v_color; return finalColor; } }%
|
多色线性渐变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| CCProgram multi-color-gradient-fs %{ precision highp float; uniform MultiGradientUniforms { vec4 color1; vec4 color2; vec4 color3; vec4 color4; vec2 gradientDir; float segments; }; vec4 multiColorGradient(float factor) { float segmentSize = 1.0 / segments; float segment = floor(factor / segmentSize); float localFactor = (factor - segment * segmentSize) / segmentSize; if (segment < 1.0) { return mix(color1, color2, localFactor); } else if (segment < 2.0) { return mix(color2, color3, localFactor); } else { return mix(color3, color4, localFactor); } } vec4 frag() { vec4 texColor = texture(mainTexture, v_uv); vec2 normalizedDir = normalize(gradientDir); float gradientFactor = dot(v_uv, normalizedDir); gradientFactor = clamp(gradientFactor, 0.0, 1.0); vec4 gradientColor = multiColorGradient(gradientFactor); return texColor * gradientColor * v_color; } }%
|
?? 径向渐变着色器
基础径向渐变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| CCProgram radial-gradient-fs %{ precision highp float; uniform RadialGradientUniforms { vec4 centerColor; vec4 edgeColor; vec2 center; float radius; float smoothness; }; vec4 frag() { vec4 texColor = texture(mainTexture, v_uv); float distance = length(v_uv - center); float normalizedDistance = clamp(distance / radius, 0.0, 1.0); normalizedDistance = smoothstep(0.0, smoothness, normalizedDistance); vec4 gradientColor = mix(centerColor, edgeColor, normalizedDistance); return texColor * gradientColor * v_color; } }%
|
圆形径向渐变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| CCProgram elliptical-gradient-fs %{ uniform EllipticalUniforms { vec4 centerColor; vec4 edgeColor; vec2 center; vec2 radius; float rotation; }; mat2 rotate2D(float angle) { float s = sin(angle); float c = cos(angle); return mat2(c, -s, s, c); } vec4 frag() { vec4 texColor = texture(mainTexture, v_uv); vec2 pos = v_uv - center; pos = rotate2D(rotation) * pos; vec2 normalizedPos = pos / radius; float distance = length(normalizedPos); float gradientFactor = clamp(distance, 0.0, 1.0); vec4 gradientColor = mix(centerColor, edgeColor, gradientFactor); return texColor * gradientColor * v_color; } }%
|
?? 角度渐变着色器
单色角度渐变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| CCProgram angular-gradient-fs %{ precision highp float; uniform AngularUniforms { vec2 center; float rotation; float brightness; float saturation; }; vec3 hsv2rgb(vec3 c) { vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); } vec4 frag() { vec4 texColor = texture(mainTexture, v_uv); vec2 dir = v_uv - center; float angle = atan(dir.y, dir.x); angle += rotation; float hue = (angle + PI) / (2.0 * PI); vec3 hsv = vec3(hue, saturation, brightness); vec3 gradientColor = hsv2rgb(hsv); return texColor * vec4(gradientColor, 1.0) * v_color; } }%
|
双色角度渐变
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| CCProgram dual-angular-gradient-fs %{ uniform DualAngularUniforms { vec4 color1; vec4 color2; vec2 center; float rotation; float sharpness; }; vec4 frag() { vec4 texColor = texture(mainTexture, v_uv); vec2 dir = v_uv - center; float angle = atan(dir.y, dir.x) + rotation; float factor = sin(angle) * 0.5 + 0.5; factor = pow(factor, sharpness); vec4 gradientColor = mix(color1, color2, factor); return texColor * gradientColor * v_color; } }%
|
? 静态效果效果
时间效果效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| CCProgram flowing-gradient-fs %{ precision highp float; #include <builtin/uniforms/cc-global> uniform FlowingUniforms { vec4 color1; vec4 color2; vec2 flowDirection; float flowSpeed; float waveLength; float intensity; }; vec4 frag() { vec4 texColor = texture(mainTexture, v_uv); vec2 flow = flowDirection * cc_time.x * flowSpeed; float wave = sin((dot(v_uv, normalize(flowDirection)) + flow.x) * waveLength); float factor = (wave + 1.0) * 0.5; factor = mix(0.5, factor, intensity); vec4 gradientColor = mix(color1, color2, factor); return texColor * gradientColor * v_color; } }%
|
脉冲效果效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| CCProgram pulse-gradient-fs %{ uniform PulseUniforms { vec4 baseColor; vec4 pulseColor; vec2 center; float pulseSpeed; float pulseRadius; float pulseWidth; }; vec4 frag() { vec4 texColor = texture(mainTexture, v_uv); float distance = length(v_uv - center); float pulse = sin(cc_time.x * pulseSpeed - distance * pulseRadius); pulse = smoothstep(-pulseWidth, pulseWidth, pulse); vec4 gradientColor = mix(baseColor, pulseColor, pulse); return texColor * gradientColor * v_color; } }%
|
?? 实际应用效果
1. 能量条效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| CCProgram energy-bar-fs %{ uniform EnergyBarUniforms { vec4 emptyColor; vec4 fullColor; vec4 criticalColor; float fillAmount; float criticalThreshold; }; vec4 frag() { vec4 texColor = texture(mainTexture, v_uv); bool isFilled = v_uv.x <= fillAmount; vec4 gradientColor; if (isFilled) { if (fillAmount <= criticalThreshold) { float flash = sin(cc_time.x * 10.0) * 0.5 + 0.5; gradientColor = mix(criticalColor, fullColor, flash); } else { float localFactor = v_uv.x / fillAmount; gradientColor = mix(fullColor, emptyColor, localFactor * 0.3); } } else { gradientColor = emptyColor; } return texColor * gradientColor * v_color; } }%
|
2. 按钮发光效果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| CCProgram button-glow-fs %{ uniform GlowUniforms { vec4 baseColor; vec4 glowColor; float glowIntensity; float glowRadius; vec2 glowCenter; }; vec4 frag() { vec4 texColor = texture(mainTexture, v_uv); float distance = length(v_uv - glowCenter); float glow = exp(-distance * glowRadius) * glowIntensity; glow = clamp(glow, 0.0, 1.0); vec4 finalColor = mix(baseColor, glowColor, glow); finalColor += glowColor * glow * 0.5; return texColor * finalColor * v_color; } }%
|
?? 优化效果
1. 预先优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
out float v_gradientFactor;
void vert() { vec2 normalizedDir = normalize(gradientDir); v_gradientFactor = dot(a_texCoord - gradientOffset, normalizedDir); }
vec4 frag() { float factor = clamp(v_gradientFactor, 0.0, 1.0); vec4 gradientColor = mix(startColor, endColor, factor); }
|
2. 使用LUT优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| uniform sampler2D gradientLUT;
vec4 frag() { vec4 texColor = texture(mainTexture, v_uv); float factor = computeGradientFactor(v_uv); vec4 gradientColor = texture(gradientLUT, vec2(factor, 0.5)); return texColor * gradientColor * v_color; }
|
?? 本章总结
通过本章学习,我们掌握了:
- ? 2D渐变的数学原理和实现
- ? 线性、径向、角度渐变技术
- ? 动态渐变和动画效果
- ? 完整的TypeScript控制系统
?? 下一步学习
掌握2D渐变精灵着色器后,建议继续学习:
👉 第9.2章:2D波纹扭曲着色器
?? 实践练习
- 创建练习: 创建一个UI按钮的渐变效果系统
- 创建练习: 实现血条的动态渐变显示
- 应用练习: 开发技能图标的闪烁渐变特效
系列导航