babylon.quarks 0.26.0 → 0.28.0

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.
Files changed (83) hide show
  1. package/CHANGELOG.md +1194 -8
  2. package/README.md +13 -9
  3. package/dist/babylon.quarks.cjs +1 -1
  4. package/dist/babylon.quarks.cjs.map +1 -1
  5. package/dist/babylon.quarks.esm.js +1 -1
  6. package/dist/babylon.quarks.esm.js.map +1 -1
  7. package/dist/babylon.quarks.umd.min.js +1 -1
  8. package/dist/babylon.quarks.umd.min.js.map +1 -1
  9. package/dist/types/index.d.cts +10108 -0
  10. package/dist/types/index.d.ts +5794 -998
  11. package/package.json +18 -7
  12. package/src/BatchedRenderer.ts +274 -156
  13. package/src/EffectPool.ts +94 -12
  14. package/src/MeshSurfaceEmitter.ts +50 -14
  15. package/src/ParticleEmitter.ts +75 -17
  16. package/src/ParticleSystem.ts +981 -2066
  17. package/src/QuarksLoader.ts +666 -194
  18. package/src/QuarksPrefab.ts +367 -73
  19. package/src/QuarksSerializer.ts +512 -0
  20. package/src/QuarksUtil.ts +77 -7
  21. package/src/SpriteBatch.ts +127 -252
  22. package/src/TrailBatch.ts +545 -348
  23. package/src/VFXBatch.ts +238 -596
  24. package/src/batchKey.ts +239 -0
  25. package/src/batchSettings.ts +546 -0
  26. package/src/effectDocumentJSON.ts +261 -0
  27. package/src/effectResources.ts +76 -0
  28. package/src/envAtlas.ts +126 -18
  29. package/src/geometryUtil.ts +1 -1
  30. package/src/index.ts +69 -35
  31. package/src/nodeId.ts +36 -0
  32. package/src/shaderProgram.ts +419 -0
  33. package/src/shaderVariants.ts +245 -0
  34. package/src/shaders/chunks/blend.ts +31 -0
  35. package/src/shaders/chunks/fog.ts +12 -5
  36. package/src/shaders/chunks/sheet.ts +111 -0
  37. package/src/shaders/chunks/soft.ts +85 -0
  38. package/src/shaders/chunks/surface.ts +12 -2
  39. package/src/shaders/local_particle_physics_vert.glsl.ts +14 -28
  40. package/src/shaders/local_particle_physics_vert.wgsl.ts +16 -29
  41. package/src/shaders/particle_frag.glsl.ts +5 -22
  42. package/src/shaders/particle_frag.wgsl.ts +5 -23
  43. package/src/shaders/particle_physics_frag.glsl.ts +16 -26
  44. package/src/shaders/particle_physics_frag.wgsl.ts +14 -26
  45. package/src/shaders/particle_vert.glsl.ts +5 -27
  46. package/src/shaders/particle_vert.wgsl.ts +5 -26
  47. package/src/shaders/stretched_bb_particle_vert.glsl.ts +7 -33
  48. package/src/shaders/stretched_bb_particle_vert.wgsl.ts +7 -33
  49. package/src/shaders/trail_frag.glsl.ts +13 -0
  50. package/src/shaders/trail_frag.wgsl.ts +13 -0
  51. package/src/shaders/trail_vert.glsl.ts +45 -36
  52. package/src/shaders/trail_vert.wgsl.ts +46 -40
  53. package/src/softDepth.ts +136 -0
  54. package/src/system/BehaviorPlan.ts +85 -0
  55. package/src/system/BoundsTracker.ts +181 -0
  56. package/src/system/EmissionController.ts +358 -0
  57. package/src/system/EventDispatcher.ts +60 -0
  58. package/src/system/ParticleSpawner.ts +274 -0
  59. package/src/system/SimulationClock.ts +130 -0
  60. package/src/system/geometry.ts +104 -0
  61. package/src/system/integrate.ts +428 -0
  62. package/src/system/materialResolve.ts +165 -0
  63. package/src/system/normalize.ts +100 -0
  64. package/src/system/serialization.ts +422 -0
  65. package/src/system/settingsSchema.ts +339 -0
  66. package/src/system/types.ts +449 -0
  67. package/src/textureSource.ts +30 -0
  68. package/src/trailSettings.ts +54 -0
  69. package/src/BatchedParticleRenderer.ts +0 -3
  70. package/src/materials/ParticleMaterials.ts +0 -23
  71. package/src/materials/index.ts +0 -1
  72. package/src/shaders/chunks/index.ts +0 -1
  73. package/src/shaders/chunks/register-shader-chunks.ts +0 -32
  74. package/src/shaders/chunks/soft_fragment.glsl.ts +0 -13
  75. package/src/shaders/chunks/soft_pars_fragment.glsl.ts +0 -20
  76. package/src/shaders/chunks/soft_pars_vertex.glsl.ts +0 -6
  77. package/src/shaders/chunks/soft_vertex.glsl.ts +0 -6
  78. package/src/shaders/chunks/tile_fragment.glsl.ts +0 -9
  79. package/src/shaders/chunks/tile_pars_fragment.glsl.ts +0 -9
  80. package/src/shaders/chunks/tile_pars_vertex.glsl.ts +0 -28
  81. package/src/shaders/chunks/tile_vertex.glsl.ts +0 -18
  82. package/src/shaders/index.ts +0 -9
  83. package/src/shaders/local_particle_vert.glsl.ts +0 -50
