第12.2章:Legacy Shader函数详解

在Legacy Shader中,函数是实现复杂效果的核心工具。本教程将深入讲解Legacy Shader中的函数定义、参数传递、优化技巧和最佳实践。

🎯 学习目标

  • 掌握Legacy Shader中函数的定义和使用
  • 理解函数参数传递机制
  • 学会函数优化和性能调优
  • 了解常用函数库的设计模式

📋 前置知识

  • 已完成第12.1章Legacy Shader介绍
  • 熟悉GLSL函数语法
  • 理解GPU并行计算特点

📝 Legacy Shader函数基础

函数定义语法

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
// Legacy Shader函数定义基础
CCProgram function-basics %{
precision highp float;

// 基本函数定义
float simpleFunction(float input) {
return input * 2.0;
}

// 多参数函数
vec3 calculateColor(vec3 baseColor, float intensity, float gamma) {
vec3 result = baseColor * intensity;
return pow(result, vec3(1.0 / gamma));
}

// 向量函数
vec2 rotateUV(vec2 uv, float angle) {
float c = cos(angle);
float s = sin(angle);
mat2 rotMatrix = mat2(c, -s, s, c);
return rotMatrix * (uv - 0.5) + 0.5;
}

// 矩阵函数
mat3 createRotationMatrix(vec3 axis, float angle) {
axis = normalize(axis);
float s = sin(angle);
float c = cos(angle);
float oc = 1.0 - c;

return mat3(
oc * axis.x * axis.x + c, oc * axis.x * axis.y - axis.z * s, oc * axis.z * axis.x + axis.y * s,
oc * axis.x * axis.y + axis.z * s, oc * axis.y * axis.y + c, oc * axis.y * axis.z - axis.x * s,
oc * axis.z * axis.x - axis.y * s, oc * axis.y * axis.z + axis.x * s, oc * axis.z * axis.z + c
);
}
}%

参数传递机制

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 parameter-passing %{
// 值传递(默认)
float valueParameter(float x) {
x *= 2.0; // 不会影响原始值
return x;
}

// 输入参数 (in)
float inputParameter(in float x) {
return x * x; // 只读参数
}

// 输出参数 (out)
void outputParameter(float input, out float result) {
result = sqrt(input); // 结果通过参数返回
}

// 输入输出参数 (inout)
void inoutParameter(inout vec3 color) {
color = normalize(color); // 修改原始值
color *= 1.2;
}

// 多重输出示例
void calculateLighting(vec3 normal, vec3 lightDir, vec3 viewDir,
out float diffuse, out float specular, out float fresnel) {
diffuse = max(0.0, dot(normal, lightDir));

vec3 halfDir = normalize(lightDir + viewDir);
specular = pow(max(0.0, dot(normal, halfDir)), 32.0);

fresnel = pow(1.0 - max(0.0, dot(normal, viewDir)), 2.0);
}
}%

🎨 常用函数库设计

数学函数库

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
// 数学工具函数库
CCProgram math-library %{
// 常量定义
#define PI 3.14159265359
#define TAU 6.28318530718
#define E 2.71828182846
#define GOLDEN_RATIO 1.61803398875

// 基础数学函数
float saturate(float x) {
return clamp(x, 0.0, 1.0);
}

vec3 saturate(vec3 x) {
return clamp(x, vec3(0.0), vec3(1.0));
}

float remap(float value, float oldMin, float oldMax, float newMin, float newMax) {
return newMin + (value - oldMin) * (newMax - newMin) / (oldMax - oldMin);
}

// 平滑插值函数
float smoothstep01(float x) {
return x * x * (3.0 - 2.0 * x);
}

float smootherstep(float edge0, float edge1, float x) {
x = saturate((x - edge0) / (edge1 - edge0));
return x * x * x * (x * (x * 6.0 - 15.0) + 10.0);
}

// 三角函数扩展
float sinWave(float x, float frequency, float amplitude, float phase) {
return sin(x * frequency + phase) * amplitude;
}

float cosWave(float x, float frequency, float amplitude, float phase) {
return cos(x * frequency + phase) * amplitude;
}

// 距离函数
float distance2D(vec2 a, vec2 b) {
vec2 delta = a - b;
return sqrt(delta.x * delta.x + delta.y * delta.y);
}

float distanceSquared(vec3 a, vec3 b) {
vec3 delta = a - b;
return dot(delta, delta);
}

// 角度计算
float angleBetween(vec3 a, vec3 b) {
return acos(dot(normalize(a), normalize(b)));
}

// 随机数函数
float random(float x) {
return fract(sin(x * 12.9898) * 43758.5453);
}

float random(vec2 st) {
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}

vec2 random2D(vec2 st) {
st = vec2(dot(st, vec2(127.1, 311.7)), dot(st, vec2(269.5, 183.3)));
return -1.0 + 2.0 * fract(sin(st) * 43758.5453123);
}
}%

