第12.3章:Legacy vs Surface Shader深度对比

本教程将从多个维度深入对比Legacy Shader和Surface Shader,帮助开发者根据具体需求选择最合适的着色器类型。

🎯 学习目标

  • 全面理解两种着色器系统的差�?- 掌握不同场景下的选择策略
  • 学会在两种系统间进行迁移
  • 了解混合使用的最佳实�?

📊 核心差异对比

架构设计差异

特�?Surface ShaderLegacy Shader
抽象级别高级抽象,框架化底层控制,手动编�?
学习曲线平缓,快速上�?陡峭,需要深度理�?
*开发效�?高,框架辅助低,手动实现所有功�?
*灵活�?有限,受框架约束完全自由,无限制
性能控制框架优化手动优化
*兼容�?框架保证需要手动处�?

代码结构对比

Surface 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
// Surface Shader - 高度封装
CCEffect %{
techniques:
- name: opaque
passes:
- vert: surface-vs
frag: surface-fs
properties:
mainTexture: { value: white }
normalMap: { value: normal }
}%

CCProgram surface-vs %{
#include <surfaces/effect-macros/vs>

void SurfacesVertexModifyLocalPos(inout SurfacesStandardVertexIntermediate In) {
// 简单的顶点修改
}
}%

CCProgram surface-fs %{
#include <surfaces/effect-macros/fs>

void SurfacesFragmentModifyBaseColorAndTransparency(inout SurfacesStandardVertexIntermediate In, inout vec4 baseColor) {
baseColor *= texture(mainTexture, In.texCoord);
}
}%

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
// Legacy Shader - 完全手动控制
CCEffect %{
techniques:
- name: opaque
passes:
- vert: legacy-vs:vert
frag: legacy-fs:frag
properties:
mainTexture: { value: white }
normalMap: { value: normal }
}%

CCProgram legacy-vs %{
precision highp float;

in vec3 a_position;
in vec3 a_normal;
in vec2 a_texCoord;

out vec3 v_worldPos;
out vec3 v_normal;
out vec2 v_uv;

uniform CCGlobal {
mat4 cc_matView;
mat4 cc_matProj;
mat4 cc_matViewProj;
vec4 cc_cameraPos;
};

uniform CCLocal {
mat4 cc_matWorld;
mat4 cc_matWorldIT;
};

void vert() {
vec4 worldPos = cc_matWorld * vec4(a_position, 1.0);
v_worldPos = worldPos.xyz;
v_normal = normalize((cc_matWorldIT * vec4(a_normal, 0.0)).xyz);
v_uv = a_texCoord;

gl_Position = cc_matViewProj * worldPos;
}
}%

CCProgram legacy-fs %{
precision highp float;

in vec3 v_worldPos;
in vec3 v_normal;
in vec2 v_uv;

layout(location = 0) out vec4 fragColor;

uniform sampler2D mainTexture;
uniform sampler2D normalMap;

uniform CCForwardLight {
vec4 cc_mainLitDir;
vec4 cc_mainLitColor;
vec4 cc_ambientSky;
};

void frag() {
// 手动实现所有光照计�? vec4 baseColor = texture(mainTexture, v_uv);
vec3 normal = normalize(v_normal);
vec3 lightDir = normalize(-cc_mainLitDir.xyz);

float NdotL = max(dot(normal, lightDir), 0.0);
vec3 lighting = cc_mainLitColor.rgb * NdotL + cc_ambientSky.rgb * 0.2;

fragColor = vec4(baseColor.rgb * lighting, baseColor.a);
}
}%

🔄 相同效果的实现对�?

PBR材质实现

