@fps-games/vfx 0.3.17 → 0.3.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,16 @@
|
|
|
12
12
|
|
|
13
13
|
<!-- release.mjs 在此行下方插入新版本区块 -->
|
|
14
14
|
|
|
15
|
+
## v0.3.18 — 2026-07-14
|
|
16
|
+
|
|
17
|
+
### 改动
|
|
18
|
+
- fix(tooling): support validation on Windows
|
|
19
|
+
- feat(energy-shield): align dome shader rendering
|
|
20
|
+
- feat(energy-shield): refine glass shield rendering
|
|
21
|
+
|
|
22
|
+
### 特效
|
|
23
|
+
- 无新增 / 删除(仍 41 个)。
|
|
24
|
+
|
|
15
25
|
## v0.3.16 — 2026-07-08
|
|
16
26
|
|
|
17
27
|
### 改动
|
|
@@ -10,10 +10,19 @@ export interface EnergyShieldParams extends VfxParamValues {
|
|
|
10
10
|
radius: number;
|
|
11
11
|
verticalScale: number;
|
|
12
12
|
color: VfxColorValue;
|
|
13
|
+
baseColor: VfxColorValue;
|
|
13
14
|
opacity: number;
|
|
14
15
|
fresnelPower: number;
|
|
15
16
|
fresnelStrength: number;
|
|
16
17
|
rimIntensity: number;
|
|
18
|
+
baseGlowStrength: number;
|
|
19
|
+
baseGlowHeight: number;
|
|
20
|
+
surfaceVariation: number;
|
|
21
|
+
backRimStrength: number;
|
|
22
|
+
backGlowStrength: number;
|
|
23
|
+
backGlowHeight: number;
|
|
24
|
+
showSurfaceTexture: boolean;
|
|
25
|
+
showSurfaceFlow: boolean;
|
|
17
26
|
surfaceIntensity: number;
|
|
18
27
|
noiseScale: number;
|
|
19
28
|
noiseEdgeWidth: number;
|
|
@@ -42,6 +51,8 @@ export interface CreateEnergyShieldOptions {
|
|
|
42
51
|
export interface EnergyShieldHandle extends VfxEffectHandle {
|
|
43
52
|
shield: Mesh;
|
|
44
53
|
material: ShaderMaterial;
|
|
54
|
+
backShield: Mesh;
|
|
55
|
+
backMaterial: ShaderMaterial;
|
|
45
56
|
glowLayer: GlowLayer | null;
|
|
46
57
|
update(params: Partial<EnergyShieldParams>): void;
|
|
47
58
|
}
|
|
@@ -9,29 +9,37 @@ import { TransformNode } from "@babylonjs/core/Meshes/transformNode";
|
|
|
9
9
|
import { V as VFX_RENDERING_GROUP_ID } from "../../chunks/rendering-CV3nhygX.js";
|
|
10
10
|
const SHADER_NAME = "vfxEnergyShield";
|
|
11
11
|
const HALO_ALPHA_SCALE_MAX = 0.3;
|
|
12
|
-
const
|
|
13
|
-
const HALO_FEATHER_SCALE_OFFSET = 0.018;
|
|
12
|
+
const SHIELD_SLICE = 0.5;
|
|
14
13
|
const DEFAULT_PARAMS = {
|
|
15
14
|
radius: 3.18,
|
|
16
|
-
verticalScale: 1
|
|
17
|
-
color: { r: 0.
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
15
|
+
verticalScale: 1,
|
|
16
|
+
color: { r: 0.28627451, g: 0.50980392, b: 1 },
|
|
17
|
+
baseColor: { r: 0.28627451, g: 0.50980392, b: 1 },
|
|
18
|
+
opacity: 0.02,
|
|
19
|
+
fresnelPower: 2,
|
|
20
|
+
fresnelStrength: 1,
|
|
21
|
+
rimIntensity: 1,
|
|
22
|
+
baseGlowStrength: 0.32,
|
|
23
|
+
baseGlowHeight: 0.46,
|
|
24
|
+
surfaceVariation: 0,
|
|
25
|
+
backRimStrength: 1,
|
|
26
|
+
backGlowStrength: 0.36,
|
|
27
|
+
backGlowHeight: 0.49,
|
|
28
|
+
showSurfaceTexture: false,
|
|
29
|
+
showSurfaceFlow: false,
|
|
30
|
+
surfaceIntensity: 0.04,
|
|
31
|
+
noiseScale: 0.9,
|
|
32
|
+
noiseEdgeWidth: 0.08,
|
|
33
|
+
noiseEdgeIntensity: 0.62,
|
|
34
|
+
noiseEdgeSmoothness: 0.3,
|
|
35
|
+
flowScale: 2.15,
|
|
36
|
+
flowSpeed: 0.18,
|
|
37
|
+
flowIntensity: 0.2,
|
|
38
|
+
marbleContrast: 1,
|
|
39
|
+
bloomIntensity: 0.4,
|
|
32
40
|
bloomKernelSize: 36,
|
|
33
|
-
showGlowLayer:
|
|
34
|
-
haloScale: 1.
|
|
41
|
+
showGlowLayer: false,
|
|
42
|
+
haloScale: 1.006,
|
|
35
43
|
showHalo: false,
|
|
36
44
|
segments: 64
|
|
37
45
|
};
|
|
@@ -61,11 +69,17 @@ precision highp float;
|
|
|
61
69
|
|
|
62
70
|
uniform float uTime;
|
|
63
71
|
uniform vec3 cameraPosition;
|
|
64
|
-
uniform vec3
|
|
72
|
+
uniform vec3 uTopColor;
|
|
73
|
+
uniform vec3 uBaseColor;
|
|
65
74
|
uniform float uOpacity;
|
|
66
75
|
uniform float uFresnelPower;
|
|
67
|
-
uniform float
|
|
76
|
+
uniform float uRimStrength;
|
|
68
77
|
uniform float uRimIntensity;
|
|
78
|
+
uniform float uHorizonStrength;
|
|
79
|
+
uniform float uHorizonHeight;
|
|
80
|
+
uniform float uSurfaceVariation;
|
|
81
|
+
uniform float uSurfaceTextureEnabled;
|
|
82
|
+
uniform float uSurfaceFlowEnabled;
|
|
69
83
|
uniform float uSurfaceIntensity;
|
|
70
84
|
uniform float uNoiseScale;
|
|
71
85
|
uniform float uNoiseEdgeWidth;
|
|
@@ -75,137 +89,69 @@ uniform float uFlowScale;
|
|
|
75
89
|
uniform float uFlowSpeed;
|
|
76
90
|
uniform float uFlowIntensity;
|
|
77
91
|
uniform float uMarbleContrast;
|
|
78
|
-
uniform float
|
|
79
|
-
uniform float uHaloMode;
|
|
92
|
+
uniform float uAlphaScale;
|
|
80
93
|
|
|
81
94
|
varying vec3 vObjPos;
|
|
82
95
|
varying vec3 vWorldPos;
|
|
83
96
|
varying vec3 vNormalW;
|
|
84
97
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
float saturate(float v) { return clamp(v, 0.0, 1.0); }
|
|
91
|
-
|
|
92
|
-
float snoise(vec3 v) {
|
|
93
|
-
const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0);
|
|
94
|
-
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
|
|
95
|
-
vec3 i = floor(v + dot(v, C.yyy));
|
|
96
|
-
vec3 x0 = v - i + dot(i, C.xxx);
|
|
97
|
-
vec3 g = step(x0.yzx, x0.xyz);
|
|
98
|
-
vec3 l = 1.0 - g;
|
|
99
|
-
vec3 i1 = min(g.xyz, l.zxy);
|
|
100
|
-
vec3 i2 = max(g.xyz, l.zxy);
|
|
101
|
-
vec3 x1 = x0 - i1 + C.xxx;
|
|
102
|
-
vec3 x2 = x0 - i2 + C.yyy;
|
|
103
|
-
vec3 x3 = x0 - D.yyy;
|
|
104
|
-
i = mod289v3(i);
|
|
105
|
-
vec4 p = permute(permute(permute(
|
|
106
|
-
i.z + vec4(0.0, i1.z, i2.z, 1.0))
|
|
107
|
-
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
|
|
108
|
-
+ i.x + vec4(0.0, i1.x, i2.x, 1.0));
|
|
109
|
-
float n_ = 0.142857142857;
|
|
110
|
-
vec3 ns = n_ * D.wyz - D.xzx;
|
|
111
|
-
vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
|
|
112
|
-
vec4 x_ = floor(j * ns.z);
|
|
113
|
-
vec4 y_ = floor(j - 7.0 * x_);
|
|
114
|
-
vec4 x = x_ * ns.x + ns.yyyy;
|
|
115
|
-
vec4 y = y_ * ns.x + ns.yyyy;
|
|
116
|
-
vec4 h = 1.0 - abs(x) - abs(y);
|
|
117
|
-
vec4 b0 = vec4(x.xy, y.xy);
|
|
118
|
-
vec4 b1 = vec4(x.zw, y.zw);
|
|
119
|
-
vec4 s0 = floor(b0) * 2.0 + 1.0;
|
|
120
|
-
vec4 s1 = floor(b1) * 2.0 + 1.0;
|
|
121
|
-
vec4 sh = -step(h, vec4(0.0));
|
|
122
|
-
vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
|
|
123
|
-
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
|
|
124
|
-
vec3 p0 = vec3(a0.xy, h.x);
|
|
125
|
-
vec3 p1 = vec3(a0.zw, h.y);
|
|
126
|
-
vec3 p2 = vec3(a1.xy, h.z);
|
|
127
|
-
vec3 p3 = vec3(a1.zw, h.w);
|
|
128
|
-
vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
|
|
129
|
-
p0 *= norm.x;
|
|
130
|
-
p1 *= norm.y;
|
|
131
|
-
p2 *= norm.z;
|
|
132
|
-
p3 *= norm.w;
|
|
133
|
-
vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);
|
|
134
|
-
m = m * m;
|
|
135
|
-
return 42.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));
|
|
98
|
+
float hash(vec3 position) {
|
|
99
|
+
position = fract(position * 0.3183099 + 0.1);
|
|
100
|
+
position *= 17.0;
|
|
101
|
+
return fract(position.x * position.y * position.z * (position.x + position.y + position.z));
|
|
136
102
|
}
|
|
137
103
|
|
|
138
|
-
float
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
104
|
+
float valueNoise(vec3 position) {
|
|
105
|
+
vec3 cell = floor(position);
|
|
106
|
+
vec3 local = fract(position);
|
|
107
|
+
local = local * local * (3.0 - 2.0 * local);
|
|
108
|
+
|
|
109
|
+
return mix(
|
|
110
|
+
mix(
|
|
111
|
+
mix(hash(cell), hash(cell + vec3(1.0, 0.0, 0.0)), local.x),
|
|
112
|
+
mix(hash(cell + vec3(0.0, 1.0, 0.0)), hash(cell + vec3(1.0, 1.0, 0.0)), local.x),
|
|
113
|
+
local.y
|
|
114
|
+
),
|
|
115
|
+
mix(
|
|
116
|
+
mix(hash(cell + vec3(0.0, 0.0, 1.0)), hash(cell + vec3(1.0, 0.0, 1.0)), local.x),
|
|
117
|
+
mix(hash(cell + vec3(0.0, 1.0, 1.0)), hash(cell + vec3(1.0, 1.0, 1.0)), local.x),
|
|
118
|
+
local.y
|
|
119
|
+
),
|
|
120
|
+
local.z
|
|
121
|
+
);
|
|
149
122
|
}
|
|
150
123
|
|
|
151
124
|
void main(void) {
|
|
152
|
-
vec3 normalW = normalize(vNormalW);
|
|
153
125
|
vec3 viewDir = normalize(cameraPosition - vWorldPos);
|
|
154
|
-
float
|
|
155
|
-
float
|
|
156
|
-
float
|
|
157
|
-
|
|
158
|
-
float t = uTime * uFlowSpeed;
|
|
159
|
-
vec3 spherePos = normalize(vObjPos + vec3(0.0001)) * max(0.05, uNoiseScale);
|
|
160
|
-
vec3 flowA = spherePos * uFlowScale + vec3(t, t * 0.62, t * 0.38);
|
|
161
|
-
vec3 flowB = spherePos * (uFlowScale * 1.91) + vec3(-t * 0.46, t * 0.82, -t * 0.27);
|
|
162
|
-
float n1 = fbm(flowA);
|
|
163
|
-
float n2 = fbm(flowB);
|
|
164
|
-
float cloud = saturate((n1 * 0.58 + n2 * 0.42) * 0.5 + 0.5);
|
|
165
|
-
|
|
166
|
-
float veinInput = spherePos.y * 0.92 + n1 * 1.65 + n2 * 0.74 + t * 0.13;
|
|
167
|
-
float ribbon = abs(sin(veinInput * 3.14159265));
|
|
168
|
-
float marble = pow(1.0 - ribbon, max(0.25, uMarbleContrast));
|
|
169
|
-
float nebula = saturate(mix(cloud, marble, 0.58) * uFlowIntensity * 0.34);
|
|
170
|
-
|
|
171
|
-
float edgeWidth = max(0.01, uNoiseEdgeWidth);
|
|
172
|
-
float edgeSoft = max(0.01, uNoiseEdgeSmoothness) * 0.22;
|
|
173
|
-
float noiseEdge = smoothstep(1.0 - edgeWidth - edgeSoft, 1.0 - edgeWidth * 0.22, nebula);
|
|
174
|
-
|
|
175
|
-
vec3 deepBlue = uColor * (0.12 + 0.42 * cloud);
|
|
176
|
-
vec3 marbleBlue = uColor * (0.34 + 0.9 * marble) * uSurfaceIntensity;
|
|
177
|
-
vec3 rimBlue = uColor * fresnel * uRimIntensity;
|
|
178
|
-
vec3 edgeBlue = uColor * noiseEdge * uNoiseEdgeIntensity;
|
|
179
|
-
vec3 color = min((deepBlue + marbleBlue + rimBlue + edgeBlue) * 0.72, vec3(1.12));
|
|
180
|
-
|
|
181
|
-
float alpha = uOpacity * (0.16 + 0.34 * cloud + 0.24 * marble);
|
|
182
|
-
alpha += fresnel * uOpacity * 0.58;
|
|
183
|
-
alpha += noiseEdge * uNoiseEdgeIntensity * 0.05;
|
|
126
|
+
float facing = abs(dot(normalize(vNormalW), viewDir));
|
|
127
|
+
float rim = pow(1.0 - facing, max(0.05, uFresnelPower));
|
|
128
|
+
float horizon = pow(1.0 - clamp(vObjPos.y / max(0.001, uHorizonHeight), 0.0, 1.0), 2.5);
|
|
129
|
+
float heightFactor = smoothstep(0.0, 0.92, vObjPos.y);
|
|
184
130
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
float featherOut = 1.0 - smoothstep(0.72, 1.0, haloRim);
|
|
189
|
-
float featherRim = featherIn * featherOut;
|
|
190
|
-
float outerFade = 1.0 - smoothstep(0.88, 1.0, haloRim);
|
|
191
|
-
color = uColor * (0.2 + featherRim * 0.24 + cloud * 0.04);
|
|
192
|
-
alpha = featherRim * 0.58 * outerFade;
|
|
193
|
-
} else if (uHaloMode > 0.5) {
|
|
194
|
-
float haloRim = pow(viewRim, max(0.3, uFresnelPower * 0.48));
|
|
195
|
-
float bodyIn = smoothstep(0.34, 0.68, haloRim);
|
|
196
|
-
float bodyOut = 1.0 - smoothstep(0.72, 1.0, haloRim);
|
|
197
|
-
float bodyRim = bodyIn * bodyOut;
|
|
198
|
-
float featherIn = smoothstep(0.12, 0.44, haloRim);
|
|
199
|
-
float featherOut = 1.0 - smoothstep(0.48, 1.0, haloRim);
|
|
200
|
-
float featherRim = featherIn * featherOut;
|
|
201
|
-
float outerFade = 1.0 - smoothstep(0.86, 1.0, haloRim);
|
|
202
|
-
color = uColor * (0.24 + bodyRim * 0.34 + featherRim * 0.12 + cloud * 0.05);
|
|
203
|
-
alpha = (bodyRim * 0.5 + featherRim * 0.14 + noiseEdge * 0.01) * outerFade;
|
|
131
|
+
vec3 motion = vec3(0.0);
|
|
132
|
+
if (uSurfaceFlowEnabled > 0.5) {
|
|
133
|
+
motion = vec3(uTime * uFlowSpeed, -uTime * uFlowSpeed * 0.62, uTime * uFlowSpeed * 0.38);
|
|
204
134
|
}
|
|
135
|
+
float cloud = valueNoise(vObjPos * max(0.05, uNoiseScale)) * 0.65;
|
|
136
|
+
cloud += valueNoise(vObjPos * max(0.05, uFlowScale) + motion) * 0.35;
|
|
137
|
+
float shapedCloud = pow(clamp(cloud, 0.0, 1.0), max(0.25, uMarbleContrast));
|
|
138
|
+
float surfaceTexture = step(0.5, uSurfaceTextureEnabled);
|
|
139
|
+
float variation = mix(1.0, mix(1.0 - uSurfaceVariation, 1.0 + uSurfaceVariation, shapedCloud), surfaceTexture);
|
|
140
|
+
float cloudShade = mix(1.0, mix(0.92, 1.08, shapedCloud), surfaceTexture);
|
|
141
|
+
rim *= cloudShade;
|
|
205
142
|
|
|
206
|
-
|
|
143
|
+
float edgeWidth = max(0.005, uNoiseEdgeWidth);
|
|
144
|
+
float edgeSoftness = max(0.005, uNoiseEdgeSmoothness * 0.2);
|
|
145
|
+
float flowBand = 1.0 - smoothstep(edgeWidth, edgeWidth + edgeSoftness, abs(shapedCloud - 0.5));
|
|
146
|
+
float flowGlow = flowBand * uFlowIntensity * uNoiseEdgeIntensity * uSurfaceFlowEnabled * surfaceTexture;
|
|
207
147
|
|
|
208
|
-
|
|
148
|
+
float alpha = uOpacity * variation + rim * uRimStrength + horizon * uHorizonStrength * variation;
|
|
149
|
+
alpha += flowGlow * uOpacity * 0.5;
|
|
150
|
+
vec3 gradientColor = mix(uBaseColor, uTopColor, heightFactor);
|
|
151
|
+
vec3 color = gradientColor * (0.25 + rim * 1.3 + horizon * 0.85) * cloudShade * uRimIntensity;
|
|
152
|
+
color += gradientColor * flowGlow * uSurfaceIntensity;
|
|
153
|
+
|
|
154
|
+
gl_FragColor = vec4(color, clamp(alpha * uAlphaScale, 0.0, 0.88));
|
|
209
155
|
}
|
|
210
156
|
`;
|
|
211
157
|
const energyShieldEffectPackage = {
|
|
@@ -222,11 +168,20 @@ const energyShieldEffectPackage = {
|
|
|
222
168
|
debugParams: [
|
|
223
169
|
{ key: "radius", label: "玻璃罩半径", kind: "scale", min: 0.4, max: 10, step: 0.01 },
|
|
224
170
|
{ key: "verticalScale", label: "纵向缩放", kind: "scale", min: 0.5, max: 1.8, step: 0.01 },
|
|
225
|
-
{ key: "color", label: "
|
|
226
|
-
{ key: "
|
|
227
|
-
{ key: "
|
|
228
|
-
{ key: "
|
|
171
|
+
{ key: "color", label: "顶部颜色", kind: "color" },
|
|
172
|
+
{ key: "baseColor", label: "底部颜色", kind: "color" },
|
|
173
|
+
{ key: "opacity", label: "球壳透明度", kind: "opacity", min: 0, max: 1, step: 0.01 },
|
|
174
|
+
{ key: "fresnelPower", label: "轮廓衰减", kind: "number", min: 0.2, max: 8, step: 0.01 },
|
|
175
|
+
{ key: "fresnelStrength", label: "正面轮廓强度", kind: "number", min: 0, max: 2.5, step: 0.01 },
|
|
229
176
|
{ key: "rimIntensity", label: "轮廓亮度", kind: "number", min: 0, max: 4, step: 0.01 },
|
|
177
|
+
{ key: "baseGlowStrength", label: "正面底部辉光", kind: "number", min: 0, max: 1, step: 0.01 },
|
|
178
|
+
{ key: "baseGlowHeight", label: "正面辉光高度", kind: "number", min: 0.04, max: 1, step: 0.01 },
|
|
179
|
+
{ key: "surfaceVariation", label: "表面明暗变化", kind: "number", min: 0, max: 0.6, step: 0.01 },
|
|
180
|
+
{ key: "backRimStrength", label: "背面轮廓强度", kind: "number", min: 0, max: 1.5, step: 0.01 },
|
|
181
|
+
{ key: "backGlowStrength", label: "背面底部辉光", kind: "number", min: 0, max: 1, step: 0.01 },
|
|
182
|
+
{ key: "backGlowHeight", label: "背面辉光高度", kind: "number", min: 0.04, max: 1, step: 0.01 },
|
|
183
|
+
{ key: "showSurfaceTexture", label: "显示表面纹理", kind: "boolean" },
|
|
184
|
+
{ key: "showSurfaceFlow", label: "显示表面流动", kind: "boolean" },
|
|
230
185
|
{ key: "surfaceIntensity", label: "表面亮度", kind: "number", min: 0, max: 3, step: 0.01 },
|
|
231
186
|
{ key: "noiseScale", label: "噪声缩放", kind: "number", min: 0.2, max: 5, step: 0.01 },
|
|
232
187
|
{ key: "noiseEdgeWidth", label: "噪声亮边宽度", kind: "number", min: 0.01, max: 0.5, step: 0.01 },
|
|
@@ -237,10 +192,10 @@ const energyShieldEffectPackage = {
|
|
|
237
192
|
{ key: "flowIntensity", label: "流动强度", kind: "number", min: 0, max: 8, step: 0.01 },
|
|
238
193
|
{ key: "marbleContrast", label: "纹路锐度", kind: "number", min: 0.25, max: 4, step: 0.01 },
|
|
239
194
|
{ key: "bloomIntensity", label: "Bloom 强度", kind: "number", min: 0, max: 4, step: 0.01 },
|
|
240
|
-
{ key: "bloomKernelSize", label: "
|
|
241
|
-
{ key: "showGlowLayer", label: "显示
|
|
242
|
-
{ key: "haloScale", label: "
|
|
243
|
-
{ key: "showHalo", label: "
|
|
195
|
+
{ key: "bloomKernelSize", label: "Bloom/Glow 半径", kind: "number", min: 8, max: 128, step: 1 },
|
|
196
|
+
{ key: "showGlowLayer", label: "显示 Bloom/Glow", kind: "boolean" },
|
|
197
|
+
{ key: "haloScale", label: "Halo 缩放", kind: "scale", min: 1, max: 1.08, step: 1e-3 },
|
|
198
|
+
{ key: "showHalo", label: "显示额外 Halo", kind: "boolean" }
|
|
244
199
|
],
|
|
245
200
|
create({ scene, root, position, renderingGroupId, params, runtime }) {
|
|
246
201
|
return createEnergyShield(scene, {
|
|
@@ -268,7 +223,7 @@ function createEnergyShield(scene, options = {}) {
|
|
|
268
223
|
{
|
|
269
224
|
diameter: 2,
|
|
270
225
|
segments: Math.max(16, Math.round(params.segments)),
|
|
271
|
-
slice:
|
|
226
|
+
slice: SHIELD_SLICE,
|
|
272
227
|
updatable: false
|
|
273
228
|
},
|
|
274
229
|
scene
|
|
@@ -278,25 +233,40 @@ function createEnergyShield(scene, options = {}) {
|
|
|
278
233
|
shield.alwaysSelectAsActiveMesh = true;
|
|
279
234
|
shield.renderingGroupId = options.renderingGroupId ?? VFX_RENDERING_GROUP_ID;
|
|
280
235
|
shield.alphaIndex = 20;
|
|
281
|
-
const material = createShieldMaterial(scene);
|
|
236
|
+
const material = createShieldMaterial(scene, { face: "front" });
|
|
282
237
|
shield.material = material;
|
|
238
|
+
const backShield = MeshBuilder.CreateSphere(
|
|
239
|
+
"vfx_energyShield_back_hemisphere",
|
|
240
|
+
{
|
|
241
|
+
diameter: 2,
|
|
242
|
+
segments: Math.max(16, Math.round(params.segments)),
|
|
243
|
+
slice: SHIELD_SLICE,
|
|
244
|
+
updatable: false
|
|
245
|
+
},
|
|
246
|
+
scene
|
|
247
|
+
);
|
|
248
|
+
backShield.parent = root;
|
|
249
|
+
backShield.isPickable = false;
|
|
250
|
+
backShield.alwaysSelectAsActiveMesh = true;
|
|
251
|
+
backShield.renderingGroupId = shield.renderingGroupId;
|
|
252
|
+
backShield.alphaIndex = shield.alphaIndex - 1;
|
|
253
|
+
const backMaterial = createShieldMaterial(scene, {
|
|
254
|
+
name: "vfx_energyShield_back_material",
|
|
255
|
+
alphaMode: Constants.ALPHA_ADD,
|
|
256
|
+
face: "back"
|
|
257
|
+
});
|
|
258
|
+
backShield.material = backMaterial;
|
|
283
259
|
const sharedGlowLayer = options.glowLayer ?? null;
|
|
284
260
|
let glowLayer = null;
|
|
285
261
|
let ownsGlowLayer = false;
|
|
286
262
|
let glowMeshIncluded = false;
|
|
287
263
|
let halo = null;
|
|
288
264
|
let haloMaterial = null;
|
|
289
|
-
let haloFeather = null;
|
|
290
|
-
let haloFeatherMaterial = null;
|
|
291
265
|
const disposeHalo = () => {
|
|
292
266
|
halo?.dispose(false, false);
|
|
293
267
|
haloMaterial?.dispose();
|
|
294
|
-
haloFeather?.dispose(false, false);
|
|
295
|
-
haloFeatherMaterial?.dispose();
|
|
296
268
|
halo = null;
|
|
297
269
|
haloMaterial = null;
|
|
298
|
-
haloFeather = null;
|
|
299
|
-
haloFeatherMaterial = null;
|
|
300
270
|
};
|
|
301
271
|
const addGlowMesh = () => {
|
|
302
272
|
if (!glowLayer || glowMeshIncluded) return;
|
|
@@ -348,7 +318,7 @@ function createEnergyShield(scene, options = {}) {
|
|
|
348
318
|
{
|
|
349
319
|
diameter: 2,
|
|
350
320
|
segments: Math.max(16, Math.round(params.segments)),
|
|
351
|
-
slice:
|
|
321
|
+
slice: SHIELD_SLICE,
|
|
352
322
|
updatable: false
|
|
353
323
|
},
|
|
354
324
|
scene
|
|
@@ -361,43 +331,21 @@ function createEnergyShield(scene, options = {}) {
|
|
|
361
331
|
halo.scaling.setAll(Math.max(1, params.haloScale));
|
|
362
332
|
haloMaterial = createShieldMaterial(scene, {
|
|
363
333
|
name: "vfx_energyShield_halo_material",
|
|
364
|
-
alphaMode: Constants.ALPHA_ADD
|
|
334
|
+
alphaMode: Constants.ALPHA_ADD,
|
|
335
|
+
face: "front"
|
|
365
336
|
});
|
|
366
337
|
halo.material = haloMaterial;
|
|
367
338
|
}
|
|
368
|
-
if (!haloFeather || !haloFeatherMaterial) {
|
|
369
|
-
haloFeather = MeshBuilder.CreateSphere(
|
|
370
|
-
"vfx_energyShield_halo_feather",
|
|
371
|
-
{
|
|
372
|
-
diameter: 2,
|
|
373
|
-
segments: Math.max(16, Math.round(params.segments)),
|
|
374
|
-
slice: 0.5,
|
|
375
|
-
updatable: false
|
|
376
|
-
},
|
|
377
|
-
scene
|
|
378
|
-
);
|
|
379
|
-
haloFeather.parent = shield;
|
|
380
|
-
haloFeather.isPickable = false;
|
|
381
|
-
haloFeather.alwaysSelectAsActiveMesh = true;
|
|
382
|
-
haloFeather.renderingGroupId = shield.renderingGroupId;
|
|
383
|
-
haloFeather.alphaIndex = shield.alphaIndex + 2;
|
|
384
|
-
haloFeather.scaling.setAll(getHaloFeatherScale(params));
|
|
385
|
-
haloFeatherMaterial = createShieldMaterial(scene, {
|
|
386
|
-
name: "vfx_energyShield_halo_feather_material",
|
|
387
|
-
alphaMode: Constants.ALPHA_ADD
|
|
388
|
-
});
|
|
389
|
-
haloFeather.material = haloFeatherMaterial;
|
|
390
|
-
}
|
|
391
339
|
};
|
|
392
340
|
ensureGlowLayer();
|
|
393
341
|
ensureHalo();
|
|
394
|
-
applyParams(material, shield,
|
|
342
|
+
applyParams(material, shield, backMaterial, backShield, halo, haloMaterial, params);
|
|
395
343
|
let elapsed = 0;
|
|
396
344
|
const observer = scene.onBeforeRenderObservable.add(() => {
|
|
397
345
|
elapsed += Math.min(scene.getEngine().getDeltaTime() / 1e3, 0.05);
|
|
398
346
|
material.setFloat("uTime", elapsed);
|
|
347
|
+
backMaterial.setFloat("uTime", elapsed);
|
|
399
348
|
haloMaterial?.setFloat("uTime", elapsed);
|
|
400
|
-
haloFeatherMaterial?.setFloat("uTime", elapsed);
|
|
401
349
|
});
|
|
402
350
|
let disposed = false;
|
|
403
351
|
const dispose = () => {
|
|
@@ -406,6 +354,8 @@ function createEnergyShield(scene, options = {}) {
|
|
|
406
354
|
scene.onBeforeRenderObservable.remove(observer);
|
|
407
355
|
disposeGlowLayer();
|
|
408
356
|
disposeHalo();
|
|
357
|
+
backShield.dispose(false, false);
|
|
358
|
+
backMaterial.dispose();
|
|
409
359
|
shield.dispose(false, false);
|
|
410
360
|
material.dispose();
|
|
411
361
|
if (disposeRoot) root.dispose();
|
|
@@ -414,6 +364,8 @@ function createEnergyShield(scene, options = {}) {
|
|
|
414
364
|
root,
|
|
415
365
|
shield,
|
|
416
366
|
material,
|
|
367
|
+
backShield,
|
|
368
|
+
backMaterial,
|
|
417
369
|
get glowLayer() {
|
|
418
370
|
return glowLayer;
|
|
419
371
|
},
|
|
@@ -421,7 +373,7 @@ function createEnergyShield(scene, options = {}) {
|
|
|
421
373
|
params = mergeParams(partial, params);
|
|
422
374
|
ensureGlowLayer();
|
|
423
375
|
ensureHalo();
|
|
424
|
-
applyParams(material, shield,
|
|
376
|
+
applyParams(material, shield, backMaterial, backShield, halo, haloMaterial, params);
|
|
425
377
|
},
|
|
426
378
|
dispose
|
|
427
379
|
};
|
|
@@ -438,11 +390,17 @@ function createShieldMaterial(scene, options = {}) {
|
|
|
438
390
|
"worldViewProjection",
|
|
439
391
|
"cameraPosition",
|
|
440
392
|
"uTime",
|
|
441
|
-
"
|
|
393
|
+
"uTopColor",
|
|
394
|
+
"uBaseColor",
|
|
442
395
|
"uOpacity",
|
|
443
396
|
"uFresnelPower",
|
|
444
|
-
"
|
|
397
|
+
"uRimStrength",
|
|
445
398
|
"uRimIntensity",
|
|
399
|
+
"uHorizonStrength",
|
|
400
|
+
"uHorizonHeight",
|
|
401
|
+
"uSurfaceVariation",
|
|
402
|
+
"uSurfaceTextureEnabled",
|
|
403
|
+
"uSurfaceFlowEnabled",
|
|
446
404
|
"uSurfaceIntensity",
|
|
447
405
|
"uNoiseScale",
|
|
448
406
|
"uNoiseEdgeWidth",
|
|
@@ -452,49 +410,69 @@ function createShieldMaterial(scene, options = {}) {
|
|
|
452
410
|
"uFlowSpeed",
|
|
453
411
|
"uFlowIntensity",
|
|
454
412
|
"uMarbleContrast",
|
|
455
|
-
"
|
|
456
|
-
"uHaloMode"
|
|
413
|
+
"uAlphaScale"
|
|
457
414
|
],
|
|
458
415
|
needAlphaBlending: true
|
|
459
416
|
}
|
|
460
417
|
);
|
|
461
418
|
material.alphaMode = options.alphaMode ?? Constants.ALPHA_COMBINE;
|
|
462
|
-
material.backFaceCulling =
|
|
419
|
+
material.backFaceCulling = true;
|
|
420
|
+
material.cullBackFaces = options.face !== "back";
|
|
463
421
|
material.disableDepthWrite = true;
|
|
464
422
|
material.fogEnabled = false;
|
|
465
423
|
return material;
|
|
466
424
|
}
|
|
467
|
-
function applyParams(material, shield,
|
|
425
|
+
function applyParams(material, shield, backMaterial, backShield, halo, haloMaterial, params) {
|
|
468
426
|
shield.scaling.set(params.radius, params.radius * params.verticalScale, params.radius);
|
|
469
|
-
|
|
470
|
-
|
|
427
|
+
backShield.scaling.copyFrom(shield.scaling);
|
|
428
|
+
applyMaterialParams(material, params, {
|
|
429
|
+
opacity: params.opacity,
|
|
430
|
+
rimStrength: params.fresnelStrength,
|
|
431
|
+
horizonStrength: params.baseGlowStrength,
|
|
432
|
+
horizonHeight: params.baseGlowHeight,
|
|
433
|
+
alphaScale: 1
|
|
434
|
+
});
|
|
435
|
+
applyMaterialParams(backMaterial, params, {
|
|
436
|
+
opacity: 0,
|
|
437
|
+
rimStrength: params.backRimStrength,
|
|
438
|
+
horizonStrength: params.backGlowStrength,
|
|
439
|
+
horizonHeight: params.backGlowHeight,
|
|
440
|
+
alphaScale: 1
|
|
441
|
+
});
|
|
442
|
+
const haloAlphaScale = Math.min(
|
|
443
|
+
HALO_ALPHA_SCALE_MAX,
|
|
444
|
+
Math.max(
|
|
445
|
+
params.opacity * Math.min(1, params.bloomIntensity),
|
|
446
|
+
Math.min(1, params.fresnelStrength) * 0.2
|
|
447
|
+
)
|
|
448
|
+
);
|
|
471
449
|
if (halo && haloMaterial) {
|
|
472
450
|
halo.scaling.setAll(Math.max(1, params.haloScale));
|
|
473
451
|
applyMaterialParams(
|
|
474
452
|
haloMaterial,
|
|
475
453
|
params,
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
applyMaterialParams(
|
|
484
|
-
haloFeatherMaterial,
|
|
485
|
-
params,
|
|
486
|
-
1,
|
|
487
|
-
haloAlphaScale * HALO_FEATHER_ALPHA_RATIO,
|
|
488
|
-
2
|
|
454
|
+
{
|
|
455
|
+
opacity: 0,
|
|
456
|
+
rimStrength: params.fresnelStrength,
|
|
457
|
+
horizonStrength: 0,
|
|
458
|
+
horizonHeight: params.baseGlowHeight,
|
|
459
|
+
alphaScale: haloAlphaScale
|
|
460
|
+
}
|
|
489
461
|
);
|
|
490
462
|
}
|
|
491
463
|
}
|
|
492
|
-
function applyMaterialParams(material, params,
|
|
493
|
-
material.setColor3("
|
|
494
|
-
material.
|
|
464
|
+
function applyMaterialParams(material, params, settings) {
|
|
465
|
+
material.setColor3("uTopColor", toColor3(params.color));
|
|
466
|
+
material.setColor3("uBaseColor", toColor3(params.baseColor));
|
|
467
|
+
material.setFloat("uOpacity", settings.opacity);
|
|
495
468
|
material.setFloat("uFresnelPower", params.fresnelPower);
|
|
496
|
-
material.setFloat("
|
|
469
|
+
material.setFloat("uRimStrength", settings.rimStrength);
|
|
497
470
|
material.setFloat("uRimIntensity", params.rimIntensity);
|
|
471
|
+
material.setFloat("uHorizonStrength", settings.horizonStrength);
|
|
472
|
+
material.setFloat("uHorizonHeight", settings.horizonHeight);
|
|
473
|
+
material.setFloat("uSurfaceVariation", params.surfaceVariation);
|
|
474
|
+
material.setFloat("uSurfaceTextureEnabled", params.showSurfaceTexture ? 1 : 0);
|
|
475
|
+
material.setFloat("uSurfaceFlowEnabled", params.showSurfaceFlow ? 1 : 0);
|
|
498
476
|
material.setFloat("uSurfaceIntensity", params.surfaceIntensity);
|
|
499
477
|
material.setFloat("uNoiseScale", params.noiseScale);
|
|
500
478
|
material.setFloat("uNoiseEdgeWidth", params.noiseEdgeWidth);
|
|
@@ -504,21 +482,18 @@ function applyMaterialParams(material, params, opacity, haloAlphaScale, haloMode
|
|
|
504
482
|
material.setFloat("uFlowSpeed", params.flowSpeed);
|
|
505
483
|
material.setFloat("uFlowIntensity", params.flowIntensity);
|
|
506
484
|
material.setFloat("uMarbleContrast", params.marbleContrast);
|
|
507
|
-
material.setFloat("
|
|
508
|
-
material.setFloat("uHaloMode", haloMode);
|
|
485
|
+
material.setFloat("uAlphaScale", settings.alphaScale);
|
|
509
486
|
}
|
|
510
487
|
function mergeParams(patch, base = DEFAULT_PARAMS) {
|
|
511
488
|
return {
|
|
512
489
|
...base,
|
|
513
490
|
...patch,
|
|
514
|
-
color: patch?.color ? { ...patch.color } : { ...base.color }
|
|
491
|
+
color: patch?.color ? { ...patch.color } : { ...base.color },
|
|
492
|
+
baseColor: patch?.baseColor ? { ...patch.baseColor } : { ...base.baseColor }
|
|
515
493
|
};
|
|
516
494
|
}
|
|
517
495
|
function toColor3(color) {
|
|
518
|
-
return new Color3(color.r, color.g, color.b);
|
|
519
|
-
}
|
|
520
|
-
function getHaloFeatherScale(params) {
|
|
521
|
-
return Math.max(1, params.haloScale + HALO_FEATHER_SCALE_OFFSET);
|
|
496
|
+
return new Color3(color.r, color.g, color.b).toLinearSpace();
|
|
522
497
|
}
|
|
523
498
|
function registerShaders() {
|
|
524
499
|
Effect.ShadersStore[`${SHADER_NAME}VertexShader`] = VERTEX_SHADER;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fps-games/vfx",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.19",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Shared VFX library for Playable projects: engine-injected effect packages + runtime. Project-pure (no imports of host project code).",
|
|
6
6
|
"publishConfig": {
|
|
@@ -3,29 +3,42 @@
|
|
|
3
3
|
"effectId": "energy-shield",
|
|
4
4
|
"params": {
|
|
5
5
|
"radius": 3.18,
|
|
6
|
-
"verticalScale": 1
|
|
6
|
+
"verticalScale": 1,
|
|
7
7
|
"color": {
|
|
8
|
-
"r": 0.
|
|
9
|
-
"g": 0.
|
|
10
|
-
"b":
|
|
8
|
+
"r": 0.28627451,
|
|
9
|
+
"g": 0.50980392,
|
|
10
|
+
"b": 1
|
|
11
11
|
},
|
|
12
|
-
"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
12
|
+
"baseColor": {
|
|
13
|
+
"r": 0.28627451,
|
|
14
|
+
"g": 0.50980392,
|
|
15
|
+
"b": 1
|
|
16
|
+
},
|
|
17
|
+
"opacity": 0.02,
|
|
18
|
+
"fresnelPower": 2,
|
|
19
|
+
"fresnelStrength": 1,
|
|
20
|
+
"rimIntensity": 1,
|
|
21
|
+
"baseGlowStrength": 0.32,
|
|
22
|
+
"baseGlowHeight": 0.46,
|
|
23
|
+
"surfaceVariation": 0,
|
|
24
|
+
"backRimStrength": 1,
|
|
25
|
+
"backGlowStrength": 0.36,
|
|
26
|
+
"backGlowHeight": 0.49,
|
|
27
|
+
"showSurfaceTexture": false,
|
|
28
|
+
"showSurfaceFlow": false,
|
|
29
|
+
"surfaceIntensity": 0.04,
|
|
30
|
+
"noiseScale": 0.9,
|
|
31
|
+
"noiseEdgeWidth": 0.08,
|
|
32
|
+
"noiseEdgeIntensity": 0.62,
|
|
33
|
+
"noiseEdgeSmoothness": 0.3,
|
|
34
|
+
"flowScale": 2.15,
|
|
35
|
+
"flowSpeed": 0.18,
|
|
36
|
+
"flowIntensity": 0.2,
|
|
37
|
+
"marbleContrast": 1,
|
|
38
|
+
"bloomIntensity": 0.4,
|
|
26
39
|
"bloomKernelSize": 36,
|
|
27
|
-
"showGlowLayer":
|
|
28
|
-
"haloScale": 1.
|
|
40
|
+
"showGlowLayer": false,
|
|
41
|
+
"haloScale": 1.006,
|
|
29
42
|
"showHalo": false,
|
|
30
43
|
"segments": 64
|
|
31
44
|
}
|