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.
Files changed (79) hide show
  1. package/CHANGELOG.md +769 -8
  2. package/README.md +10 -8
  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 +6683 -0
  10. package/dist/types/index.d.ts +1959 -588
  11. package/package.json +12 -6
  12. package/src/BatchedRenderer.ts +204 -101
  13. package/src/EffectPool.ts +4 -1
  14. package/src/MeshSurfaceEmitter.ts +29 -4
  15. package/src/ParticleEmitter.ts +45 -15
  16. package/src/ParticleSystem.ts +909 -2061
  17. package/src/QuarksLoader.ts +421 -67
  18. package/src/QuarksPrefab.ts +91 -4
  19. package/src/QuarksSerializer.ts +484 -0
  20. package/src/QuarksUtil.ts +15 -0
  21. package/src/SpriteBatch.ts +106 -246
  22. package/src/TrailBatch.ts +533 -342
  23. package/src/VFXBatch.ts +236 -136
  24. package/src/batchKey.ts +237 -0
  25. package/src/effectResources.ts +79 -0
  26. package/src/envAtlas.ts +119 -17
  27. package/src/index.ts +32 -33
  28. package/src/nodeId.ts +13 -0
  29. package/src/shaderProgram.ts +325 -0
  30. package/src/shaderVariants.ts +225 -0
  31. package/src/shaders/chunks/fog.ts +4 -2
  32. package/src/shaders/chunks/sheet.ts +111 -0
  33. package/src/shaders/chunks/soft.ts +84 -0
  34. package/src/shaders/chunks/surface.ts +10 -0
  35. package/src/shaders/local_particle_physics_vert.glsl.ts +14 -28
  36. package/src/shaders/local_particle_physics_vert.wgsl.ts +16 -29
  37. package/src/shaders/particle_frag.glsl.ts +3 -22
  38. package/src/shaders/particle_frag.wgsl.ts +3 -23
  39. package/src/shaders/particle_physics_frag.glsl.ts +12 -25
  40. package/src/shaders/particle_physics_frag.wgsl.ts +12 -26
  41. package/src/shaders/particle_vert.glsl.ts +5 -27
  42. package/src/shaders/particle_vert.wgsl.ts +5 -26
  43. package/src/shaders/stretched_bb_particle_vert.glsl.ts +7 -33
  44. package/src/shaders/stretched_bb_particle_vert.wgsl.ts +7 -33
  45. package/src/shaders/trail_frag.glsl.ts +11 -1
  46. package/src/shaders/trail_frag.wgsl.ts +11 -0
  47. package/src/shaders/trail_vert.glsl.ts +45 -36
  48. package/src/shaders/trail_vert.wgsl.ts +46 -40
  49. package/src/softDepth.ts +136 -0
  50. package/src/system/BehaviorPlan.ts +85 -0
  51. package/src/system/BoundsTracker.ts +181 -0
  52. package/src/system/EmissionController.ts +360 -0
  53. package/src/system/EventDispatcher.ts +44 -0
  54. package/src/system/ParticleSpawner.ts +274 -0
  55. package/src/system/SimulationClock.ts +130 -0
  56. package/src/system/geometry.ts +111 -0
  57. package/src/system/integrate.ts +428 -0
  58. package/src/system/materialResolve.ts +116 -0
  59. package/src/system/normalize.ts +95 -0
  60. package/src/system/serialization.ts +401 -0
  61. package/src/system/settingsSchema.ts +317 -0
  62. package/src/system/types.ts +410 -0
  63. package/src/textureSource.ts +30 -0
  64. package/src/trailSettings.ts +51 -0
  65. package/src/BatchedParticleRenderer.ts +0 -3
  66. package/src/materials/ParticleMaterials.ts +0 -23
  67. package/src/materials/index.ts +0 -1
  68. package/src/shaders/chunks/index.ts +0 -1
  69. package/src/shaders/chunks/register-shader-chunks.ts +0 -32
  70. package/src/shaders/chunks/soft_fragment.glsl.ts +0 -13
  71. package/src/shaders/chunks/soft_pars_fragment.glsl.ts +0 -20
  72. package/src/shaders/chunks/soft_pars_vertex.glsl.ts +0 -6
  73. package/src/shaders/chunks/soft_vertex.glsl.ts +0 -6
  74. package/src/shaders/chunks/tile_fragment.glsl.ts +0 -9
  75. package/src/shaders/chunks/tile_pars_fragment.glsl.ts +0 -9
  76. package/src/shaders/chunks/tile_pars_vertex.glsl.ts +0 -28
  77. package/src/shaders/chunks/tile_vertex.glsl.ts +0 -18
  78. package/src/shaders/index.ts +0 -9
  79. package/src/shaders/local_particle_vert.glsl.ts +0 -50
