@fps-games/vfx 0.3.16 → 0.3.17
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/dist/EffectPackageService.d.ts +3 -1
- package/dist/SceneVfxService.d.ts +2 -1
- package/dist/effects/energy-shield/index.d.ts +5 -0
- package/dist/effects/energy-shield/index.js +62 -2
- 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 +2 -0
|
@@ -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';
|
|
@@ -23,6 +24,8 @@ export interface EnergyShieldParams extends VfxParamValues {
|
|
|
23
24
|
flowIntensity: number;
|
|
24
25
|
marbleContrast: number;
|
|
25
26
|
bloomIntensity: number;
|
|
27
|
+
bloomKernelSize: number;
|
|
28
|
+
showGlowLayer: boolean;
|
|
26
29
|
haloScale: number;
|
|
27
30
|
showHalo: boolean;
|
|
28
31
|
segments: number;
|
|
@@ -33,11 +36,13 @@ export interface CreateEnergyShieldOptions {
|
|
|
33
36
|
position?: Vector3;
|
|
34
37
|
params?: Partial<EnergyShieldParams>;
|
|
35
38
|
renderingGroupId?: number;
|
|
39
|
+
glowLayer?: GlowLayer | null;
|
|
36
40
|
disposeRoot?: boolean;
|
|
37
41
|
}
|
|
38
42
|
export interface EnergyShieldHandle extends VfxEffectHandle {
|
|
39
43
|
shield: Mesh;
|
|
40
44
|
material: ShaderMaterial;
|
|
45
|
+
glowLayer: GlowLayer | null;
|
|
41
46
|
update(params: Partial<EnergyShieldParams>): void;
|
|
42
47
|
}
|
|
43
48
|
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";
|
|
@@ -28,6 +29,8 @@ const DEFAULT_PARAMS = {
|
|
|
28
29
|
flowIntensity: 1.15,
|
|
29
30
|
marbleContrast: 0.67,
|
|
30
31
|
bloomIntensity: 0.45,
|
|
32
|
+
bloomKernelSize: 36,
|
|
33
|
+
showGlowLayer: true,
|
|
31
34
|
haloScale: 1.018,
|
|
32
35
|
showHalo: false,
|
|
33
36
|
segments: 64
|
|
@@ -234,11 +237,19 @@ const energyShieldEffectPackage = {
|
|
|
234
237
|
{ key: "flowIntensity", label: "流动强度", kind: "number", min: 0, max: 8, step: 0.01 },
|
|
235
238
|
{ key: "marbleContrast", label: "纹路锐度", kind: "number", min: 0.25, max: 4, step: 0.01 },
|
|
236
239
|
{ key: "bloomIntensity", label: "Bloom 强度", kind: "number", min: 0, max: 4, step: 0.01 },
|
|
240
|
+
{ key: "bloomKernelSize", label: "GlowLayer 半径", kind: "number", min: 8, max: 128, step: 1 },
|
|
241
|
+
{ key: "showGlowLayer", label: "显示 GlowLayer", kind: "boolean" },
|
|
237
242
|
{ key: "haloScale", label: "外层光晕缩放", kind: "scale", min: 1, max: 1.08, step: 1e-3 },
|
|
238
243
|
{ key: "showHalo", label: "显示外层光晕", kind: "boolean" }
|
|
239
244
|
],
|
|
240
|
-
create({ scene, root, position, renderingGroupId, params }) {
|
|
241
|
-
return createEnergyShield(scene, {
|
|
245
|
+
create({ scene, root, position, renderingGroupId, params, runtime }) {
|
|
246
|
+
return createEnergyShield(scene, {
|
|
247
|
+
root,
|
|
248
|
+
position,
|
|
249
|
+
renderingGroupId,
|
|
250
|
+
params,
|
|
251
|
+
glowLayer: runtime?.glowLayer ?? runtime?.getGlowLayer?.() ?? null
|
|
252
|
+
});
|
|
242
253
|
}
|
|
243
254
|
};
|
|
244
255
|
function createEnergyShield(scene, options = {}) {
|
|
@@ -269,6 +280,10 @@ function createEnergyShield(scene, options = {}) {
|
|
|
269
280
|
shield.alphaIndex = 20;
|
|
270
281
|
const material = createShieldMaterial(scene);
|
|
271
282
|
shield.material = material;
|
|
283
|
+
const sharedGlowLayer = options.glowLayer ?? null;
|
|
284
|
+
let glowLayer = null;
|
|
285
|
+
let ownsGlowLayer = false;
|
|
286
|
+
let glowMeshIncluded = false;
|
|
272
287
|
let halo = null;
|
|
273
288
|
let haloMaterial = null;
|
|
274
289
|
let haloFeather = null;
|
|
@@ -283,6 +298,45 @@ function createEnergyShield(scene, options = {}) {
|
|
|
283
298
|
haloFeather = null;
|
|
284
299
|
haloFeatherMaterial = null;
|
|
285
300
|
};
|
|
301
|
+
const addGlowMesh = () => {
|
|
302
|
+
if (!glowLayer || glowMeshIncluded) return;
|
|
303
|
+
glowLayer.addIncludedOnlyMesh(shield);
|
|
304
|
+
glowLayer.referenceMeshToUseItsOwnMaterial(shield);
|
|
305
|
+
glowMeshIncluded = true;
|
|
306
|
+
};
|
|
307
|
+
const removeGlowMesh = () => {
|
|
308
|
+
if (!glowLayer || !glowMeshIncluded) return;
|
|
309
|
+
glowLayer.removeIncludedOnlyMesh(shield);
|
|
310
|
+
glowMeshIncluded = false;
|
|
311
|
+
};
|
|
312
|
+
const disposeGlowLayer = () => {
|
|
313
|
+
removeGlowMesh();
|
|
314
|
+
if (ownsGlowLayer) glowLayer?.dispose();
|
|
315
|
+
glowLayer = null;
|
|
316
|
+
ownsGlowLayer = false;
|
|
317
|
+
};
|
|
318
|
+
const ensureGlowLayer = () => {
|
|
319
|
+
if (!params.showGlowLayer || params.bloomIntensity <= 1e-3) {
|
|
320
|
+
disposeGlowLayer();
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
if (!glowLayer) {
|
|
324
|
+
if (sharedGlowLayer) {
|
|
325
|
+
glowLayer = sharedGlowLayer;
|
|
326
|
+
} else {
|
|
327
|
+
glowLayer = new GlowLayer(`vfx_energyShield_glow_${shield.uniqueId}`, scene, {
|
|
328
|
+
blurKernelSize: params.bloomKernelSize,
|
|
329
|
+
mainTextureRatio: 0.35
|
|
330
|
+
});
|
|
331
|
+
ownsGlowLayer = true;
|
|
332
|
+
}
|
|
333
|
+
addGlowMesh();
|
|
334
|
+
}
|
|
335
|
+
if (ownsGlowLayer) {
|
|
336
|
+
glowLayer.intensity = params.bloomIntensity;
|
|
337
|
+
glowLayer.blurKernelSize = params.bloomKernelSize;
|
|
338
|
+
}
|
|
339
|
+
};
|
|
286
340
|
const ensureHalo = () => {
|
|
287
341
|
if (!params.showHalo || params.bloomIntensity <= 1e-3) {
|
|
288
342
|
disposeHalo();
|
|
@@ -335,6 +389,7 @@ function createEnergyShield(scene, options = {}) {
|
|
|
335
389
|
haloFeather.material = haloFeatherMaterial;
|
|
336
390
|
}
|
|
337
391
|
};
|
|
392
|
+
ensureGlowLayer();
|
|
338
393
|
ensureHalo();
|
|
339
394
|
applyParams(material, shield, halo, haloMaterial, haloFeather, haloFeatherMaterial, params);
|
|
340
395
|
let elapsed = 0;
|
|
@@ -349,6 +404,7 @@ function createEnergyShield(scene, options = {}) {
|
|
|
349
404
|
if (disposed) return;
|
|
350
405
|
disposed = true;
|
|
351
406
|
scene.onBeforeRenderObservable.remove(observer);
|
|
407
|
+
disposeGlowLayer();
|
|
352
408
|
disposeHalo();
|
|
353
409
|
shield.dispose(false, false);
|
|
354
410
|
material.dispose();
|
|
@@ -358,8 +414,12 @@ function createEnergyShield(scene, options = {}) {
|
|
|
358
414
|
root,
|
|
359
415
|
shield,
|
|
360
416
|
material,
|
|
417
|
+
get glowLayer() {
|
|
418
|
+
return glowLayer;
|
|
419
|
+
},
|
|
361
420
|
update(partial) {
|
|
362
421
|
params = mergeParams(partial, params);
|
|
422
|
+
ensureGlowLayer();
|
|
363
423
|
ensureHalo();
|
|
364
424
|
applyParams(material, shield, halo, haloMaterial, haloFeather, haloFeatherMaterial, params);
|
|
365
425
|
},
|
|
@@ -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.17",
|
|
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": {
|