第10.3章:3D力场着色器

力场着色器是科幻游戏中的核心视觉特效,用于表现能量护盾、防护罩、磁场等科技元素。本章将深入探讨各种力场效果的实现技术。

🎯 学习目标

  • 理解力场视觉效果的原理
  • 掌握球形、六边形网格力场实现
  • 学会冲击波和能量传播效果
  • 理解3D空间中的力场交互

💡 力场效果原理

视觉特征分析

力场具有以下特征:

1
2
3
4
5
6
// 力场关键要素
1. 透明度 - 半透明能量层
2. 网格模式 - 六边形或方形网格
3. 边缘增强 - 菲涅尔反射
4. 冲击反应 - 局部激活效果
5. 能量流动 - 动态扰动

效果组成

1
2
3
基础几何 → 网格模式 → 菲涅尔 → 冲击检测 → 能量动画
↓ ↓ ↓ ↓ ↓
sphere hexagon fresnel impact pulse

🔧 基础力场实现

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
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
CCEffect %{
techniques:
- name: sphere-force-field
passes:
- vert: force-field-vs:vert
frag: force-field-fs:frag
blendState:
targets:
- blend: true
blendSrc: src_alpha
blendDst: one_minus_src_alpha
rasterizerState:
cullMode: none
properties: &props
shieldColor: { value: [0.2, 0.8, 1.0, 1.0], editor: { type: color } }
gridScale: { value: 20.0, range: [5.0, 100.0] }
gridThickness: { value: 0.05, range: [0.01, 0.2] }
energySpeed: { value: 2.0, range: [0.0, 10.0] }
fresnel_power: { value: 2.0, range: [0.1, 5.0] }
fresnel_intensity:{ value: 1.5, range: [0.0, 3.0] }
transparency: { value: 0.3, range: [0.0, 1.0] }
noiseTexture: { value: white }
pulseIntensity: { value: 1.0, range: [0.0, 3.0] }
}%

CCProgram force-field-vs %{
precision highp float;
#include <cc-global>
#include <cc-local>

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

out vec3 v_worldPos;
out vec3 v_worldNormal;
out vec2 v_uv;
out vec3 v_spherePos;

vec4 vert() {
vec4 worldPos = cc_matWorld * vec4(a_position, 1);
v_worldPos = worldPos.xyz;
v_worldNormal = normalize((cc_matWorldIT * vec4(a_normal, 0)).xyz);
v_uv = a_texCoord;

// 球面坐标计算
v_spherePos = normalize(a_position);

return cc_matViewProj * worldPos;
}
}%

CCProgram force-field-fs %{
precision highp float;
#include <cc-global>
#include <cc-environment>

uniform sampler2D noiseTexture;
uniform vec4 shieldColor;
uniform float gridScale;
uniform float gridThickness;
uniform float energySpeed;
uniform float fresnel_power;
uniform float fresnel_intensity;
uniform float transparency;
uniform float pulseIntensity;

in vec3 v_worldPos;
in vec3 v_worldNormal;
in vec2 v_uv;
in vec3 v_spherePos;

// 六边形网格函数
float hexagonGrid(vec2 uv) {
// 转换为六边形坐标系
vec2 s = vec2(1.0, 1.732) * gridScale;
vec2 r = vec2(1.0, 0.5);

vec2 h = r * uv.y;
vec2 a = mod(uv * s - h, s) - s * 0.5;
vec2 b = mod(uv * s - h - s * 0.5, s) - s * 0.5;

vec2 gv = dot(a, a) < dot(b, b) ? a : b;
float d = length(gv);

return smoothstep(gridThickness, gridThickness + 0.01, d);
}

vec4 frag() {
vec3 normal = normalize(v_worldNormal);
vec3 viewDir = normalize(cc_cameraPos.xyz - v_worldPos);

// 球面UV映射
float phi = atan(v_spherePos.z, v_spherePos.x);
float theta = acos(v_spherePos.y);
vec2 sphereUV = vec2(phi / 6.28318 + 0.5, theta / 3.14159);

// 时间偏移的噪声采样
vec2 noiseUV = sphereUV + cc_time.x * energySpeed * 0.1;
vec4 noise = texture(noiseTexture, noiseUV);

// 六边形网格
vec2 gridUV = sphereUV + noise.rg * 0.05;
float hexGrid = hexagonGrid(gridUV);

// 菲涅尔反射
float fresnel = 1.0 - max(0.0, dot(normal, viewDir));
fresnel = pow(fresnel, fresnel_power) * fresnel_intensity;

// 能量脉冲
float pulse = sin(cc_time.x * energySpeed * 2.0) * 0.3 + 0.7;
pulse += noise.b * 0.3;

// 合成护盾效果
vec3 shieldFinal = shieldColor.rgb;

// 网格发光
shieldFinal += shieldColor.rgb * (1.0 - hexGrid) * 0.5 * pulse;

// 边缘发光
shieldFinal += shieldColor.rgb * fresnel;

// 噪声能量流
shieldFinal += shieldColor.rgb * noise.r * 0.3 * pulse;

// 最终透明度
float finalAlpha = transparency;
finalAlpha += (1.0 - hexGrid) * 0.2 * pulse;
finalAlpha += fresnel * 0.4;
finalAlpha *= pulseIntensity;

return vec4(shieldFinal, finalAlpha);
}
}%

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
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
113
114
115
116
117
118
119
120
CCEffect %{
techniques:
- name: impact-force-field
passes:
- vert: impact-vs:vert
frag: impact-fs:frag
blendState:
targets:
- blend: true
blendSrc: src_alpha
blendDst: one
properties: &props
shieldColor: { value: [1.0, 0.4, 0.2, 1.0], editor: { type: color } }
impactPosition: { value: [0.0, 0.0, 0.0], editor: { type: vec3 } }
impactRadius: { value: 2.0, range: [0.1, 10.0] }
impactIntensity: { value: 3.0, range: [0.0, 10.0] }
waveSpeed: { value: 5.0, range: [1.0, 20.0] }
rippleCount: { value: 5.0, range: [1.0, 20.0] }
gridScale: { value: 15.0, range: [5.0, 50.0] }
distortionScale: { value: 0.1, range: [0.0, 0.5] }
noiseTexture: { value: white }
baseTransparency: { value: 0.2, range: [0.0, 1.0] }
}%

