@fps-games/vfx 0.3.16 → 0.3.18
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 +10 -0
- package/dist/EffectPackageService.d.ts +3 -1
- package/dist/SceneVfxService.d.ts +2 -1
- package/dist/effects/energy-shield/index.d.ts +15 -0
- package/dist/effects/energy-shield/index.js +242 -213
- package/dist/effects/treasure-attention/index.js +9 -2
- package/dist/index.js +5 -2
- package/dist/types.d.ts +8 -0
- package/package.json +1 -1
- package/packages/effects/energy-shield/vfx-params.json +33 -19
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
|
### 改动
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
|
|
2
2
|
import { Scene } from '@babylonjs/core/scene';
|
|
3
3
|
import { VfxRegistry } from './registry';
|
|
4
|
-
import { VfxDebugAnchor, VfxEffectHandle, VfxEffectPackage, VfxParamValues, VfxSpawnTransform } from './types';
|
|
4
|
+
import { VfxDebugAnchor, VfxEffectHandle, VfxEffectPackage, VfxParamValues, VfxRuntimeResources, VfxSpawnTransform } from './types';
|
|
5
5
|
export interface EffectPackageServiceOptions {
|
|
6
6
|
/** 注入的注册表(由项目侧 glob + buildRegistry 构建);库不直接引用项目注册表 */
|
|
7
7
|
registry: VfxRegistry;
|
|
8
8
|
getDebugAnchorPosition?: (anchor: VfxDebugAnchor) => Vector3 | null;
|
|
9
|
+
runtime?: VfxRuntimeResources;
|
|
9
10
|
}
|
|
10
11
|
export declare class EffectPackageService {
|
|
11
12
|
private readonly scene;
|
|
12
13
|
private readonly registry;
|
|
13
14
|
private readonly getDebugAnchorPosition?;
|
|
15
|
+
private readonly runtime?;
|
|
14
16
|
private readonly activeHandles;
|
|
15
17
|
private readonly savedParams;
|
|
16
18
|
constructor(scene: Scene, options: EffectPackageServiceOptions);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Scene } from '@babylonjs/core/scene';
|
|
2
2
|
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
|
|
3
3
|
import { VfxRegistry } from './registry';
|
|
4
|
-
import { VfxDebugAnchor, VfxEffectHandle, VfxEffectPackage, VfxParamValues, VfxSpawnTransform } from './types';
|
|
4
|
+
import { VfxDebugAnchor, VfxEffectHandle, VfxEffectPackage, VfxParamValues, VfxRuntimeResources, VfxSpawnTransform } from './types';
|
|
5
5
|
import { EffectPackageService } from './EffectPackageService';
|
|
6
6
|
export interface SceneVfxWarmupEntry {
|
|
7
7
|
effectId: string;
|
|
@@ -12,6 +12,7 @@ export interface SceneVfxServiceOptions {
|
|
|
12
12
|
/** 注入的注册表(项目侧 glob + buildRegistry 构建) */
|
|
13
13
|
registry: VfxRegistry;
|
|
14
14
|
getDebugAnchorPosition?: (anchor: VfxDebugAnchor) => Vector3 | null;
|
|
15
|
+
runtime?: VfxRuntimeResources;
|
|
15
16
|
}
|
|
16
17
|
export declare class SceneVfxService {
|
|
17
18
|
private effectPackageService;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GlowLayer } from '@babylonjs/core/Layers/glowLayer';
|
|
1
2
|
import { ShaderMaterial } from '@babylonjs/core/Materials/shaderMaterial';
|
|
2
3
|
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
|
|
3
4
|
import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh';
|
|
@@ -9,10 +10,18 @@ export interface EnergyShieldParams extends VfxParamValues {
|
|
|
9
10
|
radius: number;
|
|
10
11
|
verticalScale: number;
|
|
11
12
|
color: VfxColorValue;
|
|
13
|
+
baseColor: VfxColorValue;
|
|
12
14
|
opacity: number;
|
|
13
15
|
fresnelPower: number;
|
|
14
16
|
fresnelStrength: number;
|
|
15
17
|
rimIntensity: number;
|
|
18
|
+
baseGlowStrength: number;
|
|
19
|
+
baseGlowHeight: number;
|
|
20
|
+
surfaceVariation: number;
|
|
21
|
+
backRimStrength: number;
|
|
22
|
+
backGlowStrength: number;
|
|
23
|
+
backGlowHeight: number;
|
|
24
|
+
showSurfaceFlow: boolean;
|
|
16
25
|
surfaceIntensity: number;
|
|
17
26
|
noiseScale: number;
|
|
18
27
|
noiseEdgeWidth: number;
|
|
@@ -23,6 +32,8 @@ export interface EnergyShieldParams extends VfxParamValues {
|
|
|
23
32
|
flowIntensity: number;
|
|
24
33
|
marbleContrast: number;
|
|
25
34
|
bloomIntensity: number;
|
|
35
|
+
bloomKernelSize: number;
|
|
36
|
+
showGlowLayer: boolean;
|
|
26
37
|
haloScale: number;
|
|
27
38
|
showHalo: boolean;
|
|
28
39
|
segments: number;
|
|
@@ -33,11 +44,15 @@ export interface CreateEnergyShieldOptions {
|
|
|
33
44
|
position?: Vector3;
|
|
34
45
|
params?: Partial<EnergyShieldParams>;
|
|
35
46
|
renderingGroupId?: number;
|
|
47
|
+
glowLayer?: GlowLayer | null;
|
|
36
48
|
disposeRoot?: boolean;
|
|
37
49
|
}
|
|
38
50
|
export interface EnergyShieldHandle extends VfxEffectHandle {
|
|
39
51
|
shield: Mesh;
|
|
40
52
|
material: ShaderMaterial;
|
|
53
|
+
backShield: Mesh;
|
|
54
|
+
backMaterial: ShaderMaterial;
|
|
55
|
+
glowLayer: GlowLayer | null;
|
|
41
56
|
update(params: Partial<EnergyShieldParams>): void;
|
|
42
57
|
}
|
|
43
58
|
export declare const energyShieldEffectPackage: VfxEffectPackage<EnergyShieldParams>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Constants } from "@babylonjs/core/Engines/constants";
|
|
2
|
+
import { GlowLayer } from "@babylonjs/core/Layers/glowLayer";
|
|
2
3
|
import { Effect } from "@babylonjs/core/Materials/effect";
|
|
3
4
|
import { ShaderMaterial } from "@babylonjs/core/Materials/shaderMaterial";
|
|
4
5
|
import { Color3 } from "@babylonjs/core/Maths/math.color";
|
|
@@ -8,27 +9,36 @@ import { TransformNode } from "@babylonjs/core/Meshes/transformNode";
|
|
|
8
9
|
import { V as VFX_RENDERING_GROUP_ID } from "../../chunks/rendering-CV3nhygX.js";
|
|
9
10
|
const SHADER_NAME = "vfxEnergyShield";
|
|
10
11
|
const HALO_ALPHA_SCALE_MAX = 0.3;
|
|
11
|
-
const
|
|
12
|
-
const HALO_FEATHER_SCALE_OFFSET = 0.018;
|
|
12
|
+
const SHIELD_SLICE = 0.5;
|
|
13
13
|
const DEFAULT_PARAMS = {
|
|
14
14
|
radius: 3.18,
|
|
15
|
-
verticalScale: 1
|
|
16
|
-
color: { r: 0.
|
|
17
|
-
|
|
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
|
+
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,
|
|
39
|
+
bloomKernelSize: 36,
|
|
40
|
+
showGlowLayer: false,
|
|
41
|
+
haloScale: 1.006,
|
|
32
42
|
showHalo: false,
|
|
33
43
|
segments: 64
|
|
34
44
|
};
|
|
@@ -58,11 +68,16 @@ precision highp float;
|
|
|
58
68
|
|
|
59
69
|
uniform float uTime;
|
|
60
70
|
uniform vec3 cameraPosition;
|
|
61
|
-
uniform vec3
|
|
71
|
+
uniform vec3 uTopColor;
|
|
72
|
+
uniform vec3 uBaseColor;
|
|
62
73
|
uniform float uOpacity;
|
|
63
74
|
uniform float uFresnelPower;
|
|
64
|
-
uniform float
|
|
75
|
+
uniform float uRimStrength;
|
|
65
76
|
uniform float uRimIntensity;
|
|
77
|
+
uniform float uHorizonStrength;
|
|
78
|
+
uniform float uHorizonHeight;
|
|
79
|
+
uniform float uSurfaceVariation;
|
|
80
|
+
uniform float uSurfaceFlowEnabled;
|
|
66
81
|
uniform float uSurfaceIntensity;
|
|
67
82
|
uniform float uNoiseScale;
|
|
68
83
|
uniform float uNoiseEdgeWidth;
|
|
@@ -72,137 +87,68 @@ uniform float uFlowScale;
|
|
|
72
87
|
uniform float uFlowSpeed;
|
|
73
88
|
uniform float uFlowIntensity;
|
|
74
89
|
uniform float uMarbleContrast;
|
|
75
|
-
uniform float
|
|
76
|
-
uniform float uHaloMode;
|
|
90
|
+
uniform float uAlphaScale;
|
|
77
91
|
|
|
78
92
|
varying vec3 vObjPos;
|
|
79
93
|
varying vec3 vWorldPos;
|
|
80
94
|
varying vec3 vNormalW;
|
|
81
95
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
float saturate(float v) { return clamp(v, 0.0, 1.0); }
|
|
88
|
-
|
|
89
|
-
float snoise(vec3 v) {
|
|
90
|
-
const vec2 C = vec2(1.0 / 6.0, 1.0 / 3.0);
|
|
91
|
-
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
|
|
92
|
-
vec3 i = floor(v + dot(v, C.yyy));
|
|
93
|
-
vec3 x0 = v - i + dot(i, C.xxx);
|
|
94
|
-
vec3 g = step(x0.yzx, x0.xyz);
|
|
95
|
-
vec3 l = 1.0 - g;
|
|
96
|
-
vec3 i1 = min(g.xyz, l.zxy);
|
|
97
|
-
vec3 i2 = max(g.xyz, l.zxy);
|
|
98
|
-
vec3 x1 = x0 - i1 + C.xxx;
|
|
99
|
-
vec3 x2 = x0 - i2 + C.yyy;
|
|
100
|
-
vec3 x3 = x0 - D.yyy;
|
|
101
|
-
i = mod289v3(i);
|
|
102
|
-
vec4 p = permute(permute(permute(
|
|
103
|
-
i.z + vec4(0.0, i1.z, i2.z, 1.0))
|
|
104
|
-
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
|
|
105
|
-
+ i.x + vec4(0.0, i1.x, i2.x, 1.0));
|
|
106
|
-
float n_ = 0.142857142857;
|
|
107
|
-
vec3 ns = n_ * D.wyz - D.xzx;
|
|
108
|
-
vec4 j = p - 49.0 * floor(p * ns.z * ns.z);
|
|
109
|
-
vec4 x_ = floor(j * ns.z);
|
|
110
|
-
vec4 y_ = floor(j - 7.0 * x_);
|
|
111
|
-
vec4 x = x_ * ns.x + ns.yyyy;
|
|
112
|
-
vec4 y = y_ * ns.x + ns.yyyy;
|
|
113
|
-
vec4 h = 1.0 - abs(x) - abs(y);
|
|
114
|
-
vec4 b0 = vec4(x.xy, y.xy);
|
|
115
|
-
vec4 b1 = vec4(x.zw, y.zw);
|
|
116
|
-
vec4 s0 = floor(b0) * 2.0 + 1.0;
|
|
117
|
-
vec4 s1 = floor(b1) * 2.0 + 1.0;
|
|
118
|
-
vec4 sh = -step(h, vec4(0.0));
|
|
119
|
-
vec4 a0 = b0.xzyw + s0.xzyw * sh.xxyy;
|
|
120
|
-
vec4 a1 = b1.xzyw + s1.xzyw * sh.zzww;
|
|
121
|
-
vec3 p0 = vec3(a0.xy, h.x);
|
|
122
|
-
vec3 p1 = vec3(a0.zw, h.y);
|
|
123
|
-
vec3 p2 = vec3(a1.xy, h.z);
|
|
124
|
-
vec3 p3 = vec3(a1.zw, h.w);
|
|
125
|
-
vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
|
|
126
|
-
p0 *= norm.x;
|
|
127
|
-
p1 *= norm.y;
|
|
128
|
-
p2 *= norm.z;
|
|
129
|
-
p3 *= norm.w;
|
|
130
|
-
vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);
|
|
131
|
-
m = m * m;
|
|
132
|
-
return 42.0 * dot(m * m, vec4(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));
|
|
96
|
+
float hash(vec3 position) {
|
|
97
|
+
position = fract(position * 0.3183099 + 0.1);
|
|
98
|
+
position *= 17.0;
|
|
99
|
+
return fract(position.x * position.y * position.z * (position.x + position.y + position.z));
|
|
133
100
|
}
|
|
134
101
|
|
|
135
|
-
float
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
102
|
+
float valueNoise(vec3 position) {
|
|
103
|
+
vec3 cell = floor(position);
|
|
104
|
+
vec3 local = fract(position);
|
|
105
|
+
local = local * local * (3.0 - 2.0 * local);
|
|
106
|
+
|
|
107
|
+
return mix(
|
|
108
|
+
mix(
|
|
109
|
+
mix(hash(cell), hash(cell + vec3(1.0, 0.0, 0.0)), local.x),
|
|
110
|
+
mix(hash(cell + vec3(0.0, 1.0, 0.0)), hash(cell + vec3(1.0, 1.0, 0.0)), local.x),
|
|
111
|
+
local.y
|
|
112
|
+
),
|
|
113
|
+
mix(
|
|
114
|
+
mix(hash(cell + vec3(0.0, 0.0, 1.0)), hash(cell + vec3(1.0, 0.0, 1.0)), local.x),
|
|
115
|
+
mix(hash(cell + vec3(0.0, 1.0, 1.0)), hash(cell + vec3(1.0, 1.0, 1.0)), local.x),
|
|
116
|
+
local.y
|
|
117
|
+
),
|
|
118
|
+
local.z
|
|
119
|
+
);
|
|
146
120
|
}
|
|
147
121
|
|
|
148
122
|
void main(void) {
|
|
149
|
-
vec3 normalW = normalize(vNormalW);
|
|
150
123
|
vec3 viewDir = normalize(cameraPosition - vWorldPos);
|
|
151
|
-
float
|
|
152
|
-
float
|
|
153
|
-
float
|
|
154
|
-
|
|
155
|
-
float t = uTime * uFlowSpeed;
|
|
156
|
-
vec3 spherePos = normalize(vObjPos + vec3(0.0001)) * max(0.05, uNoiseScale);
|
|
157
|
-
vec3 flowA = spherePos * uFlowScale + vec3(t, t * 0.62, t * 0.38);
|
|
158
|
-
vec3 flowB = spherePos * (uFlowScale * 1.91) + vec3(-t * 0.46, t * 0.82, -t * 0.27);
|
|
159
|
-
float n1 = fbm(flowA);
|
|
160
|
-
float n2 = fbm(flowB);
|
|
161
|
-
float cloud = saturate((n1 * 0.58 + n2 * 0.42) * 0.5 + 0.5);
|
|
162
|
-
|
|
163
|
-
float veinInput = spherePos.y * 0.92 + n1 * 1.65 + n2 * 0.74 + t * 0.13;
|
|
164
|
-
float ribbon = abs(sin(veinInput * 3.14159265));
|
|
165
|
-
float marble = pow(1.0 - ribbon, max(0.25, uMarbleContrast));
|
|
166
|
-
float nebula = saturate(mix(cloud, marble, 0.58) * uFlowIntensity * 0.34);
|
|
124
|
+
float facing = abs(dot(normalize(vNormalW), viewDir));
|
|
125
|
+
float rim = pow(1.0 - facing, max(0.05, uFresnelPower));
|
|
126
|
+
float horizon = pow(1.0 - clamp(vObjPos.y / max(0.001, uHorizonHeight), 0.0, 1.0), 2.5);
|
|
127
|
+
float heightFactor = smoothstep(0.0, 0.92, vObjPos.y);
|
|
167
128
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
vec3 deepBlue = uColor * (0.12 + 0.42 * cloud);
|
|
173
|
-
vec3 marbleBlue = uColor * (0.34 + 0.9 * marble) * uSurfaceIntensity;
|
|
174
|
-
vec3 rimBlue = uColor * fresnel * uRimIntensity;
|
|
175
|
-
vec3 edgeBlue = uColor * noiseEdge * uNoiseEdgeIntensity;
|
|
176
|
-
vec3 color = min((deepBlue + marbleBlue + rimBlue + edgeBlue) * 0.72, vec3(1.12));
|
|
177
|
-
|
|
178
|
-
float alpha = uOpacity * (0.16 + 0.34 * cloud + 0.24 * marble);
|
|
179
|
-
alpha += fresnel * uOpacity * 0.58;
|
|
180
|
-
alpha += noiseEdge * uNoiseEdgeIntensity * 0.05;
|
|
181
|
-
|
|
182
|
-
if (uHaloMode > 1.5) {
|
|
183
|
-
float haloRim = pow(viewRim, max(0.28, uFresnelPower * 0.44));
|
|
184
|
-
float featherIn = smoothstep(0.1, 0.46, haloRim);
|
|
185
|
-
float featherOut = 1.0 - smoothstep(0.72, 1.0, haloRim);
|
|
186
|
-
float featherRim = featherIn * featherOut;
|
|
187
|
-
float outerFade = 1.0 - smoothstep(0.88, 1.0, haloRim);
|
|
188
|
-
color = uColor * (0.2 + featherRim * 0.24 + cloud * 0.04);
|
|
189
|
-
alpha = featherRim * 0.58 * outerFade;
|
|
190
|
-
} else if (uHaloMode > 0.5) {
|
|
191
|
-
float haloRim = pow(viewRim, max(0.3, uFresnelPower * 0.48));
|
|
192
|
-
float bodyIn = smoothstep(0.34, 0.68, haloRim);
|
|
193
|
-
float bodyOut = 1.0 - smoothstep(0.72, 1.0, haloRim);
|
|
194
|
-
float bodyRim = bodyIn * bodyOut;
|
|
195
|
-
float featherIn = smoothstep(0.12, 0.44, haloRim);
|
|
196
|
-
float featherOut = 1.0 - smoothstep(0.48, 1.0, haloRim);
|
|
197
|
-
float featherRim = featherIn * featherOut;
|
|
198
|
-
float outerFade = 1.0 - smoothstep(0.86, 1.0, haloRim);
|
|
199
|
-
color = uColor * (0.24 + bodyRim * 0.34 + featherRim * 0.12 + cloud * 0.05);
|
|
200
|
-
alpha = (bodyRim * 0.5 + featherRim * 0.14 + noiseEdge * 0.01) * outerFade;
|
|
129
|
+
vec3 motion = vec3(0.0);
|
|
130
|
+
if (uSurfaceFlowEnabled > 0.5) {
|
|
131
|
+
motion = vec3(uTime * uFlowSpeed, -uTime * uFlowSpeed * 0.62, uTime * uFlowSpeed * 0.38);
|
|
201
132
|
}
|
|
133
|
+
float cloud = valueNoise(vObjPos * max(0.05, uNoiseScale)) * 0.65;
|
|
134
|
+
cloud += valueNoise(vObjPos * max(0.05, uFlowScale) + motion) * 0.35;
|
|
135
|
+
float shapedCloud = pow(clamp(cloud, 0.0, 1.0), max(0.25, uMarbleContrast));
|
|
136
|
+
float variation = mix(1.0 - uSurfaceVariation, 1.0 + uSurfaceVariation, shapedCloud);
|
|
137
|
+
float cloudShade = mix(0.92, 1.08, shapedCloud);
|
|
138
|
+
rim *= cloudShade;
|
|
202
139
|
|
|
203
|
-
|
|
140
|
+
float edgeWidth = max(0.005, uNoiseEdgeWidth);
|
|
141
|
+
float edgeSoftness = max(0.005, uNoiseEdgeSmoothness * 0.2);
|
|
142
|
+
float flowBand = 1.0 - smoothstep(edgeWidth, edgeWidth + edgeSoftness, abs(shapedCloud - 0.5));
|
|
143
|
+
float flowGlow = flowBand * uFlowIntensity * uNoiseEdgeIntensity * uSurfaceFlowEnabled;
|
|
204
144
|
|
|
205
|
-
|
|
145
|
+
float alpha = uOpacity * variation + rim * uRimStrength + horizon * uHorizonStrength * variation;
|
|
146
|
+
alpha += flowGlow * uOpacity * 0.5;
|
|
147
|
+
vec3 gradientColor = mix(uBaseColor, uTopColor, heightFactor);
|
|
148
|
+
vec3 color = gradientColor * (0.25 + rim * 1.3 + horizon * 0.85) * cloudShade * uRimIntensity;
|
|
149
|
+
color += gradientColor * flowGlow * uSurfaceIntensity;
|
|
150
|
+
|
|
151
|
+
gl_FragColor = vec4(color, clamp(alpha * uAlphaScale, 0.0, 0.88));
|
|
206
152
|
}
|
|
207
153
|
`;
|
|
208
154
|
const energyShieldEffectPackage = {
|
|
@@ -219,11 +165,19 @@ const energyShieldEffectPackage = {
|
|
|
219
165
|
debugParams: [
|
|
220
166
|
{ key: "radius", label: "玻璃罩半径", kind: "scale", min: 0.4, max: 10, step: 0.01 },
|
|
221
167
|
{ key: "verticalScale", label: "纵向缩放", kind: "scale", min: 0.5, max: 1.8, step: 0.01 },
|
|
222
|
-
{ key: "color", label: "
|
|
223
|
-
{ key: "
|
|
224
|
-
{ key: "
|
|
225
|
-
{ key: "
|
|
168
|
+
{ key: "color", label: "顶部颜色", kind: "color" },
|
|
169
|
+
{ key: "baseColor", label: "底部颜色", kind: "color" },
|
|
170
|
+
{ key: "opacity", label: "球壳透明度", kind: "opacity", min: 0, max: 1, step: 0.01 },
|
|
171
|
+
{ key: "fresnelPower", label: "轮廓衰减", kind: "number", min: 0.2, max: 8, step: 0.01 },
|
|
172
|
+
{ key: "fresnelStrength", label: "正面轮廓强度", kind: "number", min: 0, max: 2.5, step: 0.01 },
|
|
226
173
|
{ key: "rimIntensity", label: "轮廓亮度", kind: "number", min: 0, max: 4, step: 0.01 },
|
|
174
|
+
{ key: "baseGlowStrength", label: "正面底部辉光", kind: "number", min: 0, max: 1, step: 0.01 },
|
|
175
|
+
{ key: "baseGlowHeight", label: "正面辉光高度", kind: "number", min: 0.04, max: 1, step: 0.01 },
|
|
176
|
+
{ key: "surfaceVariation", label: "表面明暗变化", kind: "number", min: 0, max: 0.6, step: 0.01 },
|
|
177
|
+
{ key: "backRimStrength", label: "背面轮廓强度", kind: "number", min: 0, max: 1.5, step: 0.01 },
|
|
178
|
+
{ key: "backGlowStrength", label: "背面底部辉光", kind: "number", min: 0, max: 1, step: 0.01 },
|
|
179
|
+
{ key: "backGlowHeight", label: "背面辉光高度", kind: "number", min: 0.04, max: 1, step: 0.01 },
|
|
180
|
+
{ key: "showSurfaceFlow", label: "显示表面流动", kind: "boolean" },
|
|
227
181
|
{ key: "surfaceIntensity", label: "表面亮度", kind: "number", min: 0, max: 3, step: 0.01 },
|
|
228
182
|
{ key: "noiseScale", label: "噪声缩放", kind: "number", min: 0.2, max: 5, step: 0.01 },
|
|
229
183
|
{ key: "noiseEdgeWidth", label: "噪声亮边宽度", kind: "number", min: 0.01, max: 0.5, step: 0.01 },
|
|
@@ -234,11 +188,19 @@ const energyShieldEffectPackage = {
|
|
|
234
188
|
{ key: "flowIntensity", label: "流动强度", kind: "number", min: 0, max: 8, step: 0.01 },
|
|
235
189
|
{ key: "marbleContrast", label: "纹路锐度", kind: "number", min: 0.25, max: 4, step: 0.01 },
|
|
236
190
|
{ key: "bloomIntensity", label: "Bloom 强度", kind: "number", min: 0, max: 4, step: 0.01 },
|
|
237
|
-
{ key: "
|
|
238
|
-
{ key: "
|
|
191
|
+
{ key: "bloomKernelSize", label: "Bloom/Glow 半径", kind: "number", min: 8, max: 128, step: 1 },
|
|
192
|
+
{ key: "showGlowLayer", label: "显示 Bloom/Glow", kind: "boolean" },
|
|
193
|
+
{ key: "haloScale", label: "Halo 缩放", kind: "scale", min: 1, max: 1.08, step: 1e-3 },
|
|
194
|
+
{ key: "showHalo", label: "显示额外 Halo", kind: "boolean" }
|
|
239
195
|
],
|
|
240
|
-
create({ scene, root, position, renderingGroupId, params }) {
|
|
241
|
-
return createEnergyShield(scene, {
|
|
196
|
+
create({ scene, root, position, renderingGroupId, params, runtime }) {
|
|
197
|
+
return createEnergyShield(scene, {
|
|
198
|
+
root,
|
|
199
|
+
position,
|
|
200
|
+
renderingGroupId,
|
|
201
|
+
params,
|
|
202
|
+
glowLayer: runtime?.glowLayer ?? runtime?.getGlowLayer?.() ?? null
|
|
203
|
+
});
|
|
242
204
|
}
|
|
243
205
|
};
|
|
244
206
|
function createEnergyShield(scene, options = {}) {
|
|
@@ -257,7 +219,7 @@ function createEnergyShield(scene, options = {}) {
|
|
|
257
219
|
{
|
|
258
220
|
diameter: 2,
|
|
259
221
|
segments: Math.max(16, Math.round(params.segments)),
|
|
260
|
-
slice:
|
|
222
|
+
slice: SHIELD_SLICE,
|
|
261
223
|
updatable: false
|
|
262
224
|
},
|
|
263
225
|
scene
|
|
@@ -267,21 +229,79 @@ function createEnergyShield(scene, options = {}) {
|
|
|
267
229
|
shield.alwaysSelectAsActiveMesh = true;
|
|
268
230
|
shield.renderingGroupId = options.renderingGroupId ?? VFX_RENDERING_GROUP_ID;
|
|
269
231
|
shield.alphaIndex = 20;
|
|
270
|
-
const material = createShieldMaterial(scene);
|
|
232
|
+
const material = createShieldMaterial(scene, { face: "front" });
|
|
271
233
|
shield.material = material;
|
|
234
|
+
const backShield = MeshBuilder.CreateSphere(
|
|
235
|
+
"vfx_energyShield_back_hemisphere",
|
|
236
|
+
{
|
|
237
|
+
diameter: 2,
|
|
238
|
+
segments: Math.max(16, Math.round(params.segments)),
|
|
239
|
+
slice: SHIELD_SLICE,
|
|
240
|
+
updatable: false
|
|
241
|
+
},
|
|
242
|
+
scene
|
|
243
|
+
);
|
|
244
|
+
backShield.parent = root;
|
|
245
|
+
backShield.isPickable = false;
|
|
246
|
+
backShield.alwaysSelectAsActiveMesh = true;
|
|
247
|
+
backShield.renderingGroupId = shield.renderingGroupId;
|
|
248
|
+
backShield.alphaIndex = shield.alphaIndex - 1;
|
|
249
|
+
const backMaterial = createShieldMaterial(scene, {
|
|
250
|
+
name: "vfx_energyShield_back_material",
|
|
251
|
+
alphaMode: Constants.ALPHA_ADD,
|
|
252
|
+
face: "back"
|
|
253
|
+
});
|
|
254
|
+
backShield.material = backMaterial;
|
|
255
|
+
const sharedGlowLayer = options.glowLayer ?? null;
|
|
256
|
+
let glowLayer = null;
|
|
257
|
+
let ownsGlowLayer = false;
|
|
258
|
+
let glowMeshIncluded = false;
|
|
272
259
|
let halo = null;
|
|
273
260
|
let haloMaterial = null;
|
|
274
|
-
let haloFeather = null;
|
|
275
|
-
let haloFeatherMaterial = null;
|
|
276
261
|
const disposeHalo = () => {
|
|
277
262
|
halo?.dispose(false, false);
|
|
278
263
|
haloMaterial?.dispose();
|
|
279
|
-
haloFeather?.dispose(false, false);
|
|
280
|
-
haloFeatherMaterial?.dispose();
|
|
281
264
|
halo = null;
|
|
282
265
|
haloMaterial = null;
|
|
283
|
-
|
|
284
|
-
|
|
266
|
+
};
|
|
267
|
+
const addGlowMesh = () => {
|
|
268
|
+
if (!glowLayer || glowMeshIncluded) return;
|
|
269
|
+
glowLayer.addIncludedOnlyMesh(shield);
|
|
270
|
+
glowLayer.referenceMeshToUseItsOwnMaterial(shield);
|
|
271
|
+
glowMeshIncluded = true;
|
|
272
|
+
};
|
|
273
|
+
const removeGlowMesh = () => {
|
|
274
|
+
if (!glowLayer || !glowMeshIncluded) return;
|
|
275
|
+
glowLayer.removeIncludedOnlyMesh(shield);
|
|
276
|
+
glowMeshIncluded = false;
|
|
277
|
+
};
|
|
278
|
+
const disposeGlowLayer = () => {
|
|
279
|
+
removeGlowMesh();
|
|
280
|
+
if (ownsGlowLayer) glowLayer?.dispose();
|
|
281
|
+
glowLayer = null;
|
|
282
|
+
ownsGlowLayer = false;
|
|
283
|
+
};
|
|
284
|
+
const ensureGlowLayer = () => {
|
|
285
|
+
if (!params.showGlowLayer || params.bloomIntensity <= 1e-3) {
|
|
286
|
+
disposeGlowLayer();
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (!glowLayer) {
|
|
290
|
+
if (sharedGlowLayer) {
|
|
291
|
+
glowLayer = sharedGlowLayer;
|
|
292
|
+
} else {
|
|
293
|
+
glowLayer = new GlowLayer(`vfx_energyShield_glow_${shield.uniqueId}`, scene, {
|
|
294
|
+
blurKernelSize: params.bloomKernelSize,
|
|
295
|
+
mainTextureRatio: 0.35
|
|
296
|
+
});
|
|
297
|
+
ownsGlowLayer = true;
|
|
298
|
+
}
|
|
299
|
+
addGlowMesh();
|
|
300
|
+
}
|
|
301
|
+
if (ownsGlowLayer) {
|
|
302
|
+
glowLayer.intensity = params.bloomIntensity;
|
|
303
|
+
glowLayer.blurKernelSize = params.bloomKernelSize;
|
|
304
|
+
}
|
|
285
305
|
};
|
|
286
306
|
const ensureHalo = () => {
|
|
287
307
|
if (!params.showHalo || params.bloomIntensity <= 1e-3) {
|
|
@@ -294,7 +314,7 @@ function createEnergyShield(scene, options = {}) {
|
|
|
294
314
|
{
|
|
295
315
|
diameter: 2,
|
|
296
316
|
segments: Math.max(16, Math.round(params.segments)),
|
|
297
|
-
slice:
|
|
317
|
+
slice: SHIELD_SLICE,
|
|
298
318
|
updatable: false
|
|
299
319
|
},
|
|
300
320
|
scene
|
|
@@ -307,49 +327,31 @@ function createEnergyShield(scene, options = {}) {
|
|
|
307
327
|
halo.scaling.setAll(Math.max(1, params.haloScale));
|
|
308
328
|
haloMaterial = createShieldMaterial(scene, {
|
|
309
329
|
name: "vfx_energyShield_halo_material",
|
|
310
|
-
alphaMode: Constants.ALPHA_ADD
|
|
330
|
+
alphaMode: Constants.ALPHA_ADD,
|
|
331
|
+
face: "front"
|
|
311
332
|
});
|
|
312
333
|
halo.material = haloMaterial;
|
|
313
334
|
}
|
|
314
|
-
if (!haloFeather || !haloFeatherMaterial) {
|
|
315
|
-
haloFeather = MeshBuilder.CreateSphere(
|
|
316
|
-
"vfx_energyShield_halo_feather",
|
|
317
|
-
{
|
|
318
|
-
diameter: 2,
|
|
319
|
-
segments: Math.max(16, Math.round(params.segments)),
|
|
320
|
-
slice: 0.5,
|
|
321
|
-
updatable: false
|
|
322
|
-
},
|
|
323
|
-
scene
|
|
324
|
-
);
|
|
325
|
-
haloFeather.parent = shield;
|
|
326
|
-
haloFeather.isPickable = false;
|
|
327
|
-
haloFeather.alwaysSelectAsActiveMesh = true;
|
|
328
|
-
haloFeather.renderingGroupId = shield.renderingGroupId;
|
|
329
|
-
haloFeather.alphaIndex = shield.alphaIndex + 2;
|
|
330
|
-
haloFeather.scaling.setAll(getHaloFeatherScale(params));
|
|
331
|
-
haloFeatherMaterial = createShieldMaterial(scene, {
|
|
332
|
-
name: "vfx_energyShield_halo_feather_material",
|
|
333
|
-
alphaMode: Constants.ALPHA_ADD
|
|
334
|
-
});
|
|
335
|
-
haloFeather.material = haloFeatherMaterial;
|
|
336
|
-
}
|
|
337
335
|
};
|
|
336
|
+
ensureGlowLayer();
|
|
338
337
|
ensureHalo();
|
|
339
|
-
applyParams(material, shield,
|
|
338
|
+
applyParams(material, shield, backMaterial, backShield, halo, haloMaterial, params);
|
|
340
339
|
let elapsed = 0;
|
|
341
340
|
const observer = scene.onBeforeRenderObservable.add(() => {
|
|
342
341
|
elapsed += Math.min(scene.getEngine().getDeltaTime() / 1e3, 0.05);
|
|
343
342
|
material.setFloat("uTime", elapsed);
|
|
343
|
+
backMaterial.setFloat("uTime", elapsed);
|
|
344
344
|
haloMaterial?.setFloat("uTime", elapsed);
|
|
345
|
-
haloFeatherMaterial?.setFloat("uTime", elapsed);
|
|
346
345
|
});
|
|
347
346
|
let disposed = false;
|
|
348
347
|
const dispose = () => {
|
|
349
348
|
if (disposed) return;
|
|
350
349
|
disposed = true;
|
|
351
350
|
scene.onBeforeRenderObservable.remove(observer);
|
|
351
|
+
disposeGlowLayer();
|
|
352
352
|
disposeHalo();
|
|
353
|
+
backShield.dispose(false, false);
|
|
354
|
+
backMaterial.dispose();
|
|
353
355
|
shield.dispose(false, false);
|
|
354
356
|
material.dispose();
|
|
355
357
|
if (disposeRoot) root.dispose();
|
|
@@ -358,10 +360,16 @@ function createEnergyShield(scene, options = {}) {
|
|
|
358
360
|
root,
|
|
359
361
|
shield,
|
|
360
362
|
material,
|
|
363
|
+
backShield,
|
|
364
|
+
backMaterial,
|
|
365
|
+
get glowLayer() {
|
|
366
|
+
return glowLayer;
|
|
367
|
+
},
|
|
361
368
|
update(partial) {
|
|
362
369
|
params = mergeParams(partial, params);
|
|
370
|
+
ensureGlowLayer();
|
|
363
371
|
ensureHalo();
|
|
364
|
-
applyParams(material, shield,
|
|
372
|
+
applyParams(material, shield, backMaterial, backShield, halo, haloMaterial, params);
|
|
365
373
|
},
|
|
366
374
|
dispose
|
|
367
375
|
};
|
|
@@ -378,11 +386,16 @@ function createShieldMaterial(scene, options = {}) {
|
|
|
378
386
|
"worldViewProjection",
|
|
379
387
|
"cameraPosition",
|
|
380
388
|
"uTime",
|
|
381
|
-
"
|
|
389
|
+
"uTopColor",
|
|
390
|
+
"uBaseColor",
|
|
382
391
|
"uOpacity",
|
|
383
392
|
"uFresnelPower",
|
|
384
|
-
"
|
|
393
|
+
"uRimStrength",
|
|
385
394
|
"uRimIntensity",
|
|
395
|
+
"uHorizonStrength",
|
|
396
|
+
"uHorizonHeight",
|
|
397
|
+
"uSurfaceVariation",
|
|
398
|
+
"uSurfaceFlowEnabled",
|
|
386
399
|
"uSurfaceIntensity",
|
|
387
400
|
"uNoiseScale",
|
|
388
401
|
"uNoiseEdgeWidth",
|
|
@@ -392,49 +405,68 @@ function createShieldMaterial(scene, options = {}) {
|
|
|
392
405
|
"uFlowSpeed",
|
|
393
406
|
"uFlowIntensity",
|
|
394
407
|
"uMarbleContrast",
|
|
395
|
-
"
|
|
396
|
-
"uHaloMode"
|
|
408
|
+
"uAlphaScale"
|
|
397
409
|
],
|
|
398
410
|
needAlphaBlending: true
|
|
399
411
|
}
|
|
400
412
|
);
|
|
401
413
|
material.alphaMode = options.alphaMode ?? Constants.ALPHA_COMBINE;
|
|
402
|
-
material.backFaceCulling =
|
|
414
|
+
material.backFaceCulling = true;
|
|
415
|
+
material.cullBackFaces = options.face !== "back";
|
|
403
416
|
material.disableDepthWrite = true;
|
|
404
417
|
material.fogEnabled = false;
|
|
405
418
|
return material;
|
|
406
419
|
}
|
|
407
|
-
function applyParams(material, shield,
|
|
420
|
+
function applyParams(material, shield, backMaterial, backShield, halo, haloMaterial, params) {
|
|
408
421
|
shield.scaling.set(params.radius, params.radius * params.verticalScale, params.radius);
|
|
409
|
-
|
|
410
|
-
|
|
422
|
+
backShield.scaling.copyFrom(shield.scaling);
|
|
423
|
+
applyMaterialParams(material, params, {
|
|
424
|
+
opacity: params.opacity,
|
|
425
|
+
rimStrength: params.fresnelStrength,
|
|
426
|
+
horizonStrength: params.baseGlowStrength,
|
|
427
|
+
horizonHeight: params.baseGlowHeight,
|
|
428
|
+
alphaScale: 1
|
|
429
|
+
});
|
|
430
|
+
applyMaterialParams(backMaterial, params, {
|
|
431
|
+
opacity: 0,
|
|
432
|
+
rimStrength: params.backRimStrength,
|
|
433
|
+
horizonStrength: params.backGlowStrength,
|
|
434
|
+
horizonHeight: params.backGlowHeight,
|
|
435
|
+
alphaScale: 1
|
|
436
|
+
});
|
|
437
|
+
const haloAlphaScale = Math.min(
|
|
438
|
+
HALO_ALPHA_SCALE_MAX,
|
|
439
|
+
Math.max(
|
|
440
|
+
params.opacity * Math.min(1, params.bloomIntensity),
|
|
441
|
+
Math.min(1, params.fresnelStrength) * 0.2
|
|
442
|
+
)
|
|
443
|
+
);
|
|
411
444
|
if (halo && haloMaterial) {
|
|
412
445
|
halo.scaling.setAll(Math.max(1, params.haloScale));
|
|
413
446
|
applyMaterialParams(
|
|
414
447
|
haloMaterial,
|
|
415
448
|
params,
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
applyMaterialParams(
|
|
424
|
-
haloFeatherMaterial,
|
|
425
|
-
params,
|
|
426
|
-
1,
|
|
427
|
-
haloAlphaScale * HALO_FEATHER_ALPHA_RATIO,
|
|
428
|
-
2
|
|
449
|
+
{
|
|
450
|
+
opacity: 0,
|
|
451
|
+
rimStrength: params.fresnelStrength,
|
|
452
|
+
horizonStrength: 0,
|
|
453
|
+
horizonHeight: params.baseGlowHeight,
|
|
454
|
+
alphaScale: haloAlphaScale
|
|
455
|
+
}
|
|
429
456
|
);
|
|
430
457
|
}
|
|
431
458
|
}
|
|
432
|
-
function applyMaterialParams(material, params,
|
|
433
|
-
material.setColor3("
|
|
434
|
-
material.
|
|
459
|
+
function applyMaterialParams(material, params, settings) {
|
|
460
|
+
material.setColor3("uTopColor", toColor3(params.color));
|
|
461
|
+
material.setColor3("uBaseColor", toColor3(params.baseColor));
|
|
462
|
+
material.setFloat("uOpacity", settings.opacity);
|
|
435
463
|
material.setFloat("uFresnelPower", params.fresnelPower);
|
|
436
|
-
material.setFloat("
|
|
464
|
+
material.setFloat("uRimStrength", settings.rimStrength);
|
|
437
465
|
material.setFloat("uRimIntensity", params.rimIntensity);
|
|
466
|
+
material.setFloat("uHorizonStrength", settings.horizonStrength);
|
|
467
|
+
material.setFloat("uHorizonHeight", settings.horizonHeight);
|
|
468
|
+
material.setFloat("uSurfaceVariation", params.surfaceVariation);
|
|
469
|
+
material.setFloat("uSurfaceFlowEnabled", params.showSurfaceFlow ? 1 : 0);
|
|
438
470
|
material.setFloat("uSurfaceIntensity", params.surfaceIntensity);
|
|
439
471
|
material.setFloat("uNoiseScale", params.noiseScale);
|
|
440
472
|
material.setFloat("uNoiseEdgeWidth", params.noiseEdgeWidth);
|
|
@@ -444,21 +476,18 @@ function applyMaterialParams(material, params, opacity, haloAlphaScale, haloMode
|
|
|
444
476
|
material.setFloat("uFlowSpeed", params.flowSpeed);
|
|
445
477
|
material.setFloat("uFlowIntensity", params.flowIntensity);
|
|
446
478
|
material.setFloat("uMarbleContrast", params.marbleContrast);
|
|
447
|
-
material.setFloat("
|
|
448
|
-
material.setFloat("uHaloMode", haloMode);
|
|
479
|
+
material.setFloat("uAlphaScale", settings.alphaScale);
|
|
449
480
|
}
|
|
450
481
|
function mergeParams(patch, base = DEFAULT_PARAMS) {
|
|
451
482
|
return {
|
|
452
483
|
...base,
|
|
453
484
|
...patch,
|
|
454
|
-
color: patch?.color ? { ...patch.color } : { ...base.color }
|
|
485
|
+
color: patch?.color ? { ...patch.color } : { ...base.color },
|
|
486
|
+
baseColor: patch?.baseColor ? { ...patch.baseColor } : { ...base.baseColor }
|
|
455
487
|
};
|
|
456
488
|
}
|
|
457
489
|
function toColor3(color) {
|
|
458
|
-
return new Color3(color.r, color.g, color.b);
|
|
459
|
-
}
|
|
460
|
-
function getHaloFeatherScale(params) {
|
|
461
|
-
return Math.max(1, params.haloScale + HALO_FEATHER_SCALE_OFFSET);
|
|
490
|
+
return new Color3(color.r, color.g, color.b).toLinearSpace();
|
|
462
491
|
}
|
|
463
492
|
function registerShaders() {
|
|
464
493
|
Effect.ShadersStore[`${SHADER_NAME}VertexShader`] = VERTEX_SHADER;
|
|
@@ -76,8 +76,15 @@ const treasureAttentionEffectPackage = {
|
|
|
76
76
|
{ key: "bloomKernelSize", label: "Bloom 半径", kind: "number", min: 8, max: 96, step: 1 },
|
|
77
77
|
{ key: "showGlowLayer", label: "显示 GlowLayer", kind: "boolean" }
|
|
78
78
|
],
|
|
79
|
-
create({ scene, root, position, renderingGroupId, params }) {
|
|
80
|
-
return createTreasureAttentionFx(scene, {
|
|
79
|
+
create({ scene, root, position, renderingGroupId, params, runtime }) {
|
|
80
|
+
return createTreasureAttentionFx(scene, {
|
|
81
|
+
root,
|
|
82
|
+
position,
|
|
83
|
+
renderingGroupId,
|
|
84
|
+
params,
|
|
85
|
+
glowLayer: runtime?.glowLayer ?? runtime?.getGlowLayer?.() ?? null,
|
|
86
|
+
serviceOwnedRoot: true
|
|
87
|
+
});
|
|
81
88
|
}
|
|
82
89
|
};
|
|
83
90
|
function createTreasureAttentionFx(scene, options = {}) {
|
package/dist/index.js
CHANGED
|
@@ -75,6 +75,7 @@ class EffectPackageService {
|
|
|
75
75
|
this.scene = scene;
|
|
76
76
|
this.registry = options.registry;
|
|
77
77
|
this.getDebugAnchorPosition = options.getDebugAnchorPosition;
|
|
78
|
+
this.runtime = options.runtime;
|
|
78
79
|
this.savedParams = cloneOverrideMap(options.registry.savedParams);
|
|
79
80
|
}
|
|
80
81
|
getEffectPackages() {
|
|
@@ -127,7 +128,8 @@ class EffectPackageService {
|
|
|
127
128
|
renderingGroupId: spawn.renderingGroupId,
|
|
128
129
|
params: runtimeParams,
|
|
129
130
|
scale: spawn.scale,
|
|
130
|
-
inputs: spawn.inputs
|
|
131
|
+
inputs: spawn.inputs,
|
|
132
|
+
runtime: this.runtime
|
|
131
133
|
});
|
|
132
134
|
applySpawnToRoot(root, spawn, applyRootScale);
|
|
133
135
|
} catch (error) {
|
|
@@ -315,7 +317,8 @@ class SceneVfxService {
|
|
|
315
317
|
constructor(scene, options) {
|
|
316
318
|
this.effectPackageService = new EffectPackageService(scene, {
|
|
317
319
|
registry: options.registry,
|
|
318
|
-
getDebugAnchorPosition: options.getDebugAnchorPosition
|
|
320
|
+
getDebugAnchorPosition: options.getDebugAnchorPosition,
|
|
321
|
+
runtime: options.runtime
|
|
319
322
|
});
|
|
320
323
|
}
|
|
321
324
|
getEffectPackageService() {
|
package/dist/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { Scene } from '@babylonjs/core/scene';
|
|
|
2
2
|
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
|
|
3
3
|
import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
|
|
4
4
|
import { AbstractMesh } from '@babylonjs/core/Meshes/abstractMesh';
|
|
5
|
+
import { GlowLayer } from '@babylonjs/core/Layers/glowLayer';
|
|
5
6
|
export type VfxDebugAnchor = 'playerRight' | 'player';
|
|
6
7
|
export type VfxInput<T> = T | (() => T);
|
|
7
8
|
export type VfxInputKey = 'aim' | 'normal' | 'endpoints' | 'target' | 'reference';
|
|
@@ -24,6 +25,11 @@ export interface VfxResolvedInputs {
|
|
|
24
25
|
reference?: () => Vector3;
|
|
25
26
|
scalars?: Record<string, () => number>;
|
|
26
27
|
}
|
|
28
|
+
/** 运行时共享资源:不可序列化,由项目/游戏层注入,与可保存 params 分开。 */
|
|
29
|
+
export interface VfxRuntimeResources {
|
|
30
|
+
glowLayer?: GlowLayer | null;
|
|
31
|
+
getGlowLayer?: () => GlowLayer | null;
|
|
32
|
+
}
|
|
27
33
|
export type VfxParamValue = number | string | boolean | VfxColorValue;
|
|
28
34
|
export type VfxParamValues = Record<string, VfxParamValue>;
|
|
29
35
|
export interface VfxColorValue {
|
|
@@ -74,6 +80,8 @@ export interface VfxEffectPackageContext<PParams extends VfxParamValues = VfxPar
|
|
|
74
80
|
scale: Vector3;
|
|
75
81
|
/** 运行时外部信息(已归一化为访问器)。link/target/定向武器/活改标量等按 required/optionalInputs 读取。 */
|
|
76
82
|
inputs?: VfxResolvedInputs;
|
|
83
|
+
/** 运行时共享资源(如 scene 级共享 GlowLayer)。 */
|
|
84
|
+
runtime?: VfxRuntimeResources;
|
|
77
85
|
}
|
|
78
86
|
export interface VfxEffectHandle {
|
|
79
87
|
root: TransformNode;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fps-games/vfx",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.18",
|
|
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,27 +3,41 @@
|
|
|
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
|
-
"
|
|
26
|
-
"
|
|
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
|
+
"showSurfaceFlow": false,
|
|
28
|
+
"surfaceIntensity": 0.04,
|
|
29
|
+
"noiseScale": 0.9,
|
|
30
|
+
"noiseEdgeWidth": 0.08,
|
|
31
|
+
"noiseEdgeIntensity": 0.62,
|
|
32
|
+
"noiseEdgeSmoothness": 0.3,
|
|
33
|
+
"flowScale": 2.15,
|
|
34
|
+
"flowSpeed": 0.18,
|
|
35
|
+
"flowIntensity": 0.2,
|
|
36
|
+
"marbleContrast": 1,
|
|
37
|
+
"bloomIntensity": 0.4,
|
|
38
|
+
"bloomKernelSize": 36,
|
|
39
|
+
"showGlowLayer": false,
|
|
40
|
+
"haloScale": 1.006,
|
|
27
41
|
"showHalo": false,
|
|
28
42
|
"segments": 64
|
|
29
43
|
}
|