颜色处理函数库

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
73
74
75
76
77
78
79
// 颜色处理函数库
CCProgram color-library %{
// RGB与HSV转换
vec3 rgb2hsv(vec3 c) {
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g));
vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r));

float d = q.x - min(q.w, q.y);
float e = 1.0e-10;
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x);
}

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, saturate(p - K.xxx), c.y);
}

// 伽马校正
vec3 linearToGamma(vec3 color) {
return pow(color, vec3(1.0 / 2.2));
}

vec3 gammaToLinear(vec3 color) {
return pow(color, vec3(2.2));
}

// 色调调整
vec3 adjustHue(vec3 color, float hueShift) {
vec3 hsv = rgb2hsv(color);
hsv.x += hueShift;
hsv.x = fract(hsv.x); // 保持在[0,1]范围
return hsv2rgb(hsv);
}

vec3 adjustSaturation(vec3 color, float saturationMultiplier) {
vec3 hsv = rgb2hsv(color);
hsv.y *= saturationMultiplier;
hsv.y = saturate(hsv.y);
return hsv2rgb(hsv);
}

vec3 adjustBrightness(vec3 color, float brightnessOffset) {
return color + vec3(brightnessOffset);
}

// 对比度调整
vec3 adjustContrast(vec3 color, float contrast) {
return (color - 0.5) * contrast + 0.5;
}

// 色彩平衡
vec3 colorBalance(vec3 color, vec3 shadows, vec3 midtones, vec3 highlights) {
float luminance = dot(color, vec3(0.299, 0.587, 0.114));

float shadowWeight = 1.0 - smoothstep(0.0, 0.5, luminance);
float highlightWeight = smoothstep(0.5, 1.0, luminance);
float midtoneWeight = 1.0 - shadowWeight - highlightWeight;

return color * (shadows * shadowWeight + midtones * midtoneWeight + highlights * highlightWeight);
}

// 温度调整 (色温)
vec3 adjustTemperature(vec3 color, float temperature) {
// 简化的色温调整
float factor = temperature / 6500.0; // 标准色温
if (factor > 1.0) {
// 偏暖色调
color.r *= 1.0 + (factor - 1.0) * 0.3;
color.b *= 1.0 - (factor - 1.0) * 0.2;
} else {
// 偏冷色调
color.r *= factor;
color.b *= 1.0 + (1.0 - factor) * 0.3;
}
return 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
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// 噪声生成函数库
CCProgram noise-library %{
// 值噪声(Value Noise)
float valueNoise(vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);

// 四个角的随机值
float a = random(i);
float b = random(i + vec2(1.0, 0.0));
float c = random(i + vec2(0.0, 1.0));
float d = random(i + vec2(1.0, 1.0));

// 平滑插值
vec2 u = f * f * (3.0 - 2.0 * f);

return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
}

// 梯度噪声 (Gradient Noise)
float gradientNoise(vec2 st) {
vec2 i = floor(st);
vec2 f = fract(st);

// 四个角的梯度向量
vec2 ga = random2D(i + vec2(0.0, 0.0));
vec2 gb = random2D(i + vec2(1.0, 0.0));
vec2 gc = random2D(i + vec2(0.0, 1.0));
vec2 gd = random2D(i + vec2(1.0, 1.0));

// 计算从角点到当前点的向量
vec2 va = f - vec2(0.0, 0.0);
vec2 vb = f - vec2(1.0, 0.0);
vec2 vc = f - vec2(0.0, 1.0);
vec2 vd = f - vec2(1.0, 1.0);

// 计算点积
float a = dot(ga, va);
float b = dot(gb, vb);
float c = dot(gc, vc);
float d = dot(gd, vd);

// 平滑插值
vec2 u = smoothstep(0.0, 1.0, f);

return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}

// 分形噪声 (Fractal Noise)
float fractalNoise(vec2 st, int octaves) {
float value = 0.0;
float amplitude = 0.5;
float frequency = 1.0;

for (int i = 0; i < octaves; i++) {
value += amplitude * gradientNoise(st * frequency);
amplitude *= 0.5;
frequency *= 2.0;
}

return value;
}

// 简化版Simplex噪声
float simplexNoise(vec2 v) {
const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0
0.366025403784439, // 0.5*(sqrt(3.0)-1.0)
-0.577350269189626, // -1.0 + 2.0 * C.x
0.024390243902439); // 1.0 / 41.0

vec2 i = floor(v + dot(v, C.yy));
vec2 x0 = v - i + dot(i, C.xx);

vec2 i1;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);

vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;

i = mod289(i);
vec3 p = permute(permute(i.y + vec3(0.0, i1.y, 1.0)) + i.x + vec3(0.0, i1.x, 1.0));

vec3 m = max(0.5 - vec3(dot(x0, x0), dot(x12.xy, x12.xy), dot(x12.zw, x12.zw)), 0.0);
m = m * m;
m = m * m;

vec3 x = 2.0 * fract(p * C.www) - 1.0;
vec3 h = abs(x) - 0.5;
vec3 ox = floor(x + 0.5);
vec3 a0 = x - ox;

m *= 1.79284291400159 - 0.85373472095314 * (a0 * a0 + h * h);

vec3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
return 130.0 * dot(m, g);
}

// 辅助函数
vec3 mod289(vec3 x) {
return x - floor(x * (1.0 / 289.0)) * 289.0;
}

vec3 permute(vec3 x) {
return mod289(((x * 34.0) + 1.0) * x);
}
}%

🔧 光照计算函数

PBR光照函数库

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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// PBR光照计算函数库
CCProgram pbr-lighting %{
struct MaterialData {
vec3 albedo;
float metallic;
float roughness;
vec3 normal;
vec3 emission;
float ao;
};

struct LightData {
vec3 direction;
vec3 color;
float intensity;
};

// 菲涅尔反射(Fresnel)
vec3 fresnelSchlick(float cosTheta, vec3 F0) {
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
}

vec3 fresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness) {
return F0 + (max(vec3(1.0 - roughness), F0) - F0) * pow(1.0 - cosTheta, 5.0);
}

// 法线分布函数 (Normal Distribution Function - GGX/Trowbridge-Reitz)
float distributionGGX(vec3 N, vec3 H, float roughness) {
float a = roughness * roughness;
float a2 = a * a;
float NdotH = max(dot(N, H), 0.0);
float NdotH2 = NdotH * NdotH;

float num = a2;
float denom = (NdotH2 * (a2 - 1.0) + 1.0);
denom = PI * denom * denom;

return num / denom;
}

// 几何遮蔽函数 (Geometry Function)
float geometrySchlickGGX(float NdotV, float roughness) {
float r = (roughness + 1.0);
float k = (r * r) / 8.0;

float num = NdotV;
float denom = NdotV * (1.0 - k) + k;

return num / denom;
}

float geometrySmith(vec3 N, vec3 V, vec3 L, float roughness) {
float NdotV = max(dot(N, V), 0.0);
float NdotL = max(dot(N, L), 0.0);
float ggx2 = geometrySchlickGGX(NdotV, roughness);
float ggx1 = geometrySchlickGGX(NdotL, roughness);

return ggx1 * ggx2;
}

