第12.1章:Legacy Shader系统介绍

Legacy Shader是Cocos Creator提供的传统着色器编写方式,相比Surface Shader提供了更底层的控制能力。本教程将全面介绍Legacy Shader的特点、应用场景和基本使用方法。

🎯 学习目标

  • 理解Legacy Shader与Surface Shader的区�?- 掌握Legacy Shader的基本语法和结构
  • 学会Legacy Shader的编写和调试技�?- 了解Legacy Shader的适用场景

📋 前置知识

  • 已完成Surface Shader章节的学�?- 熟悉GLSL语法基础
  • 理解渲染管线和着色器执行流程

🔧 Legacy Shader概述

Legacy Shader vs Surface Shader

Legacy Shader和Surface Shader的主要区别:

Surface Shader (高级抽象):

  • 框架控制渲染流程
  • 简化开发复杂度
  • 有限的自定义能力
  • 适用于标准PBR材质和快速开�?
    Legacy Shader (底层控制):
  • 完全手动控制渲染流程
  • 需要深入理解图形学原理
  • 完全自定义能�?- 适用于特殊效果和高级技�?

Legacy Shader特点

*优势�?

  • 完全控制渲染流程
  • 可以实现任意复杂的效�?- 直接访问GPU功能
  • 不受框架限制

*劣势�?

  • 开发复杂度�?- 需要手动处理兼容�?- 调试困难
  • 维护成本�?

📝 Legacy Shader基本结构

完整的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
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
// Legacy Shader完整示例
CCEffect %{
techniques:
- name: opaque
passes:
- vert: legacy-vs:vert
frag: legacy-fs:frag
properties: &props
mainTexture: { value: grey, target: mainTexture }
mainColor: { value: [1, 1, 1, 1], target: mainColor }
roughness: { value: 0.5, target: pbrParams.y }
metallic: { value: 0.0, target: pbrParams.z }
rasterizerState:
cullMode: back
depthStencilState:
depthTest: true
depthWrite: true
}%

// 顶点着色器
CCProgram legacy-vs %{
precision highp float;

// 输入属�? in vec3 a_position;
in vec3 a_normal;
in vec2 a_texCoord;

// 输出到片段着色器
out vec3 v_position;
out vec3 v_normal;
out vec2 v_uv;
out vec3 v_worldPos;

// Uniform变量
uniform CCGlobal {
mat4 cc_matView;
mat4 cc_matViewInv;
mat4 cc_matProj;
mat4 cc_matViewProj;
vec4 cc_cameraPos;
vec4 cc_time;
vec4 cc_screenSize;
};

uniform CCLocal {
mat4 cc_matWorld;
mat4 cc_matWorldIT;
};

void vert() {
vec4 position = vec4(a_position, 1.0);

// 世界空间变换
vec4 worldPos = cc_matWorld * position;
v_worldPos = worldPos.xyz;

// 法线变换
v_normal = normalize((cc_matWorldIT * vec4(a_normal, 0.0)).xyz);

// UV坐标
v_uv = a_texCoord;

// 投影变换
gl_Position = cc_matViewProj * worldPos;
}
}%

// 片段着色器
CCProgram legacy-fs %{
precision highp float;

// 输入变量
in vec3 v_position;
in vec3 v_normal;
in vec2 v_uv;
in vec3 v_worldPos;

// 输出颜色
layout(location = 0) out vec4 fragColor;

// 材质参数
uniform sampler2D mainTexture;
uniform vec4 mainColor;
uniform vec4 pbrParams; // y: roughness, z: metallic

// 光照相关
uniform CCForwardLight {
vec4 cc_mainLitDir;
vec4 cc_mainLitColor;
vec4 cc_ambientSky;
vec4 cc_ambientGround;
};

void frag() {
// 基础颜色
vec4 baseColor = texture(mainTexture, v_uv) * mainColor;

// 简单光照计�? vec3 normal = normalize(v_normal);
vec3 lightDir = normalize(-cc_mainLitDir.xyz);
float NdotL = max(dot(normal, lightDir), 0.0);

// 最终颜�? vec3 finalColor = baseColor.rgb * cc_mainLitColor.rgb * NdotL;
finalColor += cc_ambientSky.rgb * baseColor.rgb * 0.2;

fragColor = vec4(finalColor, baseColor.a);
}
}%

🔧 Legacy Shader核心组件

1. CCEffect配置

1
2
3
4
5
6
7
8
9
10
11
# CCEffect配置详解
CCEffect:
techniques:
- name: opaque # 技术名�? passes:
- vert: shader-vs:vert # 顶点着色器入口
frag: shader-fs:frag # 片段着色器入口
properties: # 材质属�? mainTexture: { value: grey, target: mainTexture }
mainColor: { value: [1,1,1,1], target: mainColor }
rasterizerState: # 光栅化状�? cullMode: back # 背面剔除
depthStencilState: # 深度模板状�? depthTest: true # 深度测试
depthWrite: true # 深度写入

2. Uniform块结�?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 内置Uniform�?CCProgram uniform-blocks %{
// 全局变量�? uniform CCGlobal {
mat4 cc_matView; // 视图矩阵
mat4 cc_matProj; // 投影矩阵
mat4 cc_matViewProj; // 视图投影矩阵
vec4 cc_cameraPos; // 摄像机位�? vec4 cc_time; // 时间信息
vec4 cc_screenSize; // 屏幕尺寸
};

