babylon.quarks 0.26.0 → 0.27.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.
- package/CHANGELOG.md +769 -8
- package/README.md +10 -8
- package/dist/babylon.quarks.cjs +1 -1
- package/dist/babylon.quarks.cjs.map +1 -1
- package/dist/babylon.quarks.esm.js +1 -1
- package/dist/babylon.quarks.esm.js.map +1 -1
- package/dist/babylon.quarks.umd.min.js +1 -1
- package/dist/babylon.quarks.umd.min.js.map +1 -1
- package/dist/types/index.d.cts +6683 -0
- package/dist/types/index.d.ts +1959 -588
- package/package.json +12 -6
- package/src/BatchedRenderer.ts +204 -101
- package/src/EffectPool.ts +4 -1
- package/src/MeshSurfaceEmitter.ts +29 -4
- package/src/ParticleEmitter.ts +45 -15
- package/src/ParticleSystem.ts +909 -2061
- package/src/QuarksLoader.ts +421 -67
- package/src/QuarksPrefab.ts +91 -4
- package/src/QuarksSerializer.ts +484 -0
- package/src/QuarksUtil.ts +15 -0
- package/src/SpriteBatch.ts +106 -246
- package/src/TrailBatch.ts +533 -342
- package/src/VFXBatch.ts +236 -136
- package/src/batchKey.ts +237 -0
- package/src/effectResources.ts +79 -0
- package/src/envAtlas.ts +119 -17
- package/src/index.ts +32 -33
- package/src/nodeId.ts +13 -0
- package/src/shaderProgram.ts +325 -0
- package/src/shaderVariants.ts +225 -0
- package/src/shaders/chunks/fog.ts +4 -2
- package/src/shaders/chunks/sheet.ts +111 -0
- package/src/shaders/chunks/soft.ts +84 -0
- package/src/shaders/chunks/surface.ts +10 -0
- package/src/shaders/local_particle_physics_vert.glsl.ts +14 -28
- package/src/shaders/local_particle_physics_vert.wgsl.ts +16 -29
- package/src/shaders/particle_frag.glsl.ts +3 -22
- package/src/shaders/particle_frag.wgsl.ts +3 -23
- package/src/shaders/particle_physics_frag.glsl.ts +12 -25
- package/src/shaders/particle_physics_frag.wgsl.ts +12 -26
- package/src/shaders/particle_vert.glsl.ts +5 -27
- package/src/shaders/particle_vert.wgsl.ts +5 -26
- package/src/shaders/stretched_bb_particle_vert.glsl.ts +7 -33
- package/src/shaders/stretched_bb_particle_vert.wgsl.ts +7 -33
- package/src/shaders/trail_frag.glsl.ts +11 -1
- package/src/shaders/trail_frag.wgsl.ts +11 -0
- package/src/shaders/trail_vert.glsl.ts +45 -36
- package/src/shaders/trail_vert.wgsl.ts +46 -40
- package/src/softDepth.ts +136 -0
- package/src/system/BehaviorPlan.ts +85 -0
- package/src/system/BoundsTracker.ts +181 -0
- package/src/system/EmissionController.ts +360 -0
- package/src/system/EventDispatcher.ts +44 -0
- package/src/system/ParticleSpawner.ts +274 -0
- package/src/system/SimulationClock.ts +130 -0
- package/src/system/geometry.ts +111 -0
- package/src/system/integrate.ts +428 -0
- package/src/system/materialResolve.ts +116 -0
- package/src/system/normalize.ts +95 -0
- package/src/system/serialization.ts +401 -0
- package/src/system/settingsSchema.ts +317 -0
- package/src/system/types.ts +410 -0
- package/src/textureSource.ts +30 -0
- package/src/trailSettings.ts +51 -0
- package/src/BatchedParticleRenderer.ts +0 -3
- package/src/materials/ParticleMaterials.ts +0 -23
- package/src/materials/index.ts +0 -1
- package/src/shaders/chunks/index.ts +0 -1
- package/src/shaders/chunks/register-shader-chunks.ts +0 -32
- package/src/shaders/chunks/soft_fragment.glsl.ts +0 -13
- package/src/shaders/chunks/soft_pars_fragment.glsl.ts +0 -20
- package/src/shaders/chunks/soft_pars_vertex.glsl.ts +0 -6
- package/src/shaders/chunks/soft_vertex.glsl.ts +0 -6
- package/src/shaders/chunks/tile_fragment.glsl.ts +0 -9
- package/src/shaders/chunks/tile_pars_fragment.glsl.ts +0 -9
- package/src/shaders/chunks/tile_pars_vertex.glsl.ts +0 -28
- package/src/shaders/chunks/tile_vertex.glsl.ts +0 -18
- package/src/shaders/index.ts +0 -9
- package/src/shaders/local_particle_vert.glsl.ts +0 -50
package/src/QuarksPrefab.ts
CHANGED
|
@@ -3,21 +3,42 @@ import {Scene} from '@babylonjs/core/scene';
|
|
|
3
3
|
import {IAnimationData, IPrefab} from 'quarks.core';
|
|
4
4
|
import {BatchedRenderer} from './BatchedRenderer';
|
|
5
5
|
import {ParticleEmitter} from './ParticleEmitter';
|
|
6
|
+
import {quarksNodeId} from './nodeId';
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* A clip a {@link QuarksPrefab} timeline can drive, such as a Babylon `AnimationGroup`. Every
|
|
10
|
+
* member is optional; the prefab calls only what is there.
|
|
11
|
+
*/
|
|
7
12
|
export interface QuarksTimelineClip {
|
|
13
|
+
/** Names the clip in a saved prefab, so it can be found again on load. */
|
|
8
14
|
uuid?: string;
|
|
15
|
+
/** Length in seconds, used when the track gives none. */
|
|
9
16
|
duration?: number;
|
|
17
|
+
/** Called when the timeline enters the track. */
|
|
10
18
|
play?: () => void;
|
|
19
|
+
/** Called when the prefab pauses. */
|
|
11
20
|
pause?: () => void;
|
|
21
|
+
/** Called when the timeline leaves the track or the prefab stops. */
|
|
12
22
|
stop?: () => void;
|
|
23
|
+
/** Called while scrubbing with {@link QuarksPrefab.setTime}, with the time into the track in seconds. */
|
|
13
24
|
setTime?: (time: number) => void;
|
|
14
25
|
}
|
|
15
26
|
|
|
27
|
+
/** One track on a {@link QuarksPrefab} timeline. */
|
|
16
28
|
export interface AnimationData extends IAnimationData {
|
|
29
|
+
/**
|
|
30
|
+
* `'ps'` plays a particle system, `'three'` plays a {@link QuarksTimelineClip}. The names are
|
|
31
|
+
* the effect format's, shared with three.quarks, where a `'three'` track plays a three.js
|
|
32
|
+
* `AnimationClip`; here the clip is whatever the host registered on the target node.
|
|
33
|
+
*/
|
|
17
34
|
type: 'three' | 'ps';
|
|
35
|
+
/** The node the track drives: a {@link ParticleEmitter} for `'ps'`, any node for `'three'`. */
|
|
18
36
|
target: TransformNode;
|
|
37
|
+
/** Restart when the track ends instead of letting it finish. */
|
|
19
38
|
loop: boolean;
|
|
39
|
+
/** The clip a `'three'` track plays. */
|
|
20
40
|
clip?: QuarksTimelineClip;
|
|
41
|
+
/** The id of the clip on `target`, written to and read from JSON. */
|
|
21
42
|
clipUUID?: string;
|
|
22
43
|
}
|
|
23
44
|
|
|
@@ -30,12 +51,26 @@ interface AnimationJSON {
|
|
|
30
51
|
loop: boolean;
|
|
31
52
|
}
|
|
32
53
|
|
|
54
|
+
/**
|
|
55
|
+
* A node with a timeline that starts and stops the particle systems and clips under it, like a
|
|
56
|
+
* Unity Timeline or a Niagara System's emitter spawn schedule. Each track starts at `startTime`
|
|
57
|
+
* and lasts `duration` seconds: a particle system restarts when its track begins and stops
|
|
58
|
+
* emitting when it ends, a clip plays and stops.
|
|
59
|
+
*
|
|
60
|
+
* Call {@link QuarksPrefab.update} every frame (or {@link QuarksPrefab.setTime} to scrub).
|
|
61
|
+
*/
|
|
33
62
|
export class QuarksPrefab extends TransformNode implements IPrefab {
|
|
63
|
+
/** Always `'QuarksPrefab'`; written to JSON. */
|
|
34
64
|
type = 'QuarksPrefab';
|
|
65
|
+
/** The tracks, in the order they were added. */
|
|
35
66
|
animationData: Array<AnimationData> = [];
|
|
67
|
+
/** Whether {@link QuarksPrefab.update} advances the timeline. */
|
|
36
68
|
isPlaying = false;
|
|
69
|
+
/** Time on the timeline in seconds; just below 0 before the first update, so a track at 0 starts. */
|
|
37
70
|
currentTime = -0.00001;
|
|
71
|
+
/** Playback speed; 1 is real time. */
|
|
38
72
|
timeScale = 1;
|
|
73
|
+
/** End of the last track in seconds; the prefab stops when it passes it. */
|
|
39
74
|
duration = 0;
|
|
40
75
|
|
|
41
76
|
private _lastUpdateTimeMs = Date.now();
|
|
@@ -46,10 +81,17 @@ export class QuarksPrefab extends TransformNode implements IPrefab {
|
|
|
46
81
|
super(name, scene);
|
|
47
82
|
}
|
|
48
83
|
|
|
84
|
+
/** The renderer that a particle system is added to again when its track starts. */
|
|
49
85
|
registerBatchedRenderer(renderer: BatchedRenderer): void {
|
|
50
86
|
this._batchedRenderer = renderer;
|
|
51
87
|
}
|
|
52
88
|
|
|
89
|
+
/**
|
|
90
|
+
* Adds a track that plays `emitter`'s system, and pauses the prefab.
|
|
91
|
+
* @param startTime - Seconds into the timeline.
|
|
92
|
+
* @param duration - Seconds; 0 or less uses the system's own duration.
|
|
93
|
+
* @param loop - Restart the system when the track ends.
|
|
94
|
+
*/
|
|
53
95
|
addParticleSystemAnimation(emitter: ParticleEmitter, startTime = 0, duration = 0, loop = false): AnimationData {
|
|
54
96
|
const animationDuration = duration > 0 ? duration : emitter.system.duration;
|
|
55
97
|
const data: AnimationData = {
|
|
@@ -65,6 +107,13 @@ export class QuarksPrefab extends TransformNode implements IPrefab {
|
|
|
65
107
|
return data;
|
|
66
108
|
}
|
|
67
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Adds a track that plays `clip` on `target`.
|
|
112
|
+
* @param startTime - Seconds into the timeline.
|
|
113
|
+
* @param duration - Seconds; 0 or less uses the clip's duration.
|
|
114
|
+
* @param loop - Play the clip again when the track ends.
|
|
115
|
+
* @param clipUUID - Saved in JSON to find the clip on load; defaults to `clip.uuid`.
|
|
116
|
+
*/
|
|
68
117
|
addThreeAnimation(
|
|
69
118
|
target: TransformNode,
|
|
70
119
|
clip?: QuarksTimelineClip,
|
|
@@ -88,17 +137,33 @@ export class QuarksPrefab extends TransformNode implements IPrefab {
|
|
|
88
137
|
return data;
|
|
89
138
|
}
|
|
90
139
|
|
|
140
|
+
/** Removes the track at `index` in {@link QuarksPrefab.animationData}. */
|
|
91
141
|
removeAnimation(index: number): void {
|
|
92
142
|
this.animationData.splice(index, 1);
|
|
93
143
|
this.updateDuration();
|
|
94
144
|
}
|
|
95
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Starts or resumes the timeline from {@link QuarksPrefab.currentTime}, resuming the systems and
|
|
148
|
+
* clips of the tracks it is inside, which {@link QuarksPrefab.pause} paused.
|
|
149
|
+
*/
|
|
96
150
|
play(): void {
|
|
97
151
|
if (this.isPlaying) return;
|
|
98
152
|
this.isPlaying = true;
|
|
99
153
|
this._lastUpdateTimeMs = Date.now();
|
|
154
|
+
this.animationData.forEach((animation) => {
|
|
155
|
+
const inside =
|
|
156
|
+
this.currentTime >= animation.startTime && this.currentTime <= animation.startTime + animation.duration;
|
|
157
|
+
if (!inside) return;
|
|
158
|
+
if (animation.type === 'ps' && animation.target instanceof ParticleEmitter) {
|
|
159
|
+
animation.target.system.play();
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
animation.clip?.play?.();
|
|
163
|
+
});
|
|
100
164
|
}
|
|
101
165
|
|
|
166
|
+
/** Pauses the timeline and every system and clip on it. */
|
|
102
167
|
pause(): void {
|
|
103
168
|
if (!this.isPlaying) return;
|
|
104
169
|
this.isPlaying = false;
|
|
@@ -111,6 +176,7 @@ export class QuarksPrefab extends TransformNode implements IPrefab {
|
|
|
111
176
|
});
|
|
112
177
|
}
|
|
113
178
|
|
|
179
|
+
/** Pauses, rewinds to the start, and stops every system and clip on it. */
|
|
114
180
|
stop(): void {
|
|
115
181
|
this.pause();
|
|
116
182
|
this.currentTime = -0.00001;
|
|
@@ -123,6 +189,10 @@ export class QuarksPrefab extends TransformNode implements IPrefab {
|
|
|
123
189
|
});
|
|
124
190
|
}
|
|
125
191
|
|
|
192
|
+
/**
|
|
193
|
+
* Advances the timeline, starting and ending tracks it crosses. Stops past {@link QuarksPrefab.duration}.
|
|
194
|
+
* @param forceDelta - Seconds to advance; by default the wall-clock time since the last update.
|
|
195
|
+
*/
|
|
126
196
|
update(forceDelta?: number): void {
|
|
127
197
|
if (!this.isPlaying) return;
|
|
128
198
|
const now = Date.now();
|
|
@@ -169,6 +239,7 @@ export class QuarksPrefab extends TransformNode implements IPrefab {
|
|
|
169
239
|
});
|
|
170
240
|
}
|
|
171
241
|
|
|
242
|
+
/** Jumps to `time` seconds, starting and ending tracks it crosses and scrubbing clips to it. */
|
|
172
243
|
setTime(time: number): void {
|
|
173
244
|
const previousTime = this.currentTime;
|
|
174
245
|
this.currentTime = time;
|
|
@@ -199,17 +270,27 @@ export class QuarksPrefab extends TransformNode implements IPrefab {
|
|
|
199
270
|
});
|
|
200
271
|
}
|
|
201
272
|
|
|
273
|
+
/** Same as {@link QuarksPrefab.duration}. */
|
|
202
274
|
getDuration(): number {
|
|
203
275
|
return this.duration;
|
|
204
276
|
}
|
|
205
277
|
|
|
278
|
+
/**
|
|
279
|
+
* Links the tracks read by {@link QuarksPrefab.fromJSON} to the nodes under `root` they name.
|
|
280
|
+
* {@link QuarksLoader} calls it once the whole effect is built; tracks whose node is missing are dropped.
|
|
281
|
+
*/
|
|
206
282
|
resolveReferences(root: TransformNode): void {
|
|
207
283
|
const nodesMap: {[uuid: string]: TransformNode} = {};
|
|
208
284
|
const traverse = (node: TransformNode) => {
|
|
209
|
-
|
|
210
|
-
|
|
285
|
+
// A file's uuid names the node it was loaded as; a Babylon uniqueId, which older files
|
|
286
|
+
// wrote for nodes made in code, only names a node that has no file uuid, and never
|
|
287
|
+
// takes over an id already claimed.
|
|
288
|
+
const fileId = (node as any)._quarksUUID as string | undefined;
|
|
289
|
+
if (fileId) {
|
|
290
|
+
nodesMap[fileId] = node;
|
|
291
|
+
} else {
|
|
292
|
+
nodesMap[node.uniqueId.toString()] ??= node;
|
|
211
293
|
}
|
|
212
|
-
nodesMap[node.uniqueId.toString()] = node;
|
|
213
294
|
const children = node.getChildren();
|
|
214
295
|
for (const child of children) {
|
|
215
296
|
if (child instanceof TransformNode) {
|
|
@@ -246,23 +327,29 @@ export class QuarksPrefab extends TransformNode implements IPrefab {
|
|
|
246
327
|
this._tempAnimationJSON = [];
|
|
247
328
|
}
|
|
248
329
|
|
|
330
|
+
/** Writes the prefab's name, time scale (when not 1) and tracks. */
|
|
249
331
|
toJSON(): any {
|
|
250
332
|
return {
|
|
251
333
|
type: this.type,
|
|
252
334
|
name: this.name,
|
|
335
|
+
...(this.timeScale !== 1 ? {timeScale: this.timeScale} : {}),
|
|
253
336
|
animationData: this.animationData.map((animation) => ({
|
|
254
337
|
startTime: animation.startTime,
|
|
255
338
|
duration: animation.duration,
|
|
256
339
|
type: animation.type,
|
|
257
|
-
targetUUID: (animation.target
|
|
340
|
+
targetUUID: quarksNodeId(animation.target),
|
|
258
341
|
clipUUID: animation.type === 'three' ? (animation.clipUUID ?? animation.clip?.uuid) : undefined,
|
|
259
342
|
loop: animation.loop,
|
|
260
343
|
})),
|
|
261
344
|
};
|
|
262
345
|
}
|
|
263
346
|
|
|
347
|
+
/** Reads a prefab written by {@link QuarksPrefab.toJSON}; call {@link QuarksPrefab.resolveReferences} afterwards. */
|
|
264
348
|
static fromJSON(json: any, scene?: Scene): QuarksPrefab {
|
|
265
349
|
const prefab = new QuarksPrefab(json.name || 'QuarksPrefab', scene);
|
|
350
|
+
if (typeof json.timeScale === 'number') {
|
|
351
|
+
prefab.timeScale = json.timeScale;
|
|
352
|
+
}
|
|
266
353
|
if (Array.isArray(json.animationData)) {
|
|
267
354
|
prefab._tempAnimationJSON = json.animationData.filter(
|
|
268
355
|
(item: any) => item?.type === 'ps' || item?.type === 'three'
|