@@ -0,0 +1,317 @@
1
+ import {Constants} from '@babylonjs/core/Engines/constants';
2
+ import {
3
+ ColorGenerator,
4
+ ColorGeneratorFromJSON,
5
+ ConstantColor,
6
+ ConstantValue,
7
+ FunctionColorGenerator,
8
+ FunctionValueGenerator,
9
+ GeneratorFromJSON,
10
+ RotationGenerator,
11
+ ValueGenerator,
12
+ ValueGeneratorFromJSON,
13
+ Vector2,
14
+ Vector3,
15
+ Vector3Generator,
16
+ Vector4,
17
+ } from 'quarks.core';
18
+ import type {ParticleSystem} from '../ParticleSystem';
19
+ import {RenderMode} from '../VFXBatch';
20
+ import {DEFAULT_SOFT_FAR_FADE, normalizeBursts, validCullingMode, validSortMode, validTileCount} from './normalize';
21
+ import type {BurstParameters, ParticleSystemJSONParameters, ParticleSystemParameters} from './types';
22
+
23
+ /**
24
+ * One setting of a {@link ParticleSystem} that is a plain value or a generator: how to read it
25
+ * from a system, what its default is, and how it goes to and from JSON and into a copy. The
26
+ * table below drives `toJSON` (which writes only values that differ from the default),
27
+ * `fromJSON` and `clone`, so a setting cannot be added to one and forgotten in another.
28
+ *
29
+ * Settings that live in the document's meta (geometry, material, texture and the texture
30
+ * effects), the render mode's own settings, the shape and the behaviors are handled by the
31
+ * callers, since they need the meta or the system itself.
32
+ */
33
+ export interface SettingDescriptor {
34
+ /** The constructor parameter. */
35
+ readonly param: keyof ParticleSystemParameters;
36
+ /** The JSON field, when it is named differently from the parameter. */
37
+ readonly json?: keyof ParticleSystemJSONParameters;
38
+ /** The current value on a system. */
39
+ get(system: ParticleSystem): unknown;
40
+ /** Whether `value` is what the constructor gives a system that leaves the setting out. */
41
+ isDefault(value: unknown): boolean;
42
+ /**
43
+ * Written even when it is the default, because the loaders of releases up to 0.27 fail on a
44
+ * file without it.
45
+ */
46
+ readonly always?: boolean;
47
+ /** The value as JSON. */
48
+ toJSON(value: unknown): unknown;
49
+ /** The constructor parameter for a JSON value that is present; undefined takes the default. */
50
+ fromJSON(json: unknown): unknown;
51
+ /** A copy that shares no mutable state with `value`. */
52
+ clone(value: unknown): unknown;
53
+ }
54
+
55
+ type Generator = {toJSON(): unknown; clone(): unknown};
56
+
57
+ /** A number, boolean or string compared by value. */
58
+ function plain<T>(
59
+ param: keyof ParticleSystemParameters,
60
+ get: (system: ParticleSystem) => T,
61
+ defaultValue: T,
62
+ read: (json: unknown) => T | undefined,
63
+ options: {json?: keyof ParticleSystemJSONParameters} = {}
64
+ ): SettingDescriptor {
65
+ return {
66
+ param,
67
+ json: options.json,
68
+ get,
69
+ isDefault: (value) => value === defaultValue,
70
+ toJSON: (value) => value,
71
+ fromJSON: read,
72
+ clone: (value) => value,
73
+ };
74
+ }
75
+
76
+ function number(json: unknown): number | undefined {
77
+ return typeof json === 'number' ? json : undefined;
78
+ }
79
+
80
+ /** A flipbook count: a whole number of at least 1, see {@link validTileCount}. */
81
+ function tileCount(json: unknown): number | undefined {
82
+ return typeof json === 'number' ? validTileCount(json) : undefined;
83
+ }
84
+
85
+ /** A soft fade distance: finite and at least 0, as `validSoftFade`; an invalid one takes the default. */
86
+ function softFade(json: unknown): number | undefined {
87
+ return typeof json === 'number' && Number.isFinite(json) && json >= 0 ? json : undefined;
88
+ }
89
+
90
+ /** A boolean; a number counts as true unless it is 0, as files with 0/1 flags meant it. */
91
+ function boolean(json: unknown): boolean | undefined {
92
+ if (typeof json === 'number') return json !== 0;
93
+ return typeof json === 'boolean' ? json : undefined;
94
+ }
95
+
96
+ /**
97
+ * A generator, compared with its default through its JSON. `read` turns the JSON back into one;
98
+ * a bare number is read as a constant.
99
+ */
100
+ function generator(
101
+ param: keyof ParticleSystemParameters,
102
+ get: (system: ParticleSystem) => Generator,
103
+ defaultValue: () => Generator,
104
+ read: (json: any) => unknown,
105
+ always = true
106
+ ): SettingDescriptor {
107
+ const defaultJSON = JSON.stringify(defaultValue().toJSON());
108
+ return {
109
+ param,
110
+ always,
111
+ get,
112
+ isDefault: (value) => JSON.stringify((value as Generator).toJSON()) === defaultJSON,
113
+ toJSON: (value) => (value as Generator).toJSON(),
114
+ fromJSON: (json) => (typeof json === 'number' ? new ConstantValue(json) : read(json)),
115
+ clone: (value) => (value as Generator).clone(),
116
+ };
117
+ }
118
+
119
+ function vectorJSON(value: unknown): number[] | undefined {
120
+ const v = value as {x: number; y: number; z?: number} | undefined;
121
+ if (v === undefined) return undefined;
122
+ return v.z === undefined ? [v.x, v.y] : [v.x, v.y, v.z];
123
+ }
124
+
125
+ /** Every plain and generator setting, in the order `toJSON` writes them. */
126
+ export const SETTINGS: ReadonlyArray<SettingDescriptor> = [
127
+ plain('autoDestroy', (s) => s.autoDestroy, false, boolean),
128
+ plain('looping', (s) => s.looping, true, boolean),
129
+ plain('prewarm', (s) => s.prewarm, false, boolean),
130
+ plain('prewarmTime', (s) => s.prewarmTime, 0, number),
131
+ plain('duration', (s) => s.duration, 1, number),
132
+ generator(
133
+ 'startDelay',
134
+ (s) => s.startDelay,
135
+ () => new ConstantValue(0),
136
+ ValueGeneratorFromJSON,
137
+ false
138
+ ),
139
+ generator(
140
+ 'startLife',
141
+ (s) => s.startLife,
142
+ () => new ConstantValue(5),
143
+ ValueGeneratorFromJSON
144
+ ),
145
+ generator(
146
+ 'startSpeed',
147
+ (s) => s.startSpeed,
148
+ () => new ConstantValue(0),
149
+ ValueGeneratorFromJSON
150
+ ),
151
+ generator(
152
+ 'startRotation',
153
+ (s) => s.startRotation,
154
+ () => new ConstantValue(0),
155
+ (json) => GeneratorFromJSON(json) as RotationGenerator | ValueGenerator | FunctionValueGenerator
156
+ ),
157
+ generator(
158
+ 'startSize',
159
+ (s) => s.startSize,
160
+ () => new ConstantValue(1),
161
+ (json) => GeneratorFromJSON(json) as Vector3Generator | ValueGenerator | FunctionValueGenerator
162
+ ),
163
+ generator(
164
+ 'startColor',
165
+ (s) => s.startColor,
166
+ () => new ConstantColor(new Vector4(1, 1, 1, 1)),
167
+ (json) => ColorGeneratorFromJSON(json) as ColorGenerator | FunctionColorGenerator
168
+ ),
169
+ generator(
170
+ 'emissionOverTime',
171
+ (s) => s.emissionOverTime,
172
+ () => new ConstantValue(10),
173
+ ValueGeneratorFromJSON
174
+ ),
175
+ generator(
176
+ 'emissionOverDistance',
177
+ (s) => s.emissionOverDistance,
178
+ () => new ConstantValue(0),
179
+ ValueGeneratorFromJSON
180
+ ),
181
+ {
182
+ param: 'emissionBursts',
183
+ get: (s) => s.emissionBursts,
184
+ isDefault: (value) => (value as BurstParameters[]).length === 0,
185
+ toJSON: (value) =>
186
+ (value as BurstParameters[]).map((burst) => ({
187
+ time: burst.time,
188
+ count: burst.count.toJSON(),
189
+ probability: burst.probability,
190
+ interval: burst.interval,
191
+ cycle: burst.cycle,
192
+ })),
193
+ fromJSON: (json) =>
194
+ Array.isArray(json)
195
+ ? normalizeBursts(
196
+ json.map((burst: any) => ({
197
+ time: burst.time,
198
+ count:
199
+ typeof burst.count === 'number'
200
+ ? new ConstantValue(burst.count)
201
+ : ValueGeneratorFromJSON(burst.count),
202
+ probability: burst.probability,
203
+ interval: burst.interval,
204
+ cycle: burst.cycle ?? burst.cycleCount,
205
+ }))
206
+ )
207
+ : undefined,
208
+ clone: (value) => (value as BurstParameters[]).map((burst) => ({...burst, count: burst.count.clone()})),
209
+ },
210
+ plain('maxParticles', (s) => s.maxParticles, undefined, number),
211
+ plain('onlyUsedByOther', (s) => s.onlyUsedByOther, false, boolean),
212
+ plain('renderMode', (s) => s.renderMode, RenderMode.BillBoard, number),
213
+ plain('renderOrder', (s) => s.renderOrder, 0, number),
214
+ plain('renderingGroupId', (s) => s.renderingGroupId, 0, number),
215
+ plain(
216
+ 'applyFog',
217
+ (s) => s.applyFog,
218
+ true,
219
+ (json) => json !== false
220
+ ),
221
+ plain('playbackSpeed', (s) => s.playbackSpeed, 1, number),
222
+ plain('cullingMode', (s) => s.cullingMode, 'always', validCullingMode),
223
+ plain(
224
+ 'scalingMode',
225
+ (s) => s.scalingMode,
226
+ 'shape',
227
+ (json) => (json === 'hierarchy' ? 'hierarchy' : 'shape')
228
+ ),
229
+ plain('seed', (s) => s.seed, undefined, number),
230
+ plain('sortMode', (s) => s.sortMode, 'none', validSortMode),
231
+ plain(
232
+ 'alignToDirection',
233
+ (s) => s.alignToDirection,
234
+ false,
235
+ (json) => json === true
236
+ ),
237
+ plain('minParticleSize', (s) => s.minParticleSize, 0, number),
238
+ plain('maxParticleSize', (s) => s.maxParticleSize, Infinity, number),
239
+ plain('layerMask', (s) => s.layers.mask, 0x0fffffff, number, {json: 'layers'}),
240
+ generator(
241
+ 'startTileIndex',
242
+ (s) => s.startTileIndex,
243
+ () => new ConstantValue(0),
244
+ ValueGeneratorFromJSON
245
+ ),
246
+ plain('uTileCount', (s) => s.uTileCount, 1, tileCount),
247
+ plain('vTileCount', (s) => s.vTileCount, 1, tileCount),
248
+ plain('blendTiles', (s) => s.blendTiles, false, boolean),
249
+ plain('softParticles', (s) => s.softParticles, false, boolean),
250
+ plain('softFarFade', (s) => s.softFarFade, DEFAULT_SOFT_FAR_FADE, softFade),
251
+ plain('softNearFade', (s) => s.softNearFade, 0, softFade),
252
+ plain('blendMode', (s) => s.blending, Constants.ALPHA_ADD, number, {json: 'blending'}),
253
+ plain('transparent', (s) => s.transparent, true, boolean),
254
+ plain('depthTest', (s) => s.depthTest, true, boolean),
255
+ plain('depthWrite', (s) => s.depthWrite, false, boolean),
256
+ plain('alphaTest', (s) => s.alphaTest, 0, number),
257
+ plain('worldSpace', (s) => s.worldSpace, false, boolean),
258
+ {
259
+ param: 'pivot',
260
+ get: (s) => s.pivot,
261
+ isDefault: (value) => value === undefined,
262
+ toJSON: vectorJSON,
263
+ fromJSON: (json) => (Array.isArray(json) ? new Vector3(json[0] ?? 0, json[1] ?? 0, json[2] ?? 0) : undefined),
264
+ clone: (value) => (value as Vector3 | undefined)?.clone(),
265
+ },
266
+ {
267
+ param: 'flip',
268
+ get: (s) => s.flip,
269
+ isDefault: (value) => value === undefined,
270
+ toJSON: vectorJSON,
271
+ fromJSON: (json) => (Array.isArray(json) ? new Vector2(json[0] ?? 0, json[1] ?? 0) : undefined),
272
+ clone: (value) => (value as Vector2 | undefined)?.clone(),
273
+ },
274
+ ];
275
+
276
+ /** The JSON field a setting is written under. */
277
+ export function settingJSONKey(setting: SettingDescriptor): string {
278
+ return setting.json ?? setting.param;
279
+ }
280
+
281
+ /** The settings of `system` that differ from their defaults, as JSON fields. */
282
+ export function settingsToJSON(system: ParticleSystem): Record<string, unknown> {
283
+ const json: Record<string, unknown> = {};
284
+ for (const setting of SETTINGS) {
285
+ const value = setting.get(system);
286
+ if (setting.always || !setting.isDefault(value)) {
287
+ json[settingJSONKey(setting)] = setting.toJSON(value);
288
+ }
289
+ }
290
+ return json;
291
+ }
292
+
293
+ /** Constructor parameters for the settings a document has; missing ones are left out, so they take the default. */
294
+ export function settingsFromJSON(json: ParticleSystemJSONParameters): Partial<ParticleSystemParameters> {
295
+ const parameters: Record<string, unknown> = {};
296
+ const fields = json as unknown as Record<string, unknown>;
297
+ for (const setting of SETTINGS) {
298
+ const value = fields[settingJSONKey(setting)];
299
+ if (value === undefined || value === null) {
300
+ continue;
301
+ }
302
+ const read = setting.fromJSON(value);
303
+ if (read !== undefined) {
304
+ parameters[setting.param] = read;
305
+ }
306
+ }
307
+ return parameters as Partial<ParticleSystemParameters>;
308
+ }
309
+
310
+ /** Constructor parameters that copy every setting of `system`. */
311
+ export function settingsForClone(system: ParticleSystem): Partial<ParticleSystemParameters> {
312
+ const parameters: Record<string, unknown> = {};
313
+ for (const setting of SETTINGS) {
314
+ parameters[setting.param] = setting.clone(setting.get(system));
315
+ }
316
+ return parameters as Partial<ParticleSystemParameters>;
317
+ }