CCProgram impact-vs %{
precision highp float;
#include <cc-global>
#include <cc-local>

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

out vec3 v_worldPos;
out vec3 v_worldNormal;
out vec2 v_uv;

vec4 vert() {
vec4 worldPos = cc_matWorld * vec4(a_position, 1);
v_worldPos = worldPos.xyz;
v_worldNormal = normalize((cc_matWorldIT * vec4(a_normal, 0)).xyz);
v_uv = a_texCoord;

return cc_matViewProj * worldPos;
}
}%

CCProgram impact-fs %{
precision highp float;
#include <cc-global>
#include <cc-environment>

uniform sampler2D noiseTexture;
uniform vec4 shieldColor;
uniform vec3 impactPosition;
uniform float impactRadius;
uniform float impactIntensity;
uniform float waveSpeed;
uniform float rippleCount;
uniform float gridScale;
uniform float distortionScale;
uniform float baseTransparency;

in vec3 v_worldPos;
in vec3 v_worldNormal;
in vec2 v_uv;

vec4 frag() {
vec3 normal = normalize(v_worldNormal);
vec3 viewDir = normalize(cc_cameraPos.xyz - v_worldPos);

// 冲击点距离
float distanceToImpact = length(v_worldPos - impactPosition);

// 冲击波计算
float wave = sin((distanceToImpact - cc_time.x * waveSpeed) * rippleCount);
wave = wave * 0.5 + 0.5;

// 冲击衰减
float impactFade = 1.0 - smoothstep(0.0, impactRadius, distanceToImpact);
float impactEffect = wave * impactFade * impactIntensity;

// 扭曲效果
vec2 distortedUV = v_uv + normal.xy * impactEffect * distortionScale;
vec4 noise = texture(noiseTexture, distortedUV + cc_time.x * 0.1);

// 网格模式
vec2 gridUV = distortedUV * gridScale;
vec2 grid = abs(fract(gridUV) - 0.5) / fwidth(gridUV);
float gridLines = min(grid.x, grid.y);
gridLines = 1.0 - min(gridLines, 1.0);

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

// 合成效果
vec3 shieldFinal = shieldColor.rgb * baseTransparency;

// 冲击波发光
shieldFinal += shieldColor.rgb * impactEffect;

// 网格激活
shieldFinal += shieldColor.rgb * gridLines * (1.0 + impactEffect);

// 边缘增强
shieldFinal += shieldColor.rgb * fresnel * (1.0 + impactEffect * 0.5);

// 噪声扰动
shieldFinal += shieldColor.rgb * noise.r * impactEffect * 0.5;

// 最终透明度
float finalAlpha = baseTransparency;
finalAlpha += impactEffect * 0.7;
finalAlpha += gridLines * 0.3;
finalAlpha += fresnel * 0.4;

return vec4(shieldFinal, finalAlpha);
}
}%