// PBR BRDF计算
vec3 calculatePBR(MaterialData material, LightData light, vec3 viewDir) {
vec3 lightDir = normalize(-light.direction);
vec3 halfwayDir = normalize(lightDir + viewDir);

// 基础反射率
vec3 F0 = mix(vec3(0.04), material.albedo, material.metallic);

// Cook-Torrance BRDF
float NDF = distributionGGX(material.normal, halfwayDir, material.roughness);
float G = geometrySmith(material.normal, viewDir, lightDir, material.roughness);
vec3 F = fresnelSchlick(max(dot(halfwayDir, viewDir), 0.0), F0);

vec3 kS = F;
vec3 kD = vec3(1.0) - kS;
kD *= 1.0 - material.metallic;

vec3 numerator = NDF * G * F;
float denominator = 4.0 * max(dot(material.normal, viewDir), 0.0) * max(dot(material.normal, lightDir), 0.0) + 0.001;
vec3 specular = numerator / denominator;

float NdotL = max(dot(material.normal, lightDir), 0.0);

vec3 diffuse = kD * material.albedo / PI;
return (diffuse + specular) * light.color * light.intensity * NdotL;
}

// 环境光照计算
vec3 calculateAmbientLighting(MaterialData material, vec3 viewDir, samplerCube irradianceMap, samplerCube prefilterMap, sampler2D brdfLUT) {
vec3 F0 = mix(vec3(0.04), material.albedo, material.metallic);
vec3 F = fresnelSchlickRoughness(max(dot(material.normal, viewDir), 0.0), F0, material.roughness);

vec3 kS = F;
vec3 kD = 1.0 - kS;
kD *= 1.0 - material.metallic;

// 漫反射环境光
vec3 irradiance = textureCube(irradianceMap, material.normal).rgb;
vec3 diffuse = irradiance * material.albedo;

// 镜面反射环境光
vec3 reflectionDir = reflect(-viewDir, material.normal);
float maxReflectionLOD = 4.0; // 预滤波贴图的最大LOD
vec3 prefilteredColor = textureLod(prefilterMap, reflectionDir, material.roughness * maxReflectionLOD).rgb;

vec2 brdf = texture(brdfLUT, vec2(max(dot(material.normal, viewDir), 0.0), material.roughness)).rg;
vec3 specular = prefilteredColor * (F * brdf.x + brdf.y);

vec3 ambient = (kD * diffuse + specular) * material.ao;
return ambient;
}
}%

自定义光照模型

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
73
74
75
76
// 自定义光照模型函数库
CCProgram custom-lighting %{
// 卡通光照模型
vec3 calculateToonLighting(vec3 baseColor, vec3 normal, vec3 lightDir, float steps) {
float NdotL = dot(normal, lightDir);
NdotL = NdotL * 0.5 + 0.5; // 重映射到[0,1]

// 量化光照
float quantized = floor(NdotL * steps) / steps;

return baseColor * quantized;
}

// 卡通边缘光
vec3 calculateToonRimLight(vec3 normal, vec3 viewDir, vec3 rimColor, float rimPower, float rimIntensity) {
float rim = 1.0 - saturate(dot(normal, viewDir));
rim = pow(rim, rimPower);
return rimColor * rim * rimIntensity;
}

// Oren-Nayar漫反射模型(适用于粗糙表面)
float calculateOrenNayar(vec3 normal, vec3 lightDir, vec3 viewDir, float roughness) {
float NdotL = dot(normal, lightDir);
float NdotV = dot(normal, viewDir);

float angleVN = acos(NdotV);
float angleLN = acos(NdotL);

float alpha = max(angleVN, angleLN);
float beta = min(angleVN, angleLN);
float gamma = dot(viewDir - normal * NdotV, lightDir - normal * NdotL);

float roughnessSquared = roughness * roughness;

float A = 1.0 - 0.5 * (roughnessSquared / (roughnessSquared + 0.57));
float B = 0.45 * (roughnessSquared / (roughnessSquared + 0.09));

float L1 = max(0.0, NdotL) * (A + B * max(0.0, gamma) * sin(alpha) * tan(beta));

return L1;
}

// Minnaert月球表面反射模型
float calculateMinnaert(vec3 normal, vec3 lightDir, vec3 viewDir, float k) {
float NdotL = max(0.0, dot(normal, lightDir));
float NdotV = max(0.0, dot(normal, viewDir));

return NdotL * pow(NdotL * NdotV, k - 1.0);
}

// 各向异性反射模型
vec3 calculateAnisotropic(vec3 normal, vec3 tangent, vec3 lightDir, vec3 viewDir,
float roughnessU, float roughnessV, vec3 specularColor) {
vec3 bitangent = cross(normal, tangent);

vec3 halfDir = normalize(lightDir + viewDir);
float NdotH = dot(normal, halfDir);
float TdotH = dot(tangent, halfDir);
float BdotH = dot(bitangent, halfDir);

float exponent = -2.0 * ((TdotH * TdotH) / (roughnessU * roughnessU) + (BdotH * BdotH) / (roughnessV * roughnessV)) / (1.0 + NdotH);
float anisotropic = sqrt(max(0.0, dot(normal, lightDir) / dot(normal, viewDir))) * exp(exponent);

return specularColor * anisotropic;
}

// 子表面散射近似
vec3 calculateSubsurfaceScattering(vec3 normal, vec3 lightDir, vec3 viewDir,
vec3 thickness, vec3 subsurfaceColor, float power) {
vec3 backLight = lightDir + normal * 0.5; // 背光方向
float backLightDot = max(0.0, dot(-viewDir, backLight));

vec3 subsurface = subsurfaceColor * pow(backLightDot, power) * thickness;
return subsurface;
}
}%

