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
@@ -0,0 +1,239 @@
1
+ import {Constants} from '@babylonjs/core/Engines/constants';
2
+ import type {Vector3} from 'quarks.core';
3
+ import type {VFXBatchSettings} from './BatchedRenderer';
4
+ import {
5
+ normalizeErosion,
6
+ normalizeGradientMap,
7
+ normalizeMapUV,
8
+ normalizeMeshRim,
9
+ normalizeUVDistortion,
10
+ readsUV1,
11
+ RenderMode,
12
+ StoredBatchSettings,
13
+ TextureUV,
14
+ } from './batchSettings';
15
+ import {DEFAULT_SOFT_FAR_FADE, validRenderFace, validSoftFade, validTileCount} from './system/normalize';
16
+
17
+ // What decides whether two systems draw from one batch.
18
+ //
19
+ // A batch is one draw call with one material, so its systems share everything the material
20
+ // holds. That falls into two groups, as a Unity material's shader keywords and texture slots
21
+ // against its MaterialPropertyBlock values, or an Unreal material against its dynamic
22
+ // instance's parameters:
23
+ //
24
+ // - the shader key: the render mode, the geometry, the textures, the blend and depth state,
25
+ // and which effects are compiled in. A change here needs a new material;
26
+ // - the live parameters: the numbers the effects run on, such as a soft fade distance, an
27
+ // erosion edge width or a rim colour. They are uniforms, so a change here is written to the
28
+ // material in place.
29
+ //
30
+ // Each render mode reads only part of the settings, so before two settings are compared they
31
+ // are reduced to a canonical form in which every field the mode ignores is at its default. Two
32
+ // billboards that differ only in a mesh rim then share a batch.
33
+
34
+ /** Geometry a trail batch's settings hold, since a trail draws its own strip. */
35
+ const NO_GEOMETRY = new Float32Array(0);
36
+ const NO_INDICES = new Uint16Array(0);
37
+
38
+ /** Whether `renderMode` draws camera-facing quads that take a pivot and screen-size limits. */
39
+ export function takesPivotAndSizeLimits(renderMode: RenderMode): boolean {
40
+ return (
41
+ renderMode === RenderMode.BillBoard ||
42
+ renderMode === RenderMode.StretchedBillBoard ||
43
+ renderMode === RenderMode.VerticalBillBoard ||
44
+ renderMode === RenderMode.HorizontalBillBoard
45
+ );
46
+ }
47
+
48
+ /** Whether the settings draw a flipbook: more than one cell in either direction. */
49
+ export function tilesSheet(settings: {uTileCount: number; vTileCount: number}): boolean {
50
+ return settings.uTileCount > 1 || settings.vTileCount > 1;
51
+ }
52
+
53
+ /** Whether the settings put a screen-size limit on the particles. */
54
+ export function hasSizeLimits(settings: {minParticleSize: number; maxParticleSize: number}): boolean {
55
+ return settings.minParticleSize > 0 || settings.maxParticleSize !== Infinity;
56
+ }
57
+
58
+ /**
59
+ * A batch's copy of a system's settings: every optional field defaulted, and every field the
60
+ * render mode ignores at its default, so that systems that draw the same share a batch whatever
61
+ * their unused settings say. See {@link batchSettingsEqual}.
62
+ */
63
+ export function storedBatchSettings(settings: VFXBatchSettings): StoredBatchSettings {
64
+ const renderMode = settings.renderMode;
65
+ const isMesh = renderMode === RenderMode.Mesh;
66
+ const isTrail = renderMode === RenderMode.Trail;
67
+ const quad = takesPivotAndSizeLimits(renderMode);
68
+ const softParticles = settings.softParticles;
69
+ const transparent = settings.materialTransparent;
70
+ const pivot = settings.pivot;
71
+ const mapUV = normalizeMapUV(settings.mapUV);
72
+ const uvDistortion = normalizeUVDistortion(settings.uvDistortion);
73
+ const gradientMap = normalizeGradientMap(settings.gradientMap);
74
+ const erosion = normalizeErosion(settings.erosion);
75
+ const uTileCount = validTileCount(settings.uTileCount);
76
+ const vTileCount = validTileCount(settings.vTileCount);
77
+ const stored: StoredBatchSettings = {
78
+ renderMode,
79
+ // A trail draws its own strip and reads none of the instanced geometry.
80
+ instancingGeometry: isTrail ? NO_GEOMETRY : settings.instancingGeometry,
81
+ instancingIndices: isTrail ? NO_INDICES : settings.instancingIndices,
82
+ instancingUVs: isTrail ? undefined : settings.instancingUVs,
83
+ // Normals, and the second UV set when a texture reads it, only reach mesh particles.
84
+ instancingUVs2: isMesh && readsUV1({mapUV, uvDistortion, erosion}) ? settings.instancingUVs2 : undefined,
85
+ instancingNormals: isMesh ? settings.instancingNormals : undefined,
86
+ renderOrder: settings.renderOrder,
87
+ uTileCount,
88
+ vTileCount,
89
+ // A trail cuts its cell on the CPU; a 1×1 sheet has no second cell to blend into.
90
+ blendTiles: !isTrail && settings.blendTiles && tilesSheet({uTileCount, vTileCount}),
91
+ softParticles,
92
+ softNearFade: softParticles ? validSoftFade(settings.softNearFade, 0) : 0,
93
+ softFarFade: softParticles ? validSoftFade(settings.softFarFade, DEFAULT_SOFT_FAR_FADE) : 0,
94
+ // An opaque batch draws with blending off, whatever mode it would blend with.
95
+ materialBlendMode: transparent ? settings.materialBlendMode : Constants.ALPHA_DISABLE,
96
+ materialTransparent: transparent,
97
+ materialDepthTest: settings.materialDepthTest,
98
+ materialDepthWrite: settings.materialDepthWrite,
99
+ materialAlphaTest: settings.materialAlphaTest > 0 ? settings.materialAlphaTest : 0,
100
+ texture: settings.texture,
101
+ reflectionTexture: isMesh ? (settings.reflectionTexture ?? null) : null,
102
+ reflectionLevel: isMesh ? (settings.reflectionLevel ?? 1) : 1,
103
+ reflectionAtlas: isMesh ? (settings.reflectionAtlas ?? null) : null,
104
+ layerMask: settings.layerMask,
105
+ renderingGroupId: settings.renderingGroupId ?? 0,
106
+ applyFog: settings.applyFog ?? true,
107
+ pivot: quad && pivot && (pivot.x !== 0 || pivot.y !== 0 || pivot.z !== 0) ? pivot.clone() : undefined,
108
+ sortMode: settings.sortMode ?? 'none',
109
+ renderFace: isMesh ? validRenderFace(settings.renderFace) : 'both',
110
+ minParticleSize: quad ? Math.max(0, settings.minParticleSize ?? 0) : 0,
111
+ maxParticleSize: quad ? positiveOrUnlimited(settings.maxParticleSize) : Infinity,
112
+ lighting: isMesh ? (settings.lighting ?? 'fixed') : 'fixed',
113
+ rim: isMesh ? normalizeMeshRim(settings.rim) : undefined,
114
+ mapUV,
115
+ uvDistortion,
116
+ gradientMap,
117
+ erosion,
118
+ };
119
+ return stored;
120
+ }
121
+
122
+ /** `size` when it limits something, else no limit. */
123
+ function positiveOrUnlimited(size: number | undefined): number {
124
+ return size !== undefined && size > 0 ? size : Infinity;
125
+ }
126
+
127
+ /**
128
+ * Whether two canonical settings compile to the same material: the same render mode, geometry,
129
+ * textures, blend and depth state, and the same effects. Batches with equal shader keys differ
130
+ * only in {@link liveParamsEqual | live parameters}.
131
+ */
132
+ export function shaderKeyEqual(a: StoredBatchSettings, b: StoredBatchSettings): boolean {
133
+ return (
134
+ a.renderMode === b.renderMode &&
135
+ a.instancingGeometry === b.instancingGeometry &&
136
+ a.instancingIndices === b.instancingIndices &&
137
+ a.instancingUVs === b.instancingUVs &&
138
+ a.instancingUVs2 === b.instancingUVs2 &&
139
+ a.instancingNormals === b.instancingNormals &&
140
+ a.texture === b.texture &&
141
+ a.reflectionTexture === b.reflectionTexture &&
142
+ a.reflectionAtlas === b.reflectionAtlas &&
143
+ a.lighting === b.lighting &&
144
+ a.rim?.mode === b.rim?.mode &&
145
+ a.uTileCount === b.uTileCount &&
146
+ a.vTileCount === b.vTileCount &&
147
+ a.blendTiles === b.blendTiles &&
148
+ a.softParticles === b.softParticles &&
149
+ a.materialBlendMode === b.materialBlendMode &&
150
+ a.materialTransparent === b.materialTransparent &&
151
+ a.materialDepthTest === b.materialDepthTest &&
152
+ a.materialDepthWrite === b.materialDepthWrite &&
153
+ a.materialAlphaTest > 0 === b.materialAlphaTest > 0 &&
154
+ a.layerMask === b.layerMask &&
155
+ a.renderingGroupId === b.renderingGroupId &&
156
+ a.renderOrder === b.renderOrder &&
157
+ a.applyFog === b.applyFog &&
158
+ a.sortMode === b.sortMode &&
159
+ a.renderFace === b.renderFace &&
160
+ !a.pivot === !b.pivot &&
161
+ hasSizeLimits(a) === hasSizeLimits(b) &&
162
+ a.mapUV?.channel === b.mapUV?.channel &&
163
+ a.uvDistortion?.map === b.uvDistortion?.map &&
164
+ a.uvDistortion?.mapUV.channel === b.uvDistortion?.mapUV.channel &&
165
+ !a.gradientMap === !b.gradientMap &&
166
+ a.gradientMap?.ramp === b.gradientMap?.ramp &&
167
+ !a.erosion === !b.erosion &&
168
+ a.erosion?.mask === b.erosion?.mask &&
169
+ a.erosion?.maskUV.channel === b.erosion?.maskUV.channel
170
+ );
171
+ }
172
+
173
+ /**
174
+ * Whether two canonical settings with the same shader key set the material's uniforms to the
175
+ * same values: the fade distances, alpha cutoff, pivot, size limits, reflection level, rim
176
+ * colour, each effect's parameters and each texture's layout.
177
+ */
178
+ export function liveParamsEqual(a: StoredBatchSettings, b: StoredBatchSettings): boolean {
179
+ return (
180
+ a.softNearFade === b.softNearFade &&
181
+ a.softFarFade === b.softFarFade &&
182
+ a.materialAlphaTest === b.materialAlphaTest &&
183
+ a.reflectionLevel === b.reflectionLevel &&
184
+ pivotEqual(a.pivot, b.pivot) &&
185
+ a.minParticleSize === b.minParticleSize &&
186
+ a.maxParticleSize === b.maxParticleSize &&
187
+ rimParamsEqual(a.rim, b.rim) &&
188
+ uvLayoutEqual(a.mapUV, b.mapUV) &&
189
+ a.uvDistortion?.strength === b.uvDistortion?.strength &&
190
+ uvLayoutEqual(a.uvDistortion?.mapUV, b.uvDistortion?.mapUV) &&
191
+ a.gradientMap?.channel === b.gradientMap?.channel &&
192
+ a.erosion?.softness === b.erosion?.softness &&
193
+ a.erosion?.edgeWidth === b.erosion?.edgeWidth &&
194
+ colorEqual(a.erosion?.edgeColor, b.erosion?.edgeColor) &&
195
+ uvLayoutEqual(a.erosion?.maskUV, b.erosion?.maskUV)
196
+ );
197
+ }
198
+
199
+ /** Whether two canonical settings draw from one batch: the same shader key and the same live parameters. */
200
+ export function batchSettingsEqual(a: StoredBatchSettings, b: StoredBatchSettings): boolean {
201
+ return shaderKeyEqual(a, b) && liveParamsEqual(a, b);
202
+ }
203
+
204
+ /** True when both pivots put the quad in the same place; a missing pivot is zero. */
205
+ function pivotEqual(a: Vector3 | undefined, b: Vector3 | undefined): boolean {
206
+ return (a?.x ?? 0) === (b?.x ?? 0) && (a?.y ?? 0) === (b?.y ?? 0) && (a?.z ?? 0) === (b?.z ?? 0);
207
+ }
208
+
209
+ function rimParamsEqual(
210
+ a: {color: readonly number[]; power: number; strength: number} | undefined,
211
+ b: {color: readonly number[]; power: number; strength: number} | undefined
212
+ ): boolean {
213
+ if (!a || !b) {
214
+ return !a === !b;
215
+ }
216
+ return a.power === b.power && a.strength === b.strength && colorEqual(a.color, b.color);
217
+ }
218
+
219
+ function colorEqual(a: readonly number[] | undefined, b: readonly number[] | undefined): boolean {
220
+ if (!a || !b) {
221
+ return !a === !b;
222
+ }
223
+ return a[0] === b[0] && a[1] === b[1] && a[2] === b[2];
224
+ }
225
+
226
+ /** Whether two layouts tile, offset and scroll the texture the same; the channel is part of the shader key. */
227
+ function uvLayoutEqual(a: TextureUV | undefined, b: TextureUV | undefined): boolean {
228
+ if (!a || !b) {
229
+ return !a === !b;
230
+ }
231
+ return (
232
+ a.tiling[0] === b.tiling[0] &&
233
+ a.tiling[1] === b.tiling[1] &&
234
+ a.offset[0] === b.offset[0] &&
235
+ a.offset[1] === b.offset[1] &&
236
+ a.scroll[0] === b.scroll[0] &&
237
+ a.scroll[1] === b.scroll[1]
238
+ );
239
+ }