package/src/QuarksUtil.ts CHANGED
@@ -1,11 +1,20 @@
1
+ import {InstancedMesh} from '@babylonjs/core/Meshes/instancedMesh';
2
+ import {Mesh} from '@babylonjs/core/Meshes/mesh';
1
3
  import {TransformNode} from '@babylonjs/core/Meshes/transformNode';
2
4
  import {Node} from '@babylonjs/core/node';
3
5
  import {ConstantValue, EmitSubParticleSystem, FunctionValueGenerator, IntervalValue, ValueGenerator} from 'quarks.core';
4
6
  import {BatchedRenderer} from './BatchedRenderer';
7
+ import {shareEffectResources} from './effectResources';
8
+ import {MeshSurfaceEmitter} from './MeshSurfaceEmitter';
5
9
  import {ParticleEmitter} from './ParticleEmitter';
6
10
  import {ParticleSystem} from './ParticleSystem';
7
11
 
12
+ /**
13
+ * Helpers that act on a whole effect: every particle system under a root node, as a loaded effect
14
+ * or a hand-built tree has them.
15
+ */
8
16
  export class QuarksUtil {
17
+ /** Calls `callback` on `root` and every node under it that is a {@link ParticleEmitter}. */
9
18
  static runOnAllParticleEmitters(root: Node, callback: (emitter: ParticleEmitter) => void): void {
10
19
  QuarksUtil.traverseNode(root, (node) => {
11
20
  if (node instanceof ParticleEmitter) {
@@ -14,42 +23,62 @@ export class QuarksUtil {
14
23
  });
15
24
  }
16
25
 
26
+ /** Adds every system under `root` to `batchRenderer`. */
17
27
  static addToBatchRenderer(root: Node, batchRenderer: BatchedRenderer): void {
18
28
  QuarksUtil.runOnAllParticleEmitters(root, (emitter) => {
19
29
  batchRenderer.addSystem(emitter.system);
20
30
  });
21
31
  }
22
32
 
33
+ /**
34
+ * Plays every system under `root`, see {@link ParticleSystem.play}: paused ones resume and
35
+ * finished ones, a short burst inside a longer effect included, start over.
36
+ */
23
37
  static play(root: Node): void {
24
38
  QuarksUtil.runOnAllParticleEmitters(root, (emitter) => {
25
39
  (emitter.system as unknown as ParticleSystem).play();
26
40
  });
27
41
  }
28
42
 
43
+ /**
44
+ * Undoes {@link pause} on every system under `root`, see {@link ParticleSystem.resume}: the
45
+ * finished ones stay finished.
46
+ */
47
+ static resume(root: Node): void {
48
+ QuarksUtil.runOnAllParticleEmitters(root, (emitter) => {
49
+ (emitter.system as unknown as ParticleSystem).resume();
50
+ });
51
+ }
52
+
53
+ /** Clears, rewinds and pauses every system under `root`, see {@link ParticleSystem.stop}. */
29
54
  static stop(root: Node): void {
30
55
  QuarksUtil.runOnAllParticleEmitters(root, (emitter) => {
31
56
  (emitter.system as unknown as ParticleSystem).stop();
32
57
  });
33
58
  }
34
59
 
60
+ /** Pauses every system under `root`, see {@link ParticleSystem.pause}. */
35
61
  static pause(root: Node): void {
36
62
  QuarksUtil.runOnAllParticleEmitters(root, (emitter) => {
37
63
  (emitter.system as unknown as ParticleSystem).pause();
38
64
  });
39
65
  }
40
66
 
67
+ /** Restarts every system under `root` from the beginning, see {@link ParticleSystem.restart}. */
41
68
  static restart(root: Node): void {
42
69
  QuarksUtil.runOnAllParticleEmitters(root, (emitter) => {
43
70
  (emitter.system as unknown as ParticleSystem).restart();
44
71
  });
45
72
  }
46
73
 
74
+ /** Sets {@link ParticleSystem.autoDestroy} on every system under `root`. */
47
75
  static setAutoDestroy(root: Node, autoDestroy: boolean): void {
48
76
  QuarksUtil.runOnAllParticleEmitters(root, (emitter) => {
49
77
  (emitter.system as unknown as ParticleSystem).autoDestroy = autoDestroy;
50
78
  });
51
79
  }
52
80
 
81
+ /** Ends emission on every system under `root` and lets the particles die out, see {@link ParticleSystem.endEmit}. */
53
82
  static endEmit(root: Node): void {
54
83
  QuarksUtil.runOnAllParticleEmitters(root, (emitter) => {
55
84
  (emitter.system as unknown as ParticleSystem).endEmit();
@@ -77,16 +106,46 @@ export class QuarksUtil {
77
106
  /**
78
107
  * A deep copy of an effect: the node tree under `root` with every particle
79
108
  * system cloned, sub emitter links pointing at the copies, and the same
80
- * transforms and enabled state. The copy is not added to any renderer.
81
- * Nodes that are neither transform nodes nor emitters are skipped.
109
+ * transforms and enabled state. Meshes are cloned as meshes that share
110
+ * the source's geometry and material, instances of a mesh in the tree as
111
+ * instances of its copy, and a mesh surface shape that emits from a mesh
112
+ * in the tree emits from its copy. An instance of a mesh outside the tree
113
+ * stays an instance of that mesh, and goes when it is disposed. The copy holds the
114
+ * source's textures and materials, so disposing the source leaves the copy
115
+ * whole. It is not added to any renderer. Nodes that are neither transform
116
+ * nodes nor emitters, such as lights and cameras, are skipped.
82
117
  */
83
118
  static instantiate(root: TransformNode, name?: string): TransformNode {
84
119
  const copies = new Map<ParticleEmitter, ParticleEmitter>();
120
+ const meshCopies = new Map<Node, Mesh>();
121
+ const inTree = new Set<Node>([root, ...root.getDescendants(false)]);
122
+ // A mesh is copied when first needed: where it sits in the tree, or earlier, as the source
123
+ // of an instance copied before it. Its children are copied as every node's are.
124
+ const meshCopyOf = (mesh: Mesh): Mesh => {
125
+ let copy = meshCopies.get(mesh);
126
+ if (copy === undefined) {
127
+ copy = mesh.clone(mesh.name, null, true);
128
+ copy.setEnabled(mesh.isEnabled(false));
129
+ meshCopies.set(mesh, copy);
130
+ }
131
+ return copy;
132
+ };
85
133
  const copyNode = (node: Node, parent: TransformNode | null, copyName?: string): TransformNode | null => {
86
134
  let copy: TransformNode;
87
135
  if (node instanceof ParticleEmitter) {
88
136
  copy = node.clone(copyName);
89
137
  copies.set(node, copy as ParticleEmitter);
138
+ } else if (node instanceof Mesh) {
139
+ copy = meshCopyOf(node);
140
+ if (copyName !== undefined) {
141
+ copy.name = copyName;
142
+ }
143
+ } else if (node instanceof InstancedMesh) {
144
+ // An instance of a mesh in the tree becomes an instance of its copy, so the copy
145
+ // does not go when the source effect is disposed (a mesh disposes its instances).
146
+ const source = inTree.has(node.sourceMesh) ? meshCopyOf(node.sourceMesh) : undefined;
147
+ copy = node.clone(copyName ?? node.name, null, true, source)!;
148
+ copy.setEnabled(node.isEnabled(false));
90
149
  } else if (node instanceof TransformNode) {
91
150
  copy = new TransformNode(copyName ?? node.name, node.getScene());
92
151
  copy.position.copyFrom(node.position);
@@ -106,9 +165,12 @@ export class QuarksUtil {
106
165
  return copy;
107
166
  };
108
167
  const copy = copyNode(root, null, name) as TransformNode;
109
- // Sub emitter behaviors on the copies still target the original emitters.
168
+ // The copy draws with the source's textures and materials, so disposeEffect(source) keeps them.
169
+ shareEffectResources(root, copy);
110
170
  for (const emitter of copies.values()) {
111
- for (const behavior of (emitter.system as unknown as ParticleSystem).behaviors) {
171
+ const system = emitter.system as unknown as ParticleSystem;
172
+ // Sub emitter behaviors on the copies still target the original emitters.
173
+ for (const behavior of system.behaviors) {
112
174
  if (behavior instanceof EmitSubParticleSystem) {
113
175
  const target = copies.get(behavior.subParticleSystem as unknown as ParticleEmitter);
114
176
  if (target !== undefined) {
@@ -116,6 +178,14 @@ export class QuarksUtil {
116
178
  }
117
179
  }
118
180
  }
181
+ // So does a mesh surface shape: it emits from the copy of its mesh when the tree has one.
182
+ const shape = system.emitterShape;
183
+ if (shape instanceof MeshSurfaceEmitter && shape.mesh !== undefined) {
184
+ const meshCopy = meshCopies.get(shape.mesh);
185
+ if (meshCopy !== undefined) {
186
+ shape.mesh = meshCopy;
187
+ }
188
+ }
119
189
  }
120
190
  return copy;
121
191
  }
@@ -130,7 +200,8 @@ export class QuarksUtil {
130
200
  * {@link endEmit}, or when one is frozen at playback speed 0.
131
201
  *
132
202
  * Random values count at their maximum, so this is an upper bound; curves
133
- * are sampled. Particles cut short by collisions or culling only make the
203
+ * are sampled. A runtime {@link ParticleSystem.timeDilation} is not counted:
204
+ * this is the effect's own length. Particles cut short by collisions or culling only make the
134
205
  * real effect shorter.
135
206
  */
136
207
  static getDuration(root: Node): number {
@@ -147,8 +218,7 @@ export class QuarksUtil {
147
218
  continue;
148
219
  }
149
220
  const target = (behavior.subParticleSystem as unknown as ParticleEmitter | undefined)?.system as
150
- | ParticleSystem
151
- | undefined;
221
+ ParticleSystem | undefined;
152
222
  if (target !== undefined && typeof target === 'object') {
153
223
  if (!systems.includes(target)) {
154
224
  systems.push(target);