// 本地变量�? uniform CCLocal {
mat4 cc_matWorld; // 世界矩阵
mat4 cc_matWorldIT; // 世界逆转置矩�? };

// 光照变量�? uniform CCForwardLight {
vec4 cc_mainLitDir; // 主光源方�? vec4 cc_mainLitColor; // 主光源颜�? vec4 cc_ambientSky; // 天空环境�? vec4 cc_ambientGround; // 地面环境�? };
}%

3. 顶点输入属�?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 标准顶点属�?CCProgram vertex-attributes %{
// 位置属�?(必须)
in vec3 a_position;

// 法线属�? in vec3 a_normal;

// 纹理坐标
in vec2 a_texCoord;
in vec2 a_texCoord1; // 第二套UV

// 切线属�? in vec4 a_tangent; // xyz: 切线, w: 手�?
// 顶点颜色
in vec4 a_color;

// 骨骼动画属�? in vec4 a_joints; // 关节索引
in vec4 a_weights; // 权重
}%

🎨 Legacy Shader应用场景

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
// 自定义卡通光照模�?CCProgram toon-lighting %{
vec3 calculateToonLighting(vec3 baseColor, vec3 normal, vec3 lightDir) {
float NdotL = dot(normal, lightDir);

// 阶梯化光�? float toonFactor;
if (NdotL > 0.8) {
toonFactor = 1.0;
} else if (NdotL > 0.4) {
toonFactor = 0.7;
} else if (NdotL > 0.0) {
toonFactor = 0.4;
} else {
toonFactor = 0.1;
}

return baseColor * toonFactor;
}

void frag() {
vec3 normal = normalize(v_normal);
vec3 lightDir = normalize(-cc_mainLitDir.xyz);

vec3 lighting = calculateToonLighting(
texture(mainTexture, v_uv).rgb,
normal,
lightDir
);

fragColor = vec4(lighting, 1.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
// 玻璃材质效果
CCProgram glass-material %{
uniform sampler2D envMap;
uniform vec4 glassParams; // x: refraction, y: reflection, z: thickness

vec3 calculateGlassEffect(vec3 normal, vec3 viewDir) {
float refractiveIndex = glassParams.x;
float reflectionStrength = glassParams.y;

// 反射
vec3 reflectionDir = reflect(-viewDir, normal);
vec3 reflection = textureCube(envMap, reflectionDir).rgb;

// 菲涅尔效�? float fresnel = pow(1.0 - max(0.0, dot(normal, viewDir)), 2.0);

// 混合反射
vec3 finalColor = reflection * fresnel * reflectionStrength;

return finalColor;
}

void frag() {
vec3 normal = normalize(v_normal);
vec3 viewDir = normalize(cc_cameraPos.xyz - v_worldPos);

vec3 glassColor = calculateGlassEffect(normal, viewDir);

fragColor = vec4(glassColor, 0.8); // 半透明
}
}%

🔍 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
// 调试可视化着色器
CCProgram debug-visualizer %{
uniform vec4 debugMode; // x: mode

vec3 visualizeNormals(vec3 normal) {
return normal * 0.5 + 0.5; // 映射到[0,1]范围
}

vec3 visualizeUV(vec2 uv) {
return vec3(uv, 0.0);
}

void frag() {
int mode = int(debugMode.x);
vec3 debugColor;

if (mode == 0) {
// 法线可视�? debugColor = visualizeNormals(normalize(v_normal));
} else if (mode == 1) {
// UV坐标可视�? debugColor = visualizeUV(v_uv);
} else {
// 默认颜色
debugColor = vec3(1, 0, 1);
}

fragColor = vec4(debugColor, 1.0);
}
}%

📝 开发最佳实�?

代码组织

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 良好的代码组织结�?CCProgram shader-utils %{
// 常量定义
#define PI 3.14159265359
#define EPSILON 0.001

// 通用函数�? float saturate(float x) {
return clamp(x, 0.0, 1.0);
}

// 光照计算函数
float distributionGGX(float NdotH, float roughness) {
float a = roughness * roughness;
float a2 = a * a;
float denom = NdotH * NdotH * (a2 - 1.0) + 1.0;
return a2 / (PI * denom * denom);
}
}%

平台兼容�?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 平台兼容性处�?CCProgram compatibility %{
precision mediump float;

// 移动端优�? #ifdef CC_USE_MOBILE
precision mediump float;
#define HIGH_QUALITY 0
#else
precision highp float;
#define HIGH_QUALITY 1
#endif

// 条件编译
#if HIGH_QUALITY
float calculateHighQualityEffect() {
// 高质量实�? return complexCalculation();
}
#else
float calculateHighQualityEffect() {
// 简化版实现
return simpleCalculation();
}
#endif
}%

📝 本章小结

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

  1. Legacy Shader概念: 理解Legacy Shader的特点和适用场景
  2. 基本结构: 掌握Legacy Shader的语法和组织结构
  3. 核心组件: 了解CCEffect、Uniform块、顶点属性等核心概念
  4. 实际应用: 学会使用Legacy Shader实现复杂效果

🚀 下一步学�?

继续深入学习Legacy Shader的高级功能!🎮