Surface Shader版本 (�?0�?:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
CCProgram surface-pbr %{
#include <surfaces/effect-macros/fs>

void SurfacesFragmentModifyBaseColorAndTransparency(inout SurfacesStandardVertexIntermediate In, inout vec4 baseColor) {
baseColor *= texture(mainTexture, In.texCoord);
}

void SurfacesFragmentModifyNormalTS(inout SurfacesStandardVertexIntermediate In, inout vec3 normal, inout vec3 tangent, inout vec3 bitangent) {
vec3 normalMap = texture(normalTexture, In.texCoord).xyz * 2.0 - 1.0;
normal = normalize(normalMap);
}

void SurfacesFragmentModifyMaterialData(inout SurfacesStandardVertexIntermediate In, inout SurfacesMaterialData surfaceData) {
surfaceData.roughness = pbrParams.y;
surfaceData.metallic = pbrParams.z;
}
}%

Legacy Shader版本 (�?50�?:

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
CCProgram legacy-pbr %{
// 需要手动实现完整的PBR光照模型

struct MaterialData {
vec3 albedo;
float metallic;
float roughness;
vec3 normal;
};

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

// 法线分布函数
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;
}

// 几何遮蔽函数
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计算
vec3 calculatePBR(MaterialData material, vec3 lightDir, vec3 viewDir, vec3 lightColor) {
vec3 halfwayDir = normalize(lightDir + viewDir);

vec3 F0 = mix(vec3(0.04), material.albedo, material.metallic);

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);

return (kD * material.albedo / PI + specular) * lightColor * NdotL;
}

void frag() {
MaterialData material;
material.albedo = texture(mainTexture, v_uv).rgb;
material.metallic = pbrParams.z;
material.roughness = pbrParams.y;

// 法线贴图处理
vec3 normalMap = texture(normalTexture, v_uv).xyz * 2.0 - 1.0;
mat3 TBN = mat3(v_tangent, v_bitangent, v_normal);
material.normal = normalize(TBN * normalMap);

vec3 viewDir = normalize(cc_cameraPos.xyz - v_worldPos);
vec3 lightDir = normalize(-cc_mainLitDir.xyz);

vec3 color = calculatePBR(material, lightDir, viewDir, cc_mainLitColor.rgb);

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

📈 性能对比分析

TypeScript性能测试工具

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
class ShaderPerformanceComparator {
private gl: WebGL2RenderingContext;
private testResults: Map<string, PerformanceMetrics> = new Map();

interface PerformanceMetrics {
frameTime: number;
gpuTime: number;
drawCalls: number;
triangles: number;
shaderComplexity: number;
memoryUsage: number;
}

public async compareShaders(surfaceShader: string, legacyShader: string): Promise<ComparisonResult> {
console.log('🔄 开始着色器性能对比测试...');

// 测试Surface Shader
const surfaceMetrics = await this.testShaderPerformance('surface', surfaceShader);

// 测试Legacy Shader
const legacyMetrics = await this.testShaderPerformance('legacy', legacyShader);

return this.generateComparisonReport(surfaceMetrics, legacyMetrics);
}

private async testShaderPerformance(type: string, shaderCode: string): Promise<PerformanceMetrics> {
const startTime = performance.now();

// 编译着色器
const program = this.compileShader(shaderCode);
const compileTime = performance.now() - startTime;

// 渲染测试场景
const renderMetrics = await this.renderTestScene(program);

// 计算着色器复杂�? const complexity = this.analyzeShaderComplexity(shaderCode);

return {
frameTime: renderMetrics.frameTime,
gpuTime: renderMetrics.gpuTime,
drawCalls: renderMetrics.drawCalls,
triangles: renderMetrics.triangles,
shaderComplexity: complexity,
memoryUsage: renderMetrics.memoryUsage
};
}

private analyzeShaderComplexity(shaderCode: string): number {
let complexity = 0;

// 纹理读取复杂�? const textureReads = (shaderCode.match(/texture\(/g) || []).length;
complexity += textureReads * 10;

// 数学运算复杂�? const mathOps = (shaderCode.match(/\*|\+|\-|\/|\bpow\b|\bsqrt\b|\bsin\b|\bcos\b/g) || []).length;
complexity += mathOps * 1;

// 分支复杂�? const branches = (shaderCode.match(/\bif\b|\bfor\b|\bwhile\b/g) || []).length;
complexity += branches * 15;

// 函数调用复杂�? const functions = (shaderCode.match(/\b\w+\s*\(/g) || []).length;
complexity += functions * 2;

return complexity;
}

private generateComparisonReport(surface: PerformanceMetrics, legacy: PerformanceMetrics): ComparisonResult {
const report = {
surface: surface,
legacy: legacy,
comparison: {
frameTimeRatio: legacy.frameTime / surface.frameTime,
complexityRatio: legacy.shaderComplexity / surface.shaderComplexity,
memoryRatio: legacy.memoryUsage / surface.memoryUsage,
recommendation: this.generateRecommendation(surface, legacy)
}
};

console.log('📊 性能对比报告�?);
console.log(`Surface Shader - 帧时�? ${surface.frameTime.toFixed(2)}ms, 复杂�? ${surface.shaderComplexity}`);
console.log(`Legacy Shader - 帧时�? ${legacy.frameTime.toFixed(2)}ms, 复杂�? ${legacy.shaderComplexity}`);
console.log(`推荐: ${report.comparison.recommendation}`);

return report;
}

private generateRecommendation(surface: PerformanceMetrics, legacy: PerformanceMetrics): string {
const frameTimeDiff = Math.abs(legacy.frameTime - surface.frameTime);
const complexityDiff = Math.abs(legacy.shaderComplexity - surface.shaderComplexity);

if (frameTimeDiff < 0.1 && complexityDiff < 50) {
return '性能相近,推荐使用Surface Shader以提高开发效�?;
} else if (legacy.frameTime < surface.frameTime * 0.8) {
return 'Legacy Shader性能更优,适合性能敏感场景';
} else if (surface.frameTime < legacy.frameTime * 0.8) {
return 'Surface Shader性能更优,且开发效率更�?;
} else {
return '根据项目需求选择:快速开发选Surface,精细控制选Legacy';
}
}
}

// 使用示例
const comparator = new ShaderPerformanceComparator();

// 对比PBR材质实现
comparator.compareShaders(surfacePBRShader, legacyPBRShader).then(result => {
console.log('PBR材质对比结果:', result);
});

🎯 选择策略指南

基于项目需求的选择矩阵

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
class ShaderSelectionGuide {
public recommendShaderType(requirements: ProjectRequirements): ShaderRecommendation {
let surfaceScore = 0;
let legacyScore = 0;

// 开发时间紧迫程�? if (requirements.developmentTime === 'tight') {
surfaceScore += 30;
} else if (requirements.developmentTime === 'flexible') {
legacyScore += 20;
}

// 性能要求
if (requirements.performanceTarget === 'high-end') {
legacyScore += 25;
} else if (requirements.performanceTarget === 'mobile') {
surfaceScore += 15;
legacyScore += 10; // 两者都适用,但legacy需要更多优�? }

// 效果复杂�? if (requirements.effectComplexity === 'simple') {
surfaceScore += 25;
} else if (requirements.effectComplexity === 'complex') {
legacyScore += 30;
}

// 团队技能水�? if (requirements.teamSkillLevel === 'beginner') {
surfaceScore += 35;
} else if (requirements.teamSkillLevel === 'expert') {
legacyScore += 25;
}

// 维护要求
if (requirements.maintenanceRequirement === 'low') {
surfaceScore += 20;
} else if (requirements.maintenanceRequirement === 'high') {
legacyScore += 15;
}

return {
recommendation: surfaceScore > legacyScore ? 'Surface Shader' : 'Legacy Shader',
confidence: Math.abs(surfaceScore - legacyScore) / 100,
reasoning: this.generateReasoning(surfaceScore, legacyScore, requirements),
surfaceScore,
legacyScore
};
}

private generateReasoning(surfaceScore: number, legacyScore: number, req: ProjectRequirements): string[] {
const reasons: string[] = [];

if (req.developmentTime === 'tight') {
reasons.push('开发时间紧迫,Surface Shader能快速实现效�?);
}

if (req.effectComplexity === 'complex') {
reasons.push('复杂效果需要Legacy Shader的底层控制能�?);
}

if (req.performanceTarget === 'high-end') {
reasons.push('高性能要求适合Legacy Shader的精细优�?);
}

if (req.teamSkillLevel === 'beginner') {
reasons.push('团队技能水平适合Surface Shader的简化开�?);
}

return reasons;
}
}

interface ProjectRequirements {
developmentTime: 'tight' | 'moderate' | 'flexible';
performanceTarget: 'mobile' | 'desktop' | 'high-end';
effectComplexity: 'simple' | 'moderate' | 'complex';
teamSkillLevel: 'beginner' | 'intermediate' | 'expert';
maintenanceRequirement: 'low' | 'moderate' | 'high';
}

// 使用示例
const guide = new ShaderSelectionGuide();

const mobileGameProject: ProjectRequirements = {
developmentTime: 'tight',
performanceTarget: 'mobile',
effectComplexity: 'moderate',
teamSkillLevel: 'intermediate',
maintenanceRequirement: 'low'
};

const recommendation = guide.recommendShaderType(mobileGameProject);
console.log(`推荐使用: ${recommendation.recommendation}`);
console.log(`置信�? ${(recommendation.confidence * 100).toFixed(1)}%`);
console.log('理由:', recommendation.reasoning);

🔄 迁移策略

Surface to Legacy迁移

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
// Surface Shader原始代码
CCProgram surface-original %{
#include <surfaces/effect-macros/fs>

void SurfacesFragmentModifyBaseColorAndTransparency(inout SurfacesStandardVertexIntermediate In, inout vec4 baseColor) {
baseColor *= texture(mainTexture, In.texCoord);
baseColor.rgb *= colorTint.rgb;
}

void SurfacesFragmentModifyNormalTS(inout SurfacesStandardVertexIntermediate In, inout vec3 normal, inout vec3 tangent, inout vec3 bitangent) {
vec3 normalMap = texture(normalTexture, In.texCoord).xyz * 2.0 - 1.0;
normal = normalize(normalMap);
}
}%

// 迁移后的Legacy Shader
CCProgram legacy-migrated %{
precision highp float;

// 重构的vertex shader
in vec3 a_position;
in vec3 a_normal;
in vec2 a_texCoord;
in vec4 a_tangent;

out vec3 v_worldPos;
out vec3 v_normal;
out vec2 v_uv;
out vec3 v_tangent;
out vec3 v_bitangent;

uniform CCGlobal {
mat4 cc_matView;
mat4 cc_matProj;
mat4 cc_matViewProj;
vec4 cc_cameraPos;
};

uniform CCLocal {
mat4 cc_matWorld;
mat4 cc_matWorldIT;
};

void vert() {
vec4 worldPos = cc_matWorld * vec4(a_position, 1.0);
v_worldPos = worldPos.xyz;

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

// 切线空间计算
v_tangent = normalize((cc_matWorld * vec4(a_tangent.xyz, 0.0)).xyz);
v_bitangent = cross(v_normal, v_tangent) * a_tangent.w;

v_uv = a_texCoord;
gl_Position = cc_matViewProj * worldPos;
}

// 重构的fragment shader
in vec3 v_worldPos;
in vec3 v_normal;
in vec2 v_uv;
in vec3 v_tangent;
in vec3 v_bitangent;

layout(location = 0) out vec4 fragColor;

uniform sampler2D mainTexture;
uniform sampler2D normalTexture;
uniform vec4 colorTint;

void frag() {
// 对应SurfacesFragmentModifyBaseColorAndTransparency
vec4 baseColor = texture(mainTexture, v_uv);
baseColor *= colorTint;

// 对应SurfacesFragmentModifyNormalTS
vec3 normalMap = texture(normalTexture, v_uv).xyz * 2.0 - 1.0;
mat3 TBN = mat3(v_tangent, v_bitangent, v_normal);
vec3 normal = normalize(TBN * normalMap);

// 手动实现光照计算(Surface Shader中由框架处理�? vec3 viewDir = normalize(cc_cameraPos.xyz - v_worldPos);
// 这里需要添加完整的光照计算...

fragColor = baseColor;
}
}%

Legacy to Surface迁移

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
// Legacy Shader原始代码
CCProgram legacy-original %{
// 复杂的手动光照计�? void frag() {
vec4 baseColor = texture(mainTexture, v_uv);

// 手动法线计算
vec3 normalMap = texture(normalTexture, v_uv).xyz * 2.0 - 1.0;
mat3 TBN = mat3(v_tangent, v_bitangent, v_normal);
vec3 normal = normalize(TBN * normalMap);

// 手动PBR计算
vec3 viewDir = normalize(cc_cameraPos.xyz - v_worldPos);
vec3 lightDir = normalize(-cc_mainLitDir.xyz);

// ... 100行的PBR实现代码 ...

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

// 迁移后的Surface Shader
CCProgram surface-migrated %{
#include <surfaces/effect-macros/fs>

// 基础颜色修改
void SurfacesFragmentModifyBaseColorAndTransparency(inout SurfacesStandardVertexIntermediate In, inout vec4 baseColor) {
baseColor *= texture(mainTexture, In.texCoord);
}

// 法线修改
void SurfacesFragmentModifyNormalTS(inout SurfacesStandardVertexIntermediate In, inout vec3 normal, inout vec3 tangent, inout vec3 bitangent) {
vec3 normalMap = texture(normalTexture, In.texCoord).xyz * 2.0 - 1.0;
normal = normalize(normalMap);
}

// PBR参数设置(框架自动处理光照计算)
void SurfacesFragmentModifyMaterialData(inout SurfacesStandardVertexIntermediate In, inout SurfacesMaterialData surfaceData) {
surfaceData.roughness = 0.5;
surfaceData.metallic = 0.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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
class HybridShaderStrategy {
private shaderCategories: Map<string, ShaderType> = new Map();

public planShaderDistribution(gameObjects: GameObject[]): ShaderPlan {
const plan: ShaderPlan = {
surfaceShaders: [],
legacyShaders: [],
reasoning: []
};

gameObjects.forEach(obj => {
const recommendation = this.categorizeGameObject(obj);

if (recommendation.type === 'surface') {
plan.surfaceShaders.push({
object: obj,
shaderType: 'Surface',
reason: recommendation.reason
});
} else {
plan.legacyShaders.push({
object: obj,
shaderType: 'Legacy',
reason: recommendation.reason
});
}
});

return plan;
}

private categorizeGameObject(obj: GameObject): ShaderRecommendation {
// UI元素 -> Surface Shader
if (obj.type === 'UI') {
return {
type: 'surface',
reason: 'UI元素使用Surface Shader可快速实现标准效�?
};
}

// 环境道具 -> Surface Shader
if (obj.type === 'Environment' && obj.complexity === 'simple') {
return {
type: 'surface',
reason: '简单环境道具适合Surface Shader的标准PBR流程'
};
}

// 主角/重要NPC -> Legacy Shader
if (obj.importance === 'high' && obj.visualEffects === 'complex') {
return {
type: 'legacy',
reason: '重要角色需要Legacy Shader实现精细化效�?
};
}

// 特效对象 -> Legacy Shader
if (obj.type === 'VFX') {
return {
type: 'legacy',
reason: '特效需要Legacy Shader的完全自定义能力'
};
}

// 默认使用Surface Shader
return {
type: 'surface',
reason: '默认使用Surface Shader以提高开发效�?
};
}
}

interface GameObject {
id: string;
type: 'Character' | 'Environment' | 'UI' | 'VFX';
importance: 'low' | 'medium' | 'high';
complexity: 'simple' | 'moderate' | 'complex';
visualEffects: 'none' | 'simple' | 'complex';
performanceRequirement: 'low' | 'medium' | 'high';
}

// 使用示例
const strategy = new HybridShaderStrategy();

const gameObjects: GameObject[] = [
{ id: 'player', type: 'Character', importance: 'high', complexity: 'complex', visualEffects: 'complex', performanceRequirement: 'high' },
{ id: 'npc1', type: 'Character', importance: 'medium', complexity: 'moderate', visualEffects: 'simple', performanceRequirement: 'medium' },
{ id: 'wall', type: 'Environment', importance: 'low', complexity: 'simple', visualEffects: 'none', performanceRequirement: 'low' },
{ id: 'magic_effect', type: 'VFX', importance: 'medium', complexity: 'complex', visualEffects: 'complex', performanceRequirement: 'high' },
{ id: 'ui_button', type: 'UI', importance: 'low', complexity: 'simple', visualEffects: 'none', performanceRequirement: 'low' }
];

const shaderPlan = strategy.planShaderDistribution(gameObjects);
console.log('着色器分配计划:', shaderPlan);

📝 本章小结

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

  1. 架构差异: 深入理解两种着色器系统的本质区�?2. 性能对比: 学会分析和测试不同着色器的性能表现
  2. 选择策略: 根据项目需求制定着色器选择方案
  3. *迁移技�?: 掌握在两种系统间转换的方�?5. 混合使用: 了解如何在项目中合理分配两种着色器

🚀 下一步学�?

恭喜完成�?2章的学习!你已经全面掌握了Legacy Shader的使用技巧。接下来可以查看系列总结,或继续学习更高级的主题。🎮✨