@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.
@@ -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, { root, position, renderingGroupId, params });
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, { root, position, renderingGroupId, params, serviceOwnedRoot: true });
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.16",
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": {
@@ -23,6 +23,8 @@
23
23
  "flowIntensity": 1.15,
24
24
  "marbleContrast": 0.67,
25
25
  "bloomIntensity": 0.45,
26
+ "bloomKernelSize": 36,
27
+ "showGlowLayer": true,
26
28
  "haloScale": 1.018,
27
29
  "showHalo": false,
28
30
  "segments": 64