🎯 函数优化技巧

性能优化函数

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
// 性能优化函数示例
CCProgram optimization-techniques %{
// 快速平方根倒数 (用于归一化)
float fastInverseSqrt(float x) {
// 注意:现代GPU通常内置了高效的rsqrt指令
return 1.0 / sqrt(x);
}

// 快速pow近似 (适用于特定情况)
float fastPow(float base, float exp) {
// 仅适用于正数base和小整数exp
if (exp == 2.0) return base * base;
if (exp == 3.0) return base * base * base;
if (exp == 4.0) {
float squared = base * base;
return squared * squared;
}
return pow(base, exp); // 回退到标准pow
}

// 向量长度的平方(避免sqrt计算)
float lengthSquared(vec3 v) {
return dot(v, v);
}

// 分支优化:使用mix代替if-else
vec3 conditionalColor(float condition, vec3 colorA, vec3 colorB) {
// 使用mix而不是if-else可以避免分支
return mix(colorB, colorA, step(0.5, condition));
}

// 查找表优化
float lookupTable(float input, sampler2D lutTexture) {
// 将计算结果预存在纹理中
return texture(lutTexture, vec2(input, 0.0)).r;
}

// 分级细节 (LOD) 函数
float calculateLOD(vec3 worldPos, vec3 cameraPos) {
float distance = length(worldPos - cameraPos);
return log2(distance / 10.0); // 10为基础距离
}

vec3 applyLODOptimization(vec3 worldPos, vec3 cameraPos, vec3 normal) {
float lod = calculateLOD(worldPos, cameraPos);

if (lod > 2.0) {
// 远距离:简化计算
return vec3(0.5); // 简单灰色
} else if (lod > 1.0) {
// 中距离:中等质量
return normal * 0.5 + 0.5; // 法线映射
} else {
// 近距离:高质量计算
return calculateComplexLighting(normal);
}
}

// 复杂光照计算示例
vec3 calculateComplexLighting(vec3 normal) {
// 这里可以放置复杂的PBR或其他光照计算
return normal * 0.8 + 0.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
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
// 调试工具函数库
CCProgram debug-utilities %{
// 可视化法线
vec3 visualizeNormal(vec3 normal) {
return normal * 0.5 + 0.5; // 映射到[0,1]范围用于显示
}

// 可视化UV坐标
vec3 visualizeUV(vec2 uv) {
return vec3(uv, 0.0);
}

// 可视化深度
vec3 visualizeDepth(float depth, float near, float far) {
float linearDepth = (2.0 * near) / (far + near - depth * (far - near));
return vec3(linearDepth);
}

// 热力图可视化
vec3 heatMap(float value) {
value = saturate(value);

vec3 color = vec3(0.0);
if (value < 0.25) {
color = mix(vec3(0.0, 0.0, 1.0), vec3(0.0, 1.0, 1.0), value * 4.0);
} else if (value < 0.5) {
color = mix(vec3(0.0, 1.0, 1.0), vec3(0.0, 1.0, 0.0), (value - 0.25) * 4.0);
} else if (value < 0.75) {
color = mix(vec3(0.0, 1.0, 0.0), vec3(1.0, 1.0, 0.0), (value - 0.5) * 4.0);
} else {
color = mix(vec3(1.0, 1.0, 0.0), vec3(1.0, 0.0, 0.0), (value - 0.75) * 4.0);
}

return color;
}

// 网格线可视化
float gridLines(vec2 uv, float lineWidth) {
vec2 grid = abs(fract(uv) - 0.5) / fwidth(uv);
float line = min(grid.x, grid.y);
return 1.0 - min(line, 1.0);
}

// 性能计时器(近似)
float performanceTimer(float startTime) {
// 注意:这只是概念性的,实际GPU时间测量需要其他方法
return fract(startTime * 1000.0);
}

// 错误检查函数
bool isValidColor(vec3 color) {
return all(greaterThanEqual(color, vec3(0.0))) && all(lessThanEqual(color, vec3(1.0)));
}

bool isValidNormal(vec3 normal) {
float length = dot(normal, normal);
return abs(length - 1.0) < 0.01; // 允许小误差
}

// 断言函数(调试用)
vec3 debugAssert(bool condition, vec3 normalColor, vec3 errorColor) {
return condition ? normalColor : errorColor;
}
}%

🎨 实际应用示例

完整的材质函数

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
// 完整材质计算示例
CCProgram material-example %{
#include <common/common-define>
#include <common/math/transform>
#include <builtin/uniforms/cc-global>

// 材质参数
uniform MaterialParams {
vec4 mainColor;
float metallic;
float roughness;
float normalScale;
vec4 emissionColor;
};

// 纹理采样器
uniform sampler2D mainTexture;
uniform sampler2D normalTexture;
uniform sampler2D metallicRoughnessTexture;
uniform sampler2D emissionTexture;

// 主材质函数
vec4 calculateMaterial(vec2 uv, vec3 worldNormal, vec3 worldPos, vec3 viewDir) {
// 基础颜色
vec4 baseColor = texture(mainTexture, uv) * mainColor;

// 法线贴图
vec3 normalMap = texture(normalTexture, uv).rgb * 2.0 - 1.0;
normalMap.xy *= normalScale;
vec3 normal = normalize(worldNormal + normalMap);

// 金属度和粗糙度
vec3 metallicRoughness = texture(metallicRoughnessTexture, uv).rgb;
float metallicValue = metallicRoughness.b * metallic;
float roughnessValue = metallicRoughness.g * roughness;

// 自发光
vec3 emission = texture(emissionTexture, uv).rgb * emissionColor.rgb;

// 创建材质数据
MaterialData material;
material.albedo = baseColor.rgb;
material.metallic = metallicValue;
material.roughness = roughnessValue;
material.normal = normal;
material.emission = emission;
material.ao = 1.0; // 可以从纹理中获取

// 计算光照
vec3 finalColor = vec3(0.0);

// 主光源
LightData mainLight;
mainLight.direction = cc_mainLitDir.xyz;
mainLight.color = cc_mainLitColor.rgb;
mainLight.intensity = cc_mainLitColor.w;

finalColor += calculatePBR(material, mainLight, viewDir);

// 环境光
finalColor += material.albedo * cc_ambientSky.rgb * 0.1;

// 自发光
finalColor += emission;

return vec4(finalColor, baseColor.a);
}
}%

动画函数库

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
73
74
75
76
77
// 动画工具函数库
CCProgram animation-library %{
// 缓动函数
float easeInQuad(float t) {
return t * t;
}

float easeOutQuad(float t) {
return 1.0 - (1.0 - t) * (1.0 - t);
}

float easeInOutQuad(float t) {
return t < 0.5 ? 2.0 * t * t : 1.0 - pow(-2.0 * t + 2.0, 2.0) / 2.0;
}

float easeInCubic(float t) {
return t * t * t;
}

float easeOutCubic(float t) {
return 1.0 - pow(1.0 - t, 3.0);
}

float easeInOutCubic(float t) {
return t < 0.5 ? 4.0 * t * t * t : 1.0 - pow(-2.0 * t + 2.0, 3.0) / 2.0;
}

// 弹性缓动
float easeOutElastic(float t) {
float c4 = (2.0 * PI) / 3.0;
return t == 0.0 ? 0.0 : t == 1.0 ? 1.0 : pow(2.0, -10.0 * t) * sin((t * 10.0 - 0.75) * c4) + 1.0;
}

// 回弹缓动
float easeOutBounce(float t) {
float n1 = 7.5625;
float d1 = 2.75;

if (t < 1.0 / d1) {
return n1 * t * t;
} else if (t < 2.0 / d1) {
return n1 * (t -= 1.5 / d1) * t + 0.75;
} else if (t < 2.5 / d1) {
return n1 * (t -= 2.25 / d1) * t + 0.9375;
} else {
return n1 * (t -= 2.625 / d1) * t + 0.984375;
}
}

// 波形动画
float waveAnimation(float time, float frequency, float amplitude, float phase) {
return sin(time * frequency + phase) * amplitude;
}

vec2 circularMotion(float time, float radius, float speed) {
float angle = time * speed;
return vec2(cos(angle), sin(angle)) * radius;
}

// 顶点动画
vec3 vertexWave(vec3 position, float time, float frequency, float amplitude) {
float wave = sin(position.x * frequency + time) * amplitude;
return position + vec3(0.0, wave, 0.0);
}

vec3 vertexTwist(vec3 position, float time, float strength) {
float angle = position.y * strength + time;
float c = cos(angle);
float s = sin(angle);

return vec3(
position.x * c - position.z * s,
position.y,
position.x * s + position.z * c
);
}
}%

📊 最佳实践

函数设计原则

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
// 函数设计最佳实践
CCProgram best-practices %{
// 1. 单一职责原则
// 好的例子:每个函数只做一件事
float calculateDistance(vec3 a, vec3 b) {
return length(a - b);
}

vec3 normalizeVector(vec3 v) {
return normalize(v);
}

// 2. 参数验证
vec3 safeNormalize(vec3 v) {
float len = length(v);
return len > 0.0001 ? v / len : vec3(0.0, 0.0, 1.0);
}

// 3. 常量提取
const float EPSILON = 0.0001;
const float PI = 3.14159265359;
const float TAU = 6.28318530718;

// 4. 可读性优先
vec3 calculateDiffuseLighting(vec3 normal, vec3 lightDirection, vec3 lightColor) {
float lightIntensity = max(0.0, dot(normal, lightDirection));
return lightColor * lightIntensity;
}

// 5. 避免深层嵌套
vec3 processLighting(vec3 normal, vec3 lightDir, vec3 viewDir, float roughness) {
// 早期返回避免深层嵌套
if (dot(normal, lightDir) <= 0.0) {
return vec3(0.0);
}

vec3 halfDir = normalize(lightDir + viewDir);
float specular = pow(max(0.0, dot(normal, halfDir)), 1.0 / roughness);

return vec3(specular);
}

// 6. 性能考虑
// 预计算常用值
struct PrecomputedLighting {
float NdotL;
float NdotV;
float NdotH;
float VdotH;
float LdotH;
};

PrecomputedLighting precomputeLightingTerms(vec3 N, vec3 L, vec3 V) {
vec3 H = normalize(L + V);

PrecomputedLighting terms;
terms.NdotL = max(0.0, dot(N, L));
terms.NdotV = max(0.0, dot(N, V));
terms.NdotH = max(0.0, dot(N, H));
terms.VdotH = max(0.0, dot(V, H));
terms.LdotH = max(0.0, dot(L, H));

return terms;
}
}%

📝 本章小结

通过本教程,你应该掌握了:

  1. 函数基础: Legacy Shader中函数的定义和参数传递
  2. 函数库设计: 数学、颜色、噪声等常用函数库的实现
  3. 光照计算: PBR和自定义光照模型的函数实现
  4. 性能优化: 函数优化技巧和最佳实践
  5. 调试工具: 调试和可视化函数的使用方法

🚀 下一步学习

恭喜完成第12.2章的学习!你已经掌握了Legacy Shader函数的高级使用技巧。接下来将学习Legacy Shader与Surface Shader的对比分析。🎮✨