3. 磁场力线效果

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
113
114
115
CCEffect %{
techniques:
- name: magnetic-field
passes:
- vert: magnetic-vs:vert
frag: magnetic-fs:frag
blendState:
targets:
- blend: true
blendSrc: src_alpha
blendDst: one_minus_src_alpha
properties: &props
fieldColor: { value: [0.8, 0.2, 1.0, 1.0], editor: { type: color } }
magnetCenter1: { value: [2.0, 0.0, 0.0], editor: { type: vec3 } }
magnetCenter2: { value: [-2.0, 0.0, 0.0], editor: { type: vec3 } }
fieldStrength: { value: 2.0, range: [0.1, 10.0] }
lineThickness: { value: 0.02, range: [0.005, 0.1] }
flowSpeed: { value: 3.0, range: [0.0, 10.0] }
density: { value: 20.0, range: [5.0, 100.0] }
noiseTexture: { value: white }
transparency: { value: 0.6, range: [0.0, 1.0] }
}%

CCProgram magnetic-vs %{
precision highp float;
#include <cc-global>
#include <cc-local>

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

out vec3 v_worldPos;
out vec3 v_worldNormal;
out vec2 v_uv;

vec4 vert() {
vec4 worldPos = cc_matWorld * vec4(a_position, 1);
v_worldPos = worldPos.xyz;
v_worldNormal = normalize((cc_matWorldIT * vec4(a_normal, 0)).xyz);
v_uv = a_texCoord;

return cc_matViewProj * worldPos;
}
}%

CCProgram magnetic-fs %{
precision highp float;
#include <cc-global>
#include <cc-environment>

uniform sampler2D noiseTexture;
uniform vec4 fieldColor;
uniform vec3 magnetCenter1;
uniform vec3 magnetCenter2;
uniform float fieldStrength;
uniform float lineThickness;
uniform float flowSpeed;
uniform float density;
uniform float transparency;

in vec3 v_worldPos;
in vec3 v_worldNormal;
in vec2 v_uv;

// 磁场线计算
vec3 magneticField(vec3 pos) {
vec3 field1 = (pos - magnetCenter1) / pow(length(pos - magnetCenter1), 3.0);
vec3 field2 = -(pos - magnetCenter2) / pow(length(pos - magnetCenter2), 3.0);
return fieldStrength * (field1 + field2);
}

vec4 frag() {
vec3 normal = normalize(v_worldNormal);
vec3 viewDir = normalize(cc_cameraPos.xyz - v_worldPos);

// 计算磁场方向
vec3 fieldVector = magneticField(v_worldPos);
vec3 fieldDirection = normalize(fieldVector);
float fieldMagnitude = length(fieldVector);

// 沿磁场线的坐标
float fieldLinePos = dot(v_worldPos, fieldDirection);

// 垂直于磁场线的距离
vec3 perpendicular = v_worldPos - fieldLinePos * fieldDirection;
float perpDistance = length(perpendicular);

// 磁场线强度
float lineIntensity = 1.0 - smoothstep(0.0, lineThickness, perpDistance);
lineIntensity *= fieldMagnitude;

// 流动效果
float flow = sin((fieldLinePos + cc_time.x * flowSpeed) * density);
flow = flow * 0.5 + 0.5;

// 噪声扰动
vec4 noise = texture(noiseTexture, v_uv + cc_time.x * 0.1);
lineIntensity *= (noise.r * 0.5 + 0.5);

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

// 合成磁场效果
vec3 fieldFinal = fieldColor.rgb * lineIntensity * flow;
fieldFinal += fieldColor.rgb * fresnel * 0.5;

// 最终透明度
float finalAlpha = transparency * lineIntensity * flow;
finalAlpha += fresnel * 0.3;

return vec4(fieldFinal, finalAlpha);
}
}%

🎨 高级力场特效

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
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
CCEffect %{
techniques:
- name: multi-layer-shield
passes:
- vert: multi-shield-vs:vert
frag: multi-shield-fs:frag
blendState:
targets:
- blend: true
blendSrc: src_alpha
blendDst: one_minus_src_alpha
properties: &props
layer1Color: { value: [0.2, 0.8, 1.0, 1.0], editor: { type: color } }
layer2Color: { value: [1.0, 0.6, 0.2, 1.0], editor: { type: color } }
layer3Color: { value: [0.8, 0.2, 1.0, 1.0], editor: { type: color } }
layer1Radius: { value: 1.0, range: [0.5, 2.0] }
layer2Radius: { value: 1.2, range: [0.7, 2.5] }
layer3Radius: { value: 1.5, range: [1.0, 3.0] }
rotationSpeed1: { value: 1.0, range: [0.0, 5.0] }
rotationSpeed2: { value: -1.5, range: [-5.0, 5.0] }
rotationSpeed3: { value: 0.8, range: [0.0, 5.0] }
interference: { value: 0.3, range: [0.0, 1.0] }
shieldStrength: { value: 1.0, range: [0.0, 3.0] }
noiseTexture: { value: white }
}%

CCProgram multi-shield-vs %{
precision highp float;
#include <cc-global>
#include <cc-local>

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

out vec3 v_worldPos;
out vec3 v_worldNormal;
out vec2 v_uv;
out float v_distanceFromCenter;

vec4 vert() {
vec4 worldPos = cc_matWorld * vec4(a_position, 1);
v_worldPos = worldPos.xyz;
v_worldNormal = normalize((cc_matWorldIT * vec4(a_normal, 0)).xyz);
v_uv = a_texCoord;
v_distanceFromCenter = length(a_position);

return cc_matViewProj * worldPos;
}
}%

CCProgram multi-shield-fs %{
precision highp float;
#include <cc-global>
#include <cc-environment>

uniform sampler2D noiseTexture;
uniform vec4 layer1Color;
uniform vec4 layer2Color;
uniform vec4 layer3Color;
uniform float layer1Radius;
uniform float layer2Radius;
uniform float layer3Radius;
uniform float rotationSpeed1;
uniform float rotationSpeed2;
uniform float rotationSpeed3;
uniform float interference;
uniform float shieldStrength;

in vec3 v_worldPos;
in vec3 v_worldNormal;
in vec2 v_uv;
in float v_distanceFromCenter;

// 旋转六边形网格
float rotatedHexGrid(vec2 uv, float rotation, float scale) {
float c = cos(rotation);
float s = sin(rotation);
mat2 rot = mat2(c, -s, s, c);
uv = rot * uv;

vec2 gridUV = uv * scale;
vec2 grid = abs(fract(gridUV) - 0.5) / fwidth(gridUV);
float gridLines = min(grid.x, grid.y);
return 1.0 - min(gridLines, 1.0);
}

vec4 frag() {
vec3 normal = normalize(v_worldNormal);
vec3 viewDir = normalize(cc_cameraPos.xyz - v_worldPos);

// 层级判断
float layer1Mask = smoothstep(layer1Radius - 0.1, layer1Radius, v_distanceFromCenter);
float layer2Mask = smoothstep(layer2Radius - 0.1, layer2Radius, v_distanceFromCenter);
float layer3Mask = smoothstep(layer3Radius - 0.1, layer3Radius, v_distanceFromCenter);

// 旋转网格
float grid1 = rotatedHexGrid(v_uv, cc_time.x * rotationSpeed1, 15.0);
float grid2 = rotatedHexGrid(v_uv, cc_time.x * rotationSpeed2, 20.0);
float grid3 = rotatedHexGrid(v_uv, cc_time.x * rotationSpeed3, 25.0);

// 噪声干扰
vec4 noise = texture(noiseTexture, v_uv + cc_time.x * 0.2);
float noiseInterference = noise.r * interference;

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

// 层级效果合成
vec3 shieldFinal = vec3(0.0);
float finalAlpha = 0.0;

// 第一层
if (layer1Mask > 0.0) {
vec3 layer1 = layer1Color.rgb * grid1 * (1.0 + noiseInterference);
layer1 += layer1Color.rgb * fresnel;
shieldFinal += layer1 * layer1Mask * shieldStrength;
finalAlpha += layer1Mask * 0.3;
}

// 第二层
if (layer2Mask > 0.0) {
vec3 layer2 = layer2Color.rgb * grid2 * (1.0 + noiseInterference);
layer2 += layer2Color.rgb * fresnel;
shieldFinal += layer2 * layer2Mask * shieldStrength;
finalAlpha += layer2Mask * 0.25;
}

// 第三层
if (layer3Mask > 0.0) {
vec3 layer3 = layer3Color.rgb * grid3 * (1.0 + noiseInterference);
layer3 += layer3Color.rgb * fresnel;
shieldFinal += layer3 * layer3Mask * shieldStrength;
finalAlpha += layer3Mask * 0.2;
}

// 边缘增强
shieldFinal += mix(layer1Color.rgb, layer3Color.rgb, 0.5) * fresnel;
finalAlpha += fresnel * 0.4;

return vec4(shieldFinal, finalAlpha);
}
}%

🔧 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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
import { Component, Material, Color, Vec3, _decorator } from 'cc';

const { ccclass, property, menu } = _decorator;

enum ForceFieldType {
Sphere = 'sphere-force-field',
Impact = 'impact-force-field',
Magnetic = 'magnetic-field',
MultiLayer = 'multi-layer-shield'
}

@ccclass('ForceFieldController')
@menu('Custom/ForceFieldController')
export class ForceFieldController extends Component {

@property({ type: Color, displayName: '力场颜色' })
public shieldColor: Color = new Color(50, 200, 255, 255);

@property({ range: [0.0, 1.0], displayName: '透明度' })
public transparency: number = 0.3;

@property({ range: [5.0, 100.0], displayName: '网格密度' })
public gridScale: number = 20.0;

@property({ range: [0.01, 0.2], displayName: '网格厚度' })
public gridThickness: number = 0.05;

@property({ range: [0.0, 10.0], displayName: '能量流速' })
public energySpeed: number = 2.0;

@property({ range: [0.1, 5.0], displayName: '菲涅尔强度' })
public fresnelPower: number = 2.0;

@property({ type: Vec3, displayName: '冲击点位置' })
public impactPosition: Vec3 = new Vec3(0, 0, 0);

@property({ range: [0.1, 10.0], displayName: '冲击半径' })
public impactRadius: number = 2.0;

@property({ range: [0.0, 10.0], displayName: '冲击强度' })
public impactIntensity: number = 3.0;

@property({ displayName: '力场类型' })
public forceFieldType: ForceFieldType = ForceFieldType.Sphere;

@property({ displayName: '启用多层防护' })
public enableMultiLayer: boolean = false;

@property({ range: [0.0, 3.0], displayName: '护盾强度' })
public shieldStrength: number = 1.0;

private _material: Material | null = null;
private _isActive: boolean = false;
private _impactTimer: number = 0;
private _impactActive: boolean = false;

onLoad() {
const renderer = this.getComponent('cc.MeshRenderer');
if (renderer && renderer.material) {
this._material = renderer.material;
this.updateMaterial();
}
}

update(deltaTime: number) {
if (this._isActive) {
if (this._impactActive) {
this._impactTimer += deltaTime;
// 冲击效果会自动衰减
if (this._impactTimer > 3.0) {
this._impactActive = false;
this._impactTimer = 0;
}
}
this.updateMaterial();
}
}

private updateMaterial() {
if (!this._material) return;

// 基础力场参数
this._material.setProperty('shieldColor', this.shieldColor);
this._material.setProperty('transparency', this.transparency);
this._material.setProperty('gridScale', this.gridScale);
this._material.setProperty('gridThickness', this.gridThickness);
this._material.setProperty('energySpeed', this.energySpeed);
this._material.setProperty('fresnel_power', this.fresnelPower);

// 冲击效果参数
this._material.setProperty('impactPosition', this.impactPosition);
this._material.setProperty('impactRadius', this.impactRadius);
this._material.setProperty('impactIntensity', this.impactIntensity);

// 多层防护参数
if (this.enableMultiLayer) {
this._material.setProperty('shieldStrength', this.shieldStrength);
}
}

// 公共接口
public setForceFieldType(type: ForceFieldType) {
this.forceFieldType = type;
console.log(`切换到力场类型: ${type}`);
this.updateMaterial();
}

public activateShield() {
this._isActive = true;
this.transparency = 0;

// 激活动画
let elapsed = 0;
const activate = (dt: number) => {
elapsed += dt;
const t = Math.min(elapsed / 1.0, 1.0);

this.transparency = t * 0.3;
this.shieldStrength = t * 2.0;
this.updateMaterial();

if (t < 1.0) {
this.scheduleOnce(activate, 0);
}
};

this.scheduleOnce(activate, 0);
}

public deactivateShield() {
const originalTransparency = this.transparency;
const originalStrength = this.shieldStrength;

let elapsed = 0;
const deactivate = (dt: number) => {
elapsed += dt;
const t = Math.min(elapsed / 0.8, 1.0);

this.transparency = originalTransparency * (1.0 - t);
this.shieldStrength = originalStrength * (1.0 - t);
this.updateMaterial();

if (t >= 1.0) {
this._isActive = false;
} else {
this.scheduleOnce(deactivate, 0);
}
};

this.scheduleOnce(deactivate, 0);
}

public triggerImpact(worldPosition: Vec3, intensity: number = 3.0) {
this.impactPosition.set(worldPosition);
this.impactIntensity = intensity;
this._impactActive = true;
this._impactTimer = 0;

// 切换到冲击力场模式
this.setForceFieldType(ForceFieldType.Impact);

this.updateMaterial();
}

public setShieldColor(color: Color) {
this.shieldColor = color;
this.updateMaterial();
}

public setShieldStrength(strength: number) {
this.shieldStrength = strength;
this.updateMaterial();
}

// 预设效果
public applyDefensiveShield() {
this.shieldColor = new Color(100, 150, 255, 255); // 蓝色
this.gridScale = 20.0;
this.energySpeed = 1.0;
this.transparency = 0.4;
this.setForceFieldType(ForceFieldType.Sphere);
}

public applyAttackShield() {
this.shieldColor = new Color(255, 100, 100, 255); // 红色
this.gridScale = 15.0;
this.energySpeed = 3.0;
this.transparency = 0.6;
this.setForceFieldType(ForceFieldType.Impact);
}

public applyAdvancedShield() {
this.enableMultiLayer = true;
this.shieldStrength = 2.0;
this.transparency = 0.3;
this.setForceFieldType(ForceFieldType.MultiLayer);
}

public applyMagneticField() {
this.shieldColor = new Color(200, 100, 255, 255); // 紫色
this.energySpeed = 2.5;
this.transparency = 0.5;
this.setForceFieldType(ForceFieldType.Magnetic);
}

// 特殊效果
public shieldOverload(duration: number = 3.0) {
const originalColor = this.shieldColor.clone();
const originalIntensity = this.impactIntensity;

// 过载效果
this.shieldColor = new Color(255, 255, 100, 255); // 黄色
this.impactIntensity = 5.0;
this.energySpeed = 8.0;

this.scheduleOnce(() => {
this.shieldColor.set(originalColor);
this.impactIntensity = originalIntensity;
this.energySpeed = 2.0;
this.updateMaterial();
}, duration);

this.updateMaterial();
}

public emergencyShield() {
// 紧急护盾 - 快速激活
this.shieldColor = new Color(255, 200, 100, 255); // 橙色
this.shieldStrength = 3.0;
this.transparency = 0.8;
this.energySpeed = 5.0;

this.activateShield();
}

public adaptiveShield(threatLevel: number) {
// 自适应护盾 - 根据威胁等级调整
threatLevel = Math.max(0, Math.min(1, threatLevel));

const baseColor = new Color(100, 200, 255, 255);
const alertColor = new Color(255, 100, 100, 255);

// 颜色插值
this.shieldColor.r = Math.lerp(baseColor.r, alertColor.r, threatLevel);
this.shieldColor.g = Math.lerp(baseColor.g, alertColor.g, threatLevel);
this.shieldColor.b = Math.lerp(baseColor.b, alertColor.b, threatLevel);

// 参数调整
this.shieldStrength = 1.0 + threatLevel * 2.0;
this.transparency = 0.3 + threatLevel * 0.4;
this.energySpeed = 1.0 + threatLevel * 4.0;

this.updateMaterial();
}

public resetToDefault() {
this.shieldColor = new Color(50, 200, 255, 255);
this.transparency = 0.3;
this.gridScale = 20.0;
this.gridThickness = 0.05;
this.energySpeed = 2.0;
this.fresnelPower = 2.0;
this.shieldStrength = 1.0;
this.enableMultiLayer = false;
this.updateMaterial();
}
}

// 导出枚举
export { ForceFieldType };

📖 本章总结

通过本章学习,我们掌握了:

  • ✅ 力场视觉效果的基本原理和特征
  • ✅ 球形护盾、冲击反应、磁场力线实现
  • ✅ 多层防护系统和高级特效
  • ✅ 完整的TypeScript控制系统和预设效果
  • ✅ 科幻游戏中力场特效的实际应用

🚀 下一步学习

掌握3D力场着色器后,建议继续学习:

👉 10.4章:3D顶点动画着色器

💡 实践练习

  1. 创建一个可交互的防护盾系统
  2. 实现多种威胁等级的自适应护盾
  3. 开发磁场可视化和科幻界面特效

系列导航