babylon.quarks 0.21.0 → 0.24.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 (36) hide show
  1. package/CHANGELOG.md +184 -0
  2. package/dist/babylon.quarks.cjs +1 -1
  3. package/dist/babylon.quarks.cjs.map +1 -1
  4. package/dist/babylon.quarks.esm.js +1 -1
  5. package/dist/babylon.quarks.esm.js.map +1 -1
  6. package/dist/babylon.quarks.umd.min.js +1 -1
  7. package/dist/babylon.quarks.umd.min.js.map +1 -1
  8. package/dist/types/index.d.ts +936 -45
  9. package/package.json +2 -2
  10. package/src/BatchedRenderer.ts +205 -4
  11. package/src/EffectPool.ts +165 -0
  12. package/src/MeshSurfaceEmitter.ts +4 -4
  13. package/src/ParticleEmitter.ts +2 -1
  14. package/src/ParticleSystem.ts +975 -69
  15. package/src/QuarksLoader.ts +25 -4
  16. package/src/QuarksUtil.ts +55 -7
  17. package/src/SpriteBatch.ts +515 -114
  18. package/src/TrailBatch.ts +128 -75
  19. package/src/VFXBatch.ts +255 -3
  20. package/src/index.ts +5 -2
  21. package/src/instanceSort.ts +121 -0
  22. package/src/shaders/chunks/fog.ts +127 -0
  23. package/src/shaders/local_particle_physics_vert.glsl.ts +4 -0
  24. package/src/shaders/local_particle_physics_vert.wgsl.ts +4 -0
  25. package/src/shaders/particle_frag.glsl.ts +4 -0
  26. package/src/shaders/particle_frag.wgsl.ts +4 -0
  27. package/src/shaders/particle_physics_frag.glsl.ts +30 -1
  28. package/src/shaders/particle_physics_frag.wgsl.ts +30 -1
  29. package/src/shaders/particle_vert.glsl.ts +23 -4
  30. package/src/shaders/particle_vert.wgsl.ts +23 -4
  31. package/src/shaders/stretched_bb_particle_vert.glsl.ts +17 -0
  32. package/src/shaders/stretched_bb_particle_vert.wgsl.ts +18 -1
  33. package/src/shaders/trail_frag.glsl.ts +4 -0
  34. package/src/shaders/trail_frag.wgsl.ts +4 -0
  35. package/src/shaders/trail_vert.glsl.ts +4 -0
  36. package/src/shaders/trail_vert.wgsl.ts +4 -0
@@ -2,10 +2,13 @@ import { BaseTexture } from '@babylonjs/core/Materials/Textures/baseTexture';
2
2
  import { Texture } from '@babylonjs/core/Materials/Textures/texture';
3
3
  import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
4
4
  import { Scene } from '@babylonjs/core/scene';
5
+ import { ShaderMaterial } from '@babylonjs/core/Materials/shaderMaterial';
6
+ import { Color3 } from '@babylonjs/core/Maths/math.color';
7
+ import { Vector3 as Vector3$1 } from '@babylonjs/core/Maths/math.vector';
5
8
  import { Mesh } from '@babylonjs/core/Meshes/mesh';
9
+ import { Node } from '@babylonjs/core/node';
6
10
  import { PBRMaterial } from '@babylonjs/core/Materials/PBR/pbrMaterial';
7
11
  import { StandardMaterial } from '@babylonjs/core/Materials/standardMaterial';
8
- import { Node } from '@babylonjs/core/node';
9
12
 
10
13
  declare class Vector2 {
11
14
  x: number;
@@ -366,6 +369,25 @@ declare const MathUtils: {
366
369
  denormalize: typeof denormalize;
367
370
  };
368
371
 
372
+ /**
373
+ * A `Quaternion` whose components live in a shared `Float32Array` at a fixed
374
+ * offset. Every `Quaternion` method reads and writes `_x` .. `_w`, so replacing
375
+ * those four with accessors inherits the whole API; they are installed on the
376
+ * prototype because TypeScript forbids overriding an inherited property with
377
+ * an accessor in the class body (TS2611).
378
+ */
379
+ declare class QuaternionView extends Quaternion {
380
+ data: Float32Array;
381
+ offset: number;
382
+ _x: number;
383
+ _y: number;
384
+ _z: number;
385
+ _w: number;
386
+ constructor(data: Float32Array, offset: number);
387
+ /** Points the view at a new backing array and row offset. */
388
+ bind(data: Float32Array, offset: number): void;
389
+ }
390
+
369
391
  /**
370
392
  * A `Vector3` whose components live in a shared `Float32Array` at a fixed
371
393
  * offset rather than in three own properties.
@@ -648,6 +670,12 @@ declare class Gradient implements FunctionColorGenerator {
648
670
  * signature check so a gradient edited in an editor is picked up.
649
671
  */
650
672
  refreshTable(): void;
673
+ /**
674
+ * The sampled table {@link genColor} currently reads from, or null while
675
+ * none has been built. Lets a compiled behavior pass interpolate the table
676
+ * inline instead of calling in here once per particle.
677
+ */
678
+ sampledTable(): Float32Array | null;
651
679
  /** Drops the sampled table, so later reads go back to evaluating the keys. */
652
680
  clearTable(): void;
653
681
  genColor(memory: GeneratorMemory, color: Vector4, t: number): Vector4;
@@ -808,6 +836,12 @@ declare class PiecewiseBezier extends PiecewiseFunction<Bezier> implements Funct
808
836
  * change. That is a handful of float compares per frame.
809
837
  */
810
838
  refreshTable(): void;
839
+ /**
840
+ * The sampled table {@link genValue} currently reads from, or null while
841
+ * none has been built. Lets a compiled behavior pass interpolate the table
842
+ * inline instead of calling in here once per particle.
843
+ */
844
+ sampledTable(): Float32Array | null;
811
845
  /** Drops the sampled table, so later reads go back to evaluating the curve. */
812
846
  clearTable(): void;
813
847
  genValue(memory: GeneratorMemory, t?: number): number;
@@ -908,6 +942,38 @@ declare class ParticleStore {
908
942
  * tightly balanced emitters flicker.
909
943
  */
910
944
  scalars: Float64Array;
945
+ /**
946
+ * Scalars the renderer uploads and the behaviors write, one per row, so a
947
+ * batch copies them as ranges instead of visiting every particle object:
948
+ * sprite rotation angle and its rate, texture tile, mirroring bits and the
949
+ * speed the particle was born with. A mesh particle keeps its quaternion
950
+ * rotation on the particle; its `rotation` row here is then unused.
951
+ */
952
+ rotation: Float32Array;
953
+ angularVelocity: Float32Array;
954
+ uvTile: Float32Array;
955
+ startSpeed: Float32Array;
956
+ /** Bit 1 mirrors along U, bit 2 along V. */
957
+ flip: Uint8Array;
958
+ /**
959
+ * Quaternion rotation and one step's quaternion turn, 4 per row, for
960
+ * particles that rotate by quaternion (mesh render mode). Empty until
961
+ * {@link ensureQuaternionColumns} is asked for them, so systems of
962
+ * billboards do not pay for columns they never read.
963
+ */
964
+ rotationQuaternion: Float32Array;
965
+ angularVelocityQuaternion: Float32Array;
966
+ /**
967
+ * Numeric copy of each particle's generator memory, {@link memoryStride}
968
+ * values per row. The spawn path calls every generator's `startGen` in a
969
+ * fixed order, so a given slot holds the same generator's sample for every
970
+ * particle, which lets a compiled behavior pass read a particle's random
971
+ * sample from a column instead of through its `memory` array. Slots that
972
+ * hold something other than a number are NaN here; readers then fall back
973
+ * to the array. Empty until {@link recordMemory} sees the first spawn.
974
+ */
975
+ memory: Float64Array;
976
+ memoryStride: number;
911
977
  /** Values per row in {@link scalars}. */
912
978
  static readonly SCALAR_STRIDE = 3;
913
979
  /** Offsets within a {@link scalars} row. */
@@ -936,7 +1002,29 @@ declare class ParticleStore {
936
1002
  * leaves every particle's view of it pointing at the old one.
937
1003
  */
938
1004
  keepPreviousVelocity(): boolean;
1005
+ /**
1006
+ * Mirrors a freshly spawned particle's generator memory into the
1007
+ * {@link memory} column, widening the column when this spawn used more
1008
+ * slots than any before it.
1009
+ */
1010
+ recordMemory(row: number, memory: ReadonlyArray<unknown>): void;
1011
+ /**
1012
+ * Whether {@link previousSize} is a snapshot of its own or an alias of
1013
+ * {@link size}. A system whose behaviors never change a particle's size
1014
+ * after birth has nothing to carry between steps for it, and aliasing the
1015
+ * two saves the copy a step would otherwise make; readers that interpolate
1016
+ * from previous to current then get the current value unchanged.
1017
+ */
1018
+ useSizeSnapshot(enabled: boolean): void;
1019
+ /** The same for {@link previousColor}, see {@link useSizeSnapshot}. */
1020
+ useColorSnapshot(enabled: boolean): void;
1021
+ /**
1022
+ * Allocates the quaternion columns. Returns true on the call that did,
1023
+ * which means views already bound to the store need re-binding.
1024
+ */
1025
+ ensureQuaternionColumns(): boolean;
939
1026
  swapRows(a: number, b: number): void;
1027
+ private static swap1;
940
1028
  private static growDouble;
941
1029
  private static swap3;
942
1030
  private static swap4;
@@ -944,8 +1032,15 @@ declare class ParticleStore {
944
1032
  }
945
1033
 
946
1034
  interface EmissionState {
1035
+ /** Bursts whose first wave has fired this loop, in time order. */
947
1036
  burstIndex: number;
1037
+ /** Wave of the burst being spawned right now (0 for its first wave). */
948
1038
  burstWaveIndex: number;
1039
+ /**
1040
+ * Waves fired so far this loop, per burst. Created by the system on first
1041
+ * use, so states made elsewhere (sub emitters) can leave it out.
1042
+ */
1043
+ burstWaves?: number[];
949
1044
  burstParticleIndex: number;
950
1045
  burstParticleCount: number;
951
1046
  isBursting: boolean;
@@ -953,6 +1048,10 @@ interface EmissionState {
953
1048
  waitEmiting: number;
954
1049
  travelDistance: number;
955
1050
  previousWorldPos?: Vector3;
1051
+ /** The particle a sub emission comes from, when it does; see `EmitSubParticleSystem.inherit`. */
1052
+ particle?: Particle;
1053
+ /** Bit mask of the parent's properties the spawned particles take, see `SubEmitterInheritMask`. */
1054
+ inherit?: number;
956
1055
  }
957
1056
  interface Resource {
958
1057
  }
@@ -1384,10 +1483,11 @@ declare class SpriteParticle implements Particle {
1384
1483
  */
1385
1484
  parentMatrix?: Matrix4;
1386
1485
  /**
1387
- * Initial speed of the particle.
1486
+ * Initial speed of the particle, kept in the store's `startSpeed` column.
1388
1487
  * @type {number}
1389
1488
  */
1390
- startSpeed: number;
1489
+ get startSpeed(): number;
1490
+ set startSpeed(value: number);
1391
1491
  /**
1392
1492
  * Initial color of the particle.
1393
1493
  * @type {Vector4}
@@ -1447,31 +1547,51 @@ declare class SpriteParticle implements Particle {
1447
1547
  get speedModifier(): number;
1448
1548
  set speedModifier(value: number);
1449
1549
  /**
1450
- * Angular velocity of the particle.
1550
+ * View of this particle's row in the store's quaternion rotation column,
1551
+ * when it rotates by quaternion (mesh render mode); undefined while it
1552
+ * rotates by an angle, which then lives in the store's `rotation` column.
1553
+ * Always present so every sprite particle keeps one hidden class.
1554
+ */
1555
+ private rotationQuaternion;
1556
+ /** Same split for the turn rate: a quaternion step here, a scalar rate in the store. */
1557
+ private angularVelocityQuaternion;
1558
+ /**
1559
+ * Angular velocity of the particle: a rate in radians per second for an
1560
+ * angle rotation, one step's turn for a quaternion rotation. Both live in
1561
+ * the store so the renderer and compiled behaviors read them as ranges;
1562
+ * assigning a quaternion copies it into the particle's row and returns a
1563
+ * view of that row from then on.
1451
1564
  * @type {number | Quaternion}
1452
1565
  */
1453
- angularVelocity?: number | Quaternion;
1566
+ get angularVelocity(): number | Quaternion;
1567
+ set angularVelocity(value: number | Quaternion | undefined);
1454
1568
  /**
1455
- * Rotation of the particle.
1569
+ * Rotation of the particle: an angle, or a quaternion for mesh particles.
1570
+ * Both live in the store; see {@link angularVelocity} for how assigning a
1571
+ * quaternion behaves.
1456
1572
  * @type {number | Quaternion}
1457
1573
  */
1458
- rotation: number | Quaternion;
1574
+ get rotation(): number | Quaternion;
1575
+ set rotation(value: number | Quaternion);
1459
1576
  /**
1460
1577
  * Color of the particle.
1461
1578
  * @type {Vector4}
1462
1579
  */
1463
1580
  color: Vector4;
1464
1581
  /**
1465
- * UV tile index.
1582
+ * UV tile index, kept in the store's `uvTile` column.
1466
1583
  * @type {number}
1467
1584
  */
1468
- uvTile: number;
1585
+ get uvTile(): number;
1586
+ set uvTile(value: number);
1469
1587
  /**
1470
1588
  * Mirroring picked at birth from the system's `flip` fractions: bit 1
1471
- * mirrors the sprite along U, bit 2 along V. 0 draws it as is.
1589
+ * mirrors the sprite along U, bit 2 along V. 0 draws it as is. Kept in
1590
+ * the store's `flip` column.
1472
1591
  * @type {number}
1473
1592
  */
1474
- flip: number;
1593
+ get flip(): number;
1594
+ set flip(value: number);
1475
1595
  /**
1476
1596
  * @param store - Column storage to bind to. A private single-row store is
1477
1597
  * created when omitted, so a standalone `new SpriteParticle()` still works.
@@ -1519,10 +1639,11 @@ declare class TrailParticle implements Particle {
1519
1639
  */
1520
1640
  parentMatrix?: Matrix4;
1521
1641
  /**
1522
- * Initial speed of the particle.
1642
+ * Initial speed of the particle, kept in the store's `startSpeed` column.
1523
1643
  * @type {number}
1524
1644
  */
1525
- startSpeed: number;
1645
+ get startSpeed(): number;
1646
+ set startSpeed(value: number);
1526
1647
  /**
1527
1648
  * Initial color of the particle.
1528
1649
  * @type {Vector4}
@@ -1604,16 +1725,31 @@ declare class TrailParticle implements Particle {
1604
1725
  * sample without allocating. This list is no longer populated or rendered.
1605
1726
  * @type {LinkedList<RecordState>}
1606
1727
  */
1607
- previous: LinkedList<RecordState>;
1728
+ get previous(): LinkedList<RecordState>;
1729
+ set previous(value: LinkedList<RecordState>);
1730
+ private _previous;
1608
1731
  /**
1609
- * UV tile index.
1732
+ * UV tile index, kept in the store's `uvTile` column.
1610
1733
  * @type {number}
1611
1734
  */
1612
- uvTile: number;
1735
+ get uvTile(): number;
1736
+ set uvTile(value: number);
1613
1737
  /** Ring buffer of recorded positions, 3 floats per sample. */
1614
1738
  historyPositions: Float32Array;
1615
- /** Ring buffer of recorded widths, 1 float per sample. */
1739
+ /** Ring buffer of the widths the renderer draws, 1 float per sample. */
1616
1740
  historySizes: Float32Array;
1741
+ /**
1742
+ * Ring buffer of the particle's size (`size.x`) at each sample, before any
1743
+ * behavior rescaled it. Width behaviors scale this rather than
1744
+ * `historySizes`, so their factor is never compounded step after step.
1745
+ */
1746
+ historyBaseSizes: Float32Array;
1747
+ /**
1748
+ * Factor the next recorded sample's width is drawn with — what a width
1749
+ * behavior gives the head of the trail, which is recorded after the
1750
+ * behaviors have run. 1 unless such a behavior sets it.
1751
+ */
1752
+ headWidthScale: number;
1617
1753
  /** Ring buffer of recorded colors, 4 floats per sample. */
1618
1754
  historyColors: Float32Array;
1619
1755
  /** Number of samples the ring buffers can hold. */
@@ -1790,15 +1926,30 @@ declare class ApplySequences implements Behavior {
1790
1926
  *
1791
1927
  * Each behavior walking the particle array on its own means the array, and
1792
1928
  * every particle in it, is re-read once per behavior. Merging the ones this
1793
- * module recognises into one pass reads each particle once — worth roughly
1794
- * 1.2x at a hundred thousand particles and up to 1.6x at twenty thousand,
1795
- * where the per-pass overhead weighs most.
1929
+ * module recognises into one pass reads each particle once.
1930
+ *
1931
+ * The compiled pass works on the {@link ParticleStore} columns directly. Going
1932
+ * through the particle objects instead — `particles[i].color.x` — means three
1933
+ * dependent loads through objects scattered over the heap for every number
1934
+ * touched (the particle, its `Vector4View`, the view's array), and at tens of
1935
+ * thousands of particles that pointer chasing, not the arithmetic, is what the
1936
+ * step spends its time on: measured at roughly ten times the cost of reading
1937
+ * the same numbers out of the columns. The particle object is only reached for
1938
+ * when a generator needs the particle's own memory (a per-particle random
1939
+ * sample) or holds an object-valued attribute (a quaternion rotation).
1940
+ *
1941
+ * The pass relies on the system's invariant that `particles[i]` owns row `i`
1942
+ * of the store, which the system keeps when it compacts the dead.
1796
1943
  *
1797
1944
  * A behavior that is not recognised keeps its own pass, in its original place
1798
1945
  * in the order, so nothing here depends on the built-in set being complete.
1799
1946
  */
1800
- /** Runs the compiled work for `particles[0..count)`. */
1801
- type FusedPass = (behaviors: Array<Behavior>, particles: Array<Particle>, count: number, delta: number) => void;
1947
+ /**
1948
+ * Runs the compiled work for `particles[0..count)`. `store` is the column
1949
+ * storage behind the particles; when omitted it is taken from the first
1950
+ * particle.
1951
+ */
1952
+ type FusedPass = (behaviors: Array<Behavior>, particles: Array<Particle>, count: number, delta: number, store?: ParticleStore) => void;
1802
1953
  /** One step of a plan: either a compiled run of behaviors, or a single behavior. */
1803
1954
  interface FusionStep {
1804
1955
  /** Behaviors this step covers, in order. */
@@ -1810,7 +1961,9 @@ interface FusionStep {
1810
1961
  * Splits `behaviors` into steps, merging consecutive recognised ones.
1811
1962
  *
1812
1963
  * Only consecutive behaviors are merged: a behavior that stays on its own must
1813
- * still see the particles exactly where the original order left them.
1964
+ * still see the particles exactly where the original order left them. A lone
1965
+ * recognised behavior is compiled too: the gain is not only the merged loop
1966
+ * but the column access, which its own `updateAll` does not have.
1814
1967
  */
1815
1968
  declare function planBehaviorFusion(behaviors: Array<Behavior>): Array<FusionStep>;
1816
1969
 
@@ -1875,29 +2028,64 @@ declare enum SubParticleEmitMode {
1875
2028
  Birth = 1,
1876
2029
  Frame = 2
1877
2030
  }
2031
+ /** A parent particle property sub emitted particles can take over (Unity's sub emitter Inherit). */
2032
+ type SubEmitterInheritance = 'color' | 'size' | 'rotation' | 'lifetime';
2033
+ /** Bits of `EmissionState.inherit`, one per {@link SubEmitterInheritance}. */
2034
+ declare const SubEmitterInheritMask: {
2035
+ readonly color: 1;
2036
+ readonly size: 2;
2037
+ readonly rotation: 4;
2038
+ readonly lifetime: 8;
2039
+ };
2040
+ /** The mask for a list of inherited properties. */
2041
+ declare function subEmitterInheritMask(inherit: ReadonlyArray<SubEmitterInheritance>): number;
1878
2042
  /**
1879
2043
  * Emit a sub particle system from particles.
1880
2044
  */
1881
2045
  declare class EmitSubParticleSystem implements Behavior {
1882
- private particleSystem;
2046
+ particleSystem: IParticleSystem;
1883
2047
  useVelocityAsBasis: boolean;
1884
2048
  subParticleSystem: IEmitter | undefined;
1885
2049
  mode: SubParticleEmitMode;
1886
2050
  emitProbability: number;
2051
+ /**
2052
+ * Which of the parent particle's properties the sub particles start
2053
+ * from: its current colour and size multiply theirs, its rotation adds
2054
+ * to theirs, and its remaining lifetime fraction scales theirs (so
2055
+ * lifetime suits birth sub emitters, not death ones).
2056
+ */
2057
+ inherit: SubEmitterInheritance[];
1887
2058
  type: string;
1888
2059
  private q_;
1889
2060
  private v_;
1890
2061
  private v2_;
1891
2062
  private subEmissions;
1892
- constructor(particleSystem: IParticleSystem, useVelocityAsBasis: boolean, subParticleSystem: IEmitter | undefined, mode?: SubParticleEmitMode, emitProbability?: number);
2063
+ /** Finished emission states, kept for reuse: a burst of deaths would otherwise allocate one plus a matrix each. */
2064
+ private spareEmissions;
2065
+ constructor(particleSystem: IParticleSystem, useVelocityAsBasis: boolean, subParticleSystem: IEmitter | undefined, mode?: SubParticleEmitMode, emitProbability?: number,
2066
+ /**
2067
+ * Which of the parent particle's properties the sub particles start
2068
+ * from: its current colour and size multiply theirs, its rotation adds
2069
+ * to theirs, and its remaining lifetime fraction scales theirs (so
2070
+ * lifetime suits birth sub emitters, not death ones).
2071
+ */
2072
+ inherit?: SubEmitterInheritance[]);
1893
2073
  initialize(particle: Particle): void;
1894
2074
  update(particle: Particle, delta: number): void;
2075
+ /**
2076
+ * The system to emit into, or undefined when `subParticleSystem` does not
2077
+ * hold a resolved emitter — unset, or a uuid string a loader could not
2078
+ * link. Every use goes through here, so a bad value is skipped rather
2079
+ * than thrown on.
2080
+ */
2081
+ private get target();
1895
2082
  private emit;
1896
2083
  frameUpdate(delta: number): void;
1897
2084
  toJSON(): any;
1898
2085
  static fromJSON(json: any, particleSystem: IParticleSystem): Behavior;
1899
2086
  clone(): Behavior;
1900
2087
  reset(): void;
2088
+ private static validInherit;
1901
2089
  private setMatrixFromParticle;
1902
2090
  }
1903
2091
 
@@ -2019,10 +2207,48 @@ declare class Noise implements Behavior {
2019
2207
  power: FunctionValueGenerator | ValueGenerator;
2020
2208
  positionAmount: FunctionValueGenerator | ValueGenerator;
2021
2209
  rotationAmount: FunctionValueGenerator | ValueGenerator;
2210
+ /**
2211
+ * How fast the noise field moves past the particles (Unity's Scroll
2212
+ * Speed), in noise time per second; 0 leaves it still. Sampled once per
2213
+ * frame, so a curve is read at t = 0.
2214
+ */
2215
+ scrollSpeed: FunctionValueGenerator | ValueGenerator;
2216
+ /**
2217
+ * Reshapes the raw noise (Unity's Remap): the curve is read at the
2218
+ * noise value mapped from [-1, 1] to [0, 1], and what it returns is
2219
+ * used in its place. Unset, the noise is used as is.
2220
+ */
2221
+ remap?: FunctionValueGenerator | undefined;
2022
2222
  type: string;
2023
2223
  duration: number;
2024
- constructor(frequency: FunctionValueGenerator | ValueGenerator, power: FunctionValueGenerator | ValueGenerator, positionAmount?: FunctionValueGenerator | ValueGenerator, rotationAmount?: FunctionValueGenerator | ValueGenerator);
2224
+ constructor(frequency: FunctionValueGenerator | ValueGenerator, power: FunctionValueGenerator | ValueGenerator, positionAmount?: FunctionValueGenerator | ValueGenerator, rotationAmount?: FunctionValueGenerator | ValueGenerator,
2225
+ /**
2226
+ * How fast the noise field moves past the particles (Unity's Scroll
2227
+ * Speed), in noise time per second; 0 leaves it still. Sampled once per
2228
+ * frame, so a curve is read at t = 0.
2229
+ */
2230
+ scrollSpeed?: FunctionValueGenerator | ValueGenerator,
2231
+ /**
2232
+ * Reshapes the raw noise (Unity's Remap): the curve is read at the
2233
+ * noise value mapped from [-1, 1] to [0, 1], and what it returns is
2234
+ * used in its place. Unset, the noise is used as is.
2235
+ */
2236
+ remap?: FunctionValueGenerator | undefined);
2237
+ /** Noise time the field has scrolled by so far. */
2238
+ private scrollOffset;
2239
+ private readonly scrollMemory;
2240
+ /** The noise value a generator gives at `time`, through the remap when there is one. */
2241
+ private sample;
2025
2242
  initialize(particle: Particle): void;
2243
+ /**
2244
+ * Values of the generators that are constants, cached by {@link frameUpdate};
2245
+ * NaN where the generator has to be evaluated per particle.
2246
+ */
2247
+ private _frequency;
2248
+ private _power;
2249
+ private _positionAmount;
2250
+ private _rotationAmount;
2251
+ private static constantOf;
2026
2252
  update(particle: Particle, _: number): void;
2027
2253
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
2028
2254
  toJSON(): any;
@@ -2090,14 +2316,27 @@ declare class RotationBySpeed implements Behavior {
2090
2316
 
2091
2317
  /**
2092
2318
  * Apply rotation to particles over their life.
2319
+ *
2320
+ * A billboard (rotation is an angle) turns in its own plane. A mesh particle
2321
+ * (rotation is a quaternion) turns about its local Z axis — the axis a
2322
+ * number `startRotation` turns a mesh about, and what Unity's Rotation over
2323
+ * Lifetime without separate axes does to mesh particles. For any other axis,
2324
+ * or a turn about all three, use {@link Rotation3DOverLife}.
2093
2325
  */
2094
2326
  declare class RotationOverLife implements Behavior {
2095
2327
  angularVelocity: ValueGenerator | FunctionValueGenerator;
2096
2328
  type: string;
2329
+ /** Scratch for a mesh particle's rotation step; also read by the fused pass. */
2330
+ tempQuat: Quaternion;
2097
2331
  constructor(angularVelocity: ValueGenerator | FunctionValueGenerator);
2098
2332
  initialize(particle: Particle): void;
2099
2333
  update(particle: Particle, delta: number): void;
2100
2334
  updateAll(particles: Array<Particle>, count: number, delta: number): void;
2335
+ /**
2336
+ * Turns a mesh particle by `angle` about its own Z axis, keeping the step
2337
+ * for the renderer to draw a fraction of between simulation steps.
2338
+ */
2339
+ turnAboutZ(particle: Particle, rotation: Quaternion, angle: number): void;
2101
2340
  toJSON(): any;
2102
2341
  static fromJSON(json: any): Behavior;
2103
2342
  frameUpdate(delta: number): void;
@@ -2216,6 +2455,7 @@ declare class TurbulenceField implements Behavior {
2216
2455
  constructor(scale: Vector3, octaves: number, velocityMultiplier: Vector3, timeScale: Vector3);
2217
2456
  initialize(particle: Particle): void;
2218
2457
  update(particle: Particle, delta: number): void;
2458
+ updateAll(particles: Array<Particle>, count: number, delta: number): void;
2219
2459
  toJSON(): any;
2220
2460
  frameUpdate(delta: number): void;
2221
2461
  static fromJSON(json: any): Behavior;
@@ -2237,10 +2477,18 @@ declare class VelocityOverLife implements Behavior {
2237
2477
  orbitalY: FunctionValueGenerator | ValueGenerator;
2238
2478
  orbitalZ: FunctionValueGenerator | ValueGenerator;
2239
2479
  space: VelocityOverLifeSpace;
2480
+ /** Speed away from the orbit centre (Unity's Radial), in the authored space's units. */
2481
+ radial: FunctionValueGenerator | ValueGenerator;
2482
+ /** Where the orbital speeds turn around, relative to the emitter (Unity's Orbital Offset). */
2483
+ orbitalOffset: Vector3;
2240
2484
  type: string;
2241
2485
  /** Learned in {@link initialize}, so undefined until this behavior sees a particle. */
2242
2486
  ps?: IParticleSystem;
2243
- constructor(linearX?: FunctionValueGenerator | ValueGenerator, linearY?: FunctionValueGenerator | ValueGenerator, linearZ?: FunctionValueGenerator | ValueGenerator, orbitalX?: FunctionValueGenerator | ValueGenerator, orbitalY?: FunctionValueGenerator | ValueGenerator, orbitalZ?: FunctionValueGenerator | ValueGenerator, space?: VelocityOverLifeSpace);
2487
+ constructor(linearX?: FunctionValueGenerator | ValueGenerator, linearY?: FunctionValueGenerator | ValueGenerator, linearZ?: FunctionValueGenerator | ValueGenerator, orbitalX?: FunctionValueGenerator | ValueGenerator, orbitalY?: FunctionValueGenerator | ValueGenerator, orbitalZ?: FunctionValueGenerator | ValueGenerator, space?: VelocityOverLifeSpace,
2488
+ /** Speed away from the orbit centre (Unity's Radial), in the authored space's units. */
2489
+ radial?: FunctionValueGenerator | ValueGenerator,
2490
+ /** Where the orbital speeds turn around, relative to the emitter (Unity's Orbital Offset). */
2491
+ orbitalOffset?: Vector3);
2244
2492
  _temp: Vector3;
2245
2493
  _tempEmitterPos: Vector3;
2246
2494
  _tempQ: Quaternion;
@@ -2257,6 +2505,8 @@ declare class VelocityOverLife implements Behavior {
2257
2505
  _axisX: Vector3;
2258
2506
  _axisY: Vector3;
2259
2507
  _axisZ: Vector3;
2508
+ /** The orbit centre in the simulation space, refreshed with the axes. */
2509
+ _center: Vector3;
2260
2510
  initialize(particle: Particle, particleSystem: IParticleSystem): void;
2261
2511
  frameUpdate(delta: number): void;
2262
2512
  update(particle: Particle, delta: number): void;
@@ -2268,13 +2518,29 @@ declare class VelocityOverLife implements Behavior {
2268
2518
  }
2269
2519
 
2270
2520
  /**
2271
- * Apply width to particles based on their length.
2521
+ * Shapes a trail's width along its length — Unity's Width over Trail.
2522
+ *
2523
+ * The curve runs from the head (0) to the tail (1) and, by default, is a
2524
+ * multiplier on the width each sample was recorded with (the particle's
2525
+ * `size.x` at that moment): a curve from 1 to 0 tapers the trail from the
2526
+ * particle's size at the head down to nothing at the tail, whatever that size
2527
+ * is. The head itself gets the curve's value at 0.
2528
+ *
2529
+ * With `absolute` set the curve is the width itself, in world units, ignoring
2530
+ * the particle's size; the head keeps the particle's size. That is how this
2531
+ * behavior read every curve up to 0.21, and an effect JSON written by those
2532
+ * versions (it has no `absolute` field) still loads that way.
2272
2533
  */
2273
2534
  declare class WidthOverLength implements Behavior {
2274
2535
  width: FunctionValueGenerator;
2536
+ absolute: boolean;
2275
2537
  type: string;
2276
2538
  initialize(particle: Particle): void;
2277
- constructor(width: FunctionValueGenerator);
2539
+ /**
2540
+ * @param width - Width along the trail, head (0) to tail (1).
2541
+ * @param absolute - Read `width` as world units instead of a multiplier on the particle's size.
2542
+ */
2543
+ constructor(width: FunctionValueGenerator, absolute?: boolean);
2278
2544
  update(particle: Particle): void;
2279
2545
  frameUpdate(delta: number): void;
2280
2546
  toJSON(): any;
@@ -2946,6 +3212,50 @@ declare class TextureSequencer implements Sequencer {
2946
3212
  fromImage(img: CanvasImageSource, threshold: number): void;
2947
3213
  }
2948
3214
 
3215
+ /**
3216
+ * The one source of randomness for particle simulation.
3217
+ *
3218
+ * Every roll a particle system makes — spawn positions, interval values,
3219
+ * random colours and rotations, burst probability, noise offsets — goes
3220
+ * through {@link random}, so it can be replaced: with a seeded generator for
3221
+ * reproducible tests, replays and lock-step multiplayer, or with a system's own
3222
+ * generator while that system steps (see `ParticleSystem.seed`).
3223
+ *
3224
+ * UUIDs are deliberately not drawn from here; two effects loaded under the same
3225
+ * seed must still get distinct ids.
3226
+ */
3227
+ /** A generator in the shape of `Math.random`: uniform in [0, 1). */
3228
+ type RandomSource = () => number;
3229
+ /** Uniform random number in [0, 1) from the current source. */
3230
+ declare function random(): number;
3231
+ /** The generator {@link random} currently draws from. */
3232
+ declare function getRandomSource(): RandomSource;
3233
+ /**
3234
+ * Replaces the generator every roll draws from; `null` restores `Math.random`.
3235
+ * Returns the previous source, so a caller can put it back.
3236
+ */
3237
+ declare function setRandomSource(next: RandomSource | null): RandomSource;
3238
+ /**
3239
+ * A small, fast seeded generator (mulberry32): the same seed always yields
3240
+ * the same sequence, on every platform. Good enough for visual randomness;
3241
+ * not for anything cryptographic.
3242
+ */
3243
+ declare function createSeededRandom(seed: number): RandomSource;
3244
+ /** Runs `fn` with `generator` as the random source, restoring the previous one after. */
3245
+ declare function withRandomSource<T>(generator: RandomSource, fn: () => T): T;
3246
+
3247
+ /**
3248
+ * The order the particles of a batch are drawn in (Unity's Sort Mode). Alpha
3249
+ * blended particles cover what was drawn before them, so the order shows.
3250
+ *
3251
+ * - `'none'`: as they are, system by system. Right for additive blending.
3252
+ * - `'distance'`: farthest from the active camera first, so nearer particles
3253
+ * cover farther ones.
3254
+ * - `'oldestInFront'` / `'youngestInFront'`: by age.
3255
+ *
3256
+ * Sorting runs over the whole batch after each fill. Trails are not sorted.
3257
+ */
3258
+ type SortMode = 'none' | 'distance' | 'oldestInFront' | 'youngestInFront';
2949
3259
  declare enum RenderMode {
2950
3260
  BillBoard = 0,
2951
3261
  StretchedBillBoard = 1,
@@ -2954,6 +3264,56 @@ declare enum RenderMode {
2954
3264
  HorizontalBillBoard = 4,
2955
3265
  VerticalBillBoard = 5
2956
3266
  }
3267
+ /**
3268
+ * How mesh particles are lit.
3269
+ *
3270
+ * - `'fixed'` (default): one directional light plus ambient, the same for every
3271
+ * mesh batch of a renderer, set with {@link BatchedRenderer.setMeshLighting}.
3272
+ * - `'unlit'`: no lighting term — the texture times the particle colour, for
3273
+ * emissive meshes (fire, energy, glowing blades).
3274
+ * - `'scene'`: follows the scene's first enabled `DirectionalLight` or
3275
+ * `HemisphericLight` every frame, falling back to the fixed light when there
3276
+ * is none.
3277
+ *
3278
+ * Only mesh particles are lit; other render modes ignore it.
3279
+ */
3280
+ type MeshLighting = 'unlit' | 'fixed' | 'scene';
3281
+ /** The light {@link MeshLighting} `'fixed'` mesh particles are lit by. */
3282
+ interface MeshLightingSettings {
3283
+ /** Direction the light travels in, world space. Default `(0.4, -1, 0.6)`. */
3284
+ direction: Vector3$1;
3285
+ /** Light colour, intensity folded in. Default white. */
3286
+ color: Color3;
3287
+ /** Light every face gets regardless of its direction. Default `(0.35, 0.35, 0.35)`. */
3288
+ ambient: Color3;
3289
+ }
3290
+ /** The light mesh particles have always been lit by. */
3291
+ declare function defaultMeshLighting(): MeshLightingSettings;
3292
+ /**
3293
+ * A rim (Fresnel) term on mesh particles: a colour that grows where the surface
3294
+ * turns away from the camera, `pow(1 - |N·V|, power) * strength`. Unset: no rim.
3295
+ * Only mesh particles draw it.
3296
+ */
3297
+ interface MeshRim {
3298
+ /** Edge colour, linear RGB. Default `[1, 1, 1]`. */
3299
+ color: [number, number, number];
3300
+ /** Falloff exponent; higher keeps the rim to a thinner edge. Default 2. */
3301
+ power: number;
3302
+ /** How much of the rim is applied, usually 0…1. Default 1. */
3303
+ strength: number;
3304
+ /**
3305
+ * `'add'` (default) adds the colour, for a glowing edge; `'mix'` blends the
3306
+ * surface toward it, for an outline (a dark ink line with a dark colour).
3307
+ */
3308
+ mode: 'add' | 'mix';
3309
+ }
3310
+ /**
3311
+ * A complete rim from a partial one, every field defaulted and kept in range,
3312
+ * or undefined when `rim` is unset.
3313
+ */
3314
+ declare function normalizeMeshRim(rim: Partial<MeshRim> | null | undefined): MeshRim | undefined;
3315
+ /** True when both describe the same rim (or both none). */
3316
+ declare function meshRimEqual(a: MeshRim | undefined, b: MeshRim | undefined): boolean;
2957
3317
  interface StoredBatchSettings {
2958
3318
  instancingGeometry: Float32Array;
2959
3319
  instancingIndices: Uint32Array | Uint16Array;
@@ -2978,8 +3338,22 @@ interface StoredBatchSettings {
2978
3338
  reflectionFaces: BaseTexture[] | null;
2979
3339
  reflectionAtlas: BaseTexture | null;
2980
3340
  layerMask: number;
3341
+ /** Babylon rendering group the batch mesh draws in, see {@link VFXBatchSettings.renderingGroupId}. */
3342
+ renderingGroupId: number;
3343
+ /** Whether the scene's fog is applied, see {@link VFXBatchSettings.applyFog}. */
3344
+ applyFog: boolean;
2981
3345
  /** Billboard pivot in particle-size units, see {@link VFXBatchSettings.pivot}. */
2982
3346
  pivot?: Vector3;
3347
+ /** Draw order within the batch, see {@link SortMode}. */
3348
+ sortMode: SortMode;
3349
+ /** Smallest size a particle may have on screen, see {@link VFXBatchSettings.minParticleSize}. */
3350
+ minParticleSize: number;
3351
+ /** Largest size a particle may have on screen, see {@link VFXBatchSettings.maxParticleSize}. */
3352
+ maxParticleSize: number;
3353
+ /** Mesh particle lighting, see {@link VFXBatchSettings.lighting}. */
3354
+ lighting?: MeshLighting;
3355
+ /** Mesh particle rim, see {@link VFXBatchSettings.rim}. */
3356
+ rim?: MeshRim;
2983
3357
  }
2984
3358
  declare abstract class VFXBatch {
2985
3359
  mesh: Mesh;
@@ -2987,8 +3361,36 @@ declare abstract class VFXBatch {
2987
3361
  settings: StoredBatchSettings;
2988
3362
  protected maxParticles: number;
2989
3363
  protected scene: Scene;
2990
- private readonly visibleSystems;
3364
+ protected readonly visibleSystems: IParticleSystem[];
2991
3365
  protected constructor(settings: VFXBatchSettings, scene: Scene);
3366
+ /**
3367
+ * Applies the batch-level scene settings to {@link mesh}. Called on every
3368
+ * mesh the batch creates, since the buffers rebuild it.
3369
+ *
3370
+ * The bounds of a batch mesh are not kept, so Babylon cannot sort it among
3371
+ * the scene's transparent meshes by distance; `alphaIndex` from the
3372
+ * system's render order puts it where the author said, and the rendering
3373
+ * group and layer mask reach the mesh at all (they used to stop at the
3374
+ * settings).
3375
+ */
3376
+ protected configureMesh(): void;
3377
+ private readonly boundsMin_;
3378
+ private readonly boundsMax_;
3379
+ /**
3380
+ * Sets the batch mesh's bounds to the union of its filled systems' world
3381
+ * bounds, so Babylon skips the draw when none of them is in view. Called
3382
+ * after each fill, over the systems {@link getVisibleSystems} last returned.
3383
+ * A batch whose systems have no measured bounds stays always drawn.
3384
+ */
3385
+ protected refreshBoundingInfo(): void;
3386
+ /**
3387
+ * Fog defines and uniforms for a material of this batch, and the per-bind
3388
+ * upload of the scene's current fog. Mode 0 (none) when the scene has fog
3389
+ * disabled, so toggling fog at runtime needs no recompile.
3390
+ */
3391
+ protected static readonly FOG_UNIFORMS: string[];
3392
+ protected fogDefines(): string[];
3393
+ protected bindFog(material: ShaderMaterial): void;
2992
3394
  addSystem(system: IParticleSystem): void;
2993
3395
  removeSystem(system: IParticleSystem): void;
2994
3396
  /**
@@ -2998,6 +3400,8 @@ declare abstract class VFXBatch {
2998
3400
  */
2999
3401
  getVisibleSystems(): IParticleSystem[];
3000
3402
  applyDepthTexture(depthTexture: BaseTexture | null): void;
3403
+ /** Sets the light `'fixed'` mesh particles are lit by. Batches that draw no meshes ignore it. */
3404
+ applyMeshLighting(_lighting: MeshLightingSettings): void;
3001
3405
  abstract setupBuffers(): void;
3002
3406
  abstract expandBuffers(target: number): void;
3003
3407
  abstract rebuildMaterial(): void;
@@ -3044,6 +3448,17 @@ interface VFXBatchSettings {
3044
3448
  */
3045
3449
  reflectionAtlas: BaseTexture | null;
3046
3450
  layerMask: number;
3451
+ /**
3452
+ * Babylon rendering group (`mesh.renderingGroupId`) the batch draws in,
3453
+ * 0 by default. Systems with different groups are batched apart.
3454
+ */
3455
+ renderingGroupId: number;
3456
+ /**
3457
+ * Whether the scene's fog applies to the particles, as it does to any other
3458
+ * mesh; true by default. Additive particles fade toward black rather than
3459
+ * the fog colour. Systems that differ are batched apart.
3460
+ */
3461
+ applyFog: boolean;
3047
3462
  /**
3048
3463
  * Offset of billboard quads from their particle, in particle-size units
3049
3464
  * (Unity's renderer Pivot). On billboards x/y move the quad in its own plane
@@ -3052,6 +3467,27 @@ interface VFXBatchSettings {
3052
3467
  * y across, and z is unused. Absent or zero: no offset. Meshes ignore it.
3053
3468
  */
3054
3469
  pivot?: Vector3;
3470
+ /** Draw order within the batch, see {@link SortMode}. Unset is `'none'`. Systems that differ are batched apart. */
3471
+ sortMode?: SortMode;
3472
+ /**
3473
+ * Smallest size a billboard or stretched particle may have on screen, as a
3474
+ * fraction of the viewport height (Unity's Min Particle Size); 0 by default.
3475
+ * Meshes and trails ignore it. Systems that differ are batched apart.
3476
+ */
3477
+ minParticleSize?: number;
3478
+ /**
3479
+ * Largest size a billboard or stretched particle may have on screen, as a
3480
+ * fraction of the viewport height (Unity's Max Particle Size); unlimited by
3481
+ * default. Meshes and trails ignore it. Systems that differ are batched apart.
3482
+ */
3483
+ maxParticleSize?: number;
3484
+ /**
3485
+ * How mesh particles are lit (`'unlit'`, `'fixed'` or `'scene'`); unset is
3486
+ * `'fixed'`. See {@link MeshLighting}. Other render modes ignore it.
3487
+ */
3488
+ lighting?: MeshLighting;
3489
+ /** Rim (Fresnel) term on mesh particles; unset draws none. See {@link MeshRim}. */
3490
+ rim?: MeshRim;
3055
3491
  }
3056
3492
  interface AdaptivePerformanceOptions {
3057
3493
  targetFrameMs: number;
@@ -3094,7 +3530,44 @@ declare class BatchedRenderer extends TransformNode {
3094
3530
  private static readonly EMPTY_BATCH_GRACE_FRAMES;
3095
3531
  private adaptivePerformanceState;
3096
3532
  private lastAppliedQuality;
3533
+ private meshLighting;
3534
+ /**
3535
+ * Whether systems whose {@link ParticleSystem.cullingMode} is not
3536
+ * `'always'` are tested against the active cameras each frame and paused
3537
+ * while unseen. Off, every system simulates every frame; the batches' own
3538
+ * frustum culling of the draw stays on either way.
3539
+ */
3540
+ cullingEnabled: boolean;
3541
+ /**
3542
+ * Time per frame, in milliseconds, that systems coming back into view may
3543
+ * spend together on the steps they missed while culled (`'pauseAndCatchUp'`).
3544
+ * Steps that do not fit are dropped, not deferred, so a crowd of effects
3545
+ * reappearing at once costs at most this. 2 by default.
3546
+ */
3547
+ catchUpBudgetMs: number;
3548
+ /**
3549
+ * Time per frame, in milliseconds, after which the systems still to be
3550
+ * advanced run one step instead of catching up on a long frame. The time
3551
+ * the skipped steps would have covered is dropped, so a frame that already
3552
+ * ran long cannot make the next one longer still. Unlimited by default;
3553
+ * {@link configureAdaptivePerformance} does not set it.
3554
+ */
3555
+ simulationBudgetMs: number;
3556
+ /** Frustum planes of the active cameras, six per camera, rebuilt each update. */
3557
+ private frustumPlanes;
3558
+ private readonly boundsMin;
3559
+ private readonly boundsMax;
3097
3560
  constructor(name: string, scene: Scene);
3561
+ /**
3562
+ * Gathers the frustum planes of the cameras the scene renders with, six per
3563
+ * camera. Empty when there is no camera yet; systems are then never culled.
3564
+ */
3565
+ private collectFrustumPlanes;
3566
+ /**
3567
+ * True when `system`'s world bounds reach into at least one camera's
3568
+ * frustum, or when it has no bounds to test (empty, or not yet measured).
3569
+ */
3570
+ private isSystemInView;
3098
3571
  private static clamp;
3099
3572
  private static equals;
3100
3573
  addSystem(system: IParticleSystem): void;
@@ -3109,6 +3582,20 @@ declare class BatchedRenderer extends TransformNode {
3109
3582
  */
3110
3583
  updateSystem(system: IParticleSystem): void;
3111
3584
  setDepthTexture(depthTexture: BaseTexture | null): void;
3585
+ /**
3586
+ * Sets the light mesh particles with `lighting: 'fixed'` (the default) are
3587
+ * lit by, for every mesh batch of this renderer, including ones created
3588
+ * later. Fields left out keep their current value. Also the fallback for
3589
+ * `'scene'` lighting when the scene has no directional or hemispheric light.
3590
+ *
3591
+ * @example
3592
+ * ```ts
3593
+ * renderer.setMeshLighting({direction: new Vector3(-0.3, -1, 0.2), color: new Color3(1, 0.9, 0.75)});
3594
+ * ```
3595
+ */
3596
+ setMeshLighting(lighting: Partial<MeshLightingSettings>): void;
3597
+ /** A copy of the light set with {@link setMeshLighting}. */
3598
+ getMeshLighting(): MeshLightingSettings;
3112
3599
  configureAdaptivePerformance(options?: Partial<AdaptivePerformanceOptions>): void;
3113
3600
  disableAdaptivePerformance(resetQuality?: boolean): void;
3114
3601
  getAdaptivePerformanceState(): AdaptivePerformanceState;
@@ -3142,6 +3629,63 @@ declare class BatchedRenderer extends TransformNode {
3142
3629
 
3143
3630
  declare const BatchedParticleRenderer: typeof BatchedRenderer;
3144
3631
 
3632
+ interface EffectPoolOptions {
3633
+ /** The renderer every copy the pool makes is added to. */
3634
+ renderer: BatchedRenderer;
3635
+ /** Copies made up front, so the first plays do not pay for cloning. Default 0. */
3636
+ prewarm?: number;
3637
+ /** Most copies the pool will ever hold; {@link EffectPool.acquire} returns null past it. Default unlimited. */
3638
+ maxSize?: number;
3639
+ }
3640
+ /**
3641
+ * A pool of copies of one effect, for effects played many times over: hits,
3642
+ * footsteps, muzzle flashes, pickups.
3643
+ *
3644
+ * {@link acquire} hands out an idle copy (or makes one), places it and plays
3645
+ * it; a copy whose every system has finished goes back to the pool by itself,
3646
+ * so a one-shot effect needs nothing more. A looping effect is ended with
3647
+ * {@link stop}, which lets its particles die out before the copy returns, or
3648
+ * dropped at once with {@link release}.
3649
+ *
3650
+ * Idle copies are parked disabled, which costs the renderer nothing, and keep
3651
+ * their place in its batches, so acquiring one allocates nothing.
3652
+ *
3653
+ * The template itself is never played by the pool; it is only cloned. Disable
3654
+ * it, or keep it out of the renderer, if it is not meant to be seen.
3655
+ */
3656
+ declare class EffectPool {
3657
+ private readonly template;
3658
+ private readonly options;
3659
+ private readonly idle;
3660
+ private readonly playing;
3661
+ private readonly systemsOf;
3662
+ private disposed;
3663
+ constructor(template: TransformNode, options: EffectPoolOptions);
3664
+ /** Copies currently playing. */
3665
+ get activeCount(): number;
3666
+ /** Copies parked and ready. */
3667
+ get idleCount(): number;
3668
+ /**
3669
+ * Takes an idle copy (making one when none is idle and the pool is under
3670
+ * its size), parents it, places it and starts it from the beginning.
3671
+ * Null when the pool is full or disposed.
3672
+ */
3673
+ acquire(position?: Vector3$1, parent?: Node | null): TransformNode | null;
3674
+ /**
3675
+ * Ends the emission of a playing copy; it returns to the pool on its own
3676
+ * once its particles have died, looping systems included.
3677
+ */
3678
+ stop(copy: TransformNode): void;
3679
+ /** Puts a copy back at once, particles and all, parked and disabled. */
3680
+ release(copy: TransformNode): void;
3681
+ /** Disposes every copy, playing or idle. The template is left alone. */
3682
+ dispose(): void;
3683
+ private makeCopy;
3684
+ private disposeCopy;
3685
+ /** The copy a system belongs to is done when all of its systems are. */
3686
+ private readonly onSystemFinished;
3687
+ }
3688
+
3145
3689
  /** Reads the six face URLs from a Babylon CubeTexture (px py pz nx ny nz). */
3146
3690
  declare function cubeFaceUrls(reflection: BaseTexture | null | undefined): string[] | null;
3147
3691
  /** Returns a previously built atlas for this cube, if any. */
@@ -3217,6 +3761,23 @@ interface BurstParameters {
3217
3761
  interval: number;
3218
3762
  probability: number;
3219
3763
  }
3764
+ /**
3765
+ * What a system does while no camera can see its particles (Unity's Culling
3766
+ * Mode). The {@link BatchedRenderer} tests each system's bounds against the
3767
+ * active cameras' frusta every frame.
3768
+ *
3769
+ * - `'always'` keeps simulating off screen, so an effect is exactly where it
3770
+ * would have been when it comes back into view. The default, and the only
3771
+ * safe choice for an emitter whose particles reach the screen from off it.
3772
+ * - `'pause'` freezes the system off screen and resumes it where it left off.
3773
+ * - `'pauseAndCatchUp'` freezes it too, then runs the missed time (up to a few
3774
+ * seconds) within the renderer's catch-up budget when it is seen again.
3775
+ *
3776
+ * An empty system is never culled, so it can start emitting and grow the
3777
+ * bounds that decide its visibility. A system another one emits into is never
3778
+ * culled either; its parent decides.
3779
+ */
3780
+ type CullingMode = 'always' | 'pause' | 'pauseAndCatchUp';
3220
3781
  interface ParticleSystemParameters {
3221
3782
  autoDestroy?: boolean;
3222
3783
  looping?: boolean;
@@ -3265,6 +3826,28 @@ interface ParticleSystemParameters {
3265
3826
  pivot?: Vector3;
3266
3827
  /** Fraction of billboard particles mirrored along U (x) and V (y), see {@link ParticleSystem.flip}. */
3267
3828
  flip?: Vector2;
3829
+ /** How mesh particles are lit, see {@link ParticleSystem.lighting}. Default `'fixed'`. */
3830
+ lighting?: MeshLighting;
3831
+ /** Rim (Fresnel) term on mesh particles, see {@link ParticleSystem.rim}. Default none. */
3832
+ rim?: Partial<MeshRim>;
3833
+ /** Multiplier on the time the system is advanced by, see {@link ParticleSystem.playbackSpeed}. Default 1. */
3834
+ playbackSpeed?: number;
3835
+ /** What the system does while off screen, see {@link CullingMode}. Default `'always'`. */
3836
+ cullingMode?: CullingMode;
3837
+ /** Seed for this system's own random generator, see {@link ParticleSystem.seed}. Default none. */
3838
+ seed?: number;
3839
+ /** Draw order within the batch, see {@link ParticleSystem.sortMode}. Default `'none'`. */
3840
+ sortMode?: SortMode;
3841
+ /** Whether particles start turned along their direction of travel, see {@link ParticleSystem.alignToDirection}. Default false. */
3842
+ alignToDirection?: boolean;
3843
+ /** Smallest on-screen size, as a fraction of the viewport height, see {@link ParticleSystem.minParticleSize}. Default 0. */
3844
+ minParticleSize?: number;
3845
+ /** Largest on-screen size, as a fraction of the viewport height, see {@link ParticleSystem.maxParticleSize}. Default unlimited. */
3846
+ maxParticleSize?: number;
3847
+ /** Babylon rendering group of the batch, see {@link ParticleSystem.renderingGroupId}. Default 0. */
3848
+ renderingGroupId?: number;
3849
+ /** Whether the scene's fog applies, see {@link ParticleSystem.applyFog}. Default true. */
3850
+ applyFog?: boolean;
3268
3851
  scene?: Scene;
3269
3852
  }
3270
3853
  interface BurstParametersJSON {
@@ -3296,6 +3879,24 @@ interface ParticleSystemJSONParameters {
3296
3879
  instancingGeometry?: any;
3297
3880
  renderMode: number;
3298
3881
  renderOrder?: number;
3882
+ /** Written only when not 0. */
3883
+ renderingGroupId?: number;
3884
+ /** Written only when false. */
3885
+ applyFog?: boolean;
3886
+ /** Written only when not 1. */
3887
+ playbackSpeed?: number;
3888
+ /** Written only when not `'always'`. */
3889
+ cullingMode?: CullingMode;
3890
+ /** Written only when set. */
3891
+ seed?: number;
3892
+ /** Written only when not `'none'`. */
3893
+ sortMode?: SortMode;
3894
+ /** Written only when true. */
3895
+ alignToDirection?: boolean;
3896
+ /** Written only when not 0. */
3897
+ minParticleSize?: number;
3898
+ /** Written only when limited. */
3899
+ maxParticleSize?: number;
3299
3900
  speedFactor?: number;
3300
3901
  texture?: string;
3301
3902
  material?: string;
@@ -3392,6 +3993,8 @@ declare class ParticleSystem implements IParticleSystem {
3392
3993
  private previousEmitterPos?;
3393
3994
  private tempEmitterPos;
3394
3995
  private temp;
3996
+ /** Emitter matrix moved along the step's path, see spawnAlongPath. */
3997
+ private pathMatrix;
3395
3998
  private normalMatrix;
3396
3999
  private memory;
3397
4000
  private listeners;
@@ -3404,6 +4007,12 @@ declare class ParticleSystem implements IParticleSystem {
3404
4007
  /** Behaviors the cached plan was built from, compared by identity. */
3405
4008
  private fusionPlan?;
3406
4009
  private fusionSteps;
4010
+ /**
4011
+ * Whether any behavior in the plan can change a particle's size or colour
4012
+ * after birth. Only then does a step have to snapshot them for the renderer.
4013
+ */
4014
+ private planChangesSize;
4015
+ private planChangesColor;
3407
4016
  /** @internal **/
3408
4017
  _renderer?: BatchedRenderer;
3409
4018
  set time(time: number);
@@ -3411,7 +4020,11 @@ declare class ParticleSystem implements IParticleSystem {
3411
4020
  get isEmitEnded(): boolean;
3412
4021
  /** Whether continuous or queued emission can still spawn particles before the system is done. */
3413
4022
  hasPendingEmission(): boolean;
3414
- /** Non-looping system with no particles left and nothing left to emit. */
4023
+ /**
4024
+ * No particles left and nothing left to emit: a non-looping system that
4025
+ * ran its course, or a looping one whose emission was ended with
4026
+ * {@link endEmit} and whose last particle has died.
4027
+ */
3415
4028
  isFinished(): boolean;
3416
4029
  get layers(): {
3417
4030
  mask: number;
@@ -3433,8 +4046,54 @@ declare class ParticleSystem implements IParticleSystem {
3433
4046
  * {@link VFXBatchSettings.pivot}. Assign a new vector to change it: editing
3434
4047
  * the returned one in place does not reach the renderer.
3435
4048
  */
4049
+ /**
4050
+ * The order this system's batch draws its particles in (Unity's Sort
4051
+ * Mode), `'none'` by default. Alpha blended smoke wants `'distance'`;
4052
+ * additive effects need nothing. Sorting covers the whole batch, so systems
4053
+ * with different modes are batched apart. See {@link SortMode}.
4054
+ */
4055
+ get sortMode(): SortMode;
4056
+ set sortMode(mode: SortMode);
4057
+ /**
4058
+ * Smallest size a billboard or stretched particle is drawn at, as a
4059
+ * fraction of the viewport height (Unity's Min Particle Size); 0 by
4060
+ * default. Keeps distant sparks from vanishing. Meshes and trails ignore it.
4061
+ */
4062
+ get minParticleSize(): number;
4063
+ set minParticleSize(size: number);
4064
+ /**
4065
+ * Largest size a billboard or stretched particle is drawn at, as a fraction
4066
+ * of the viewport height (Unity's Max Particle Size, 0.5 there); unlimited
4067
+ * by default. Keeps a close particle from filling the screen. Meshes and
4068
+ * trails ignore it.
4069
+ */
4070
+ get maxParticleSize(): number;
4071
+ set maxParticleSize(size: number);
3436
4072
  get pivot(): Vector3 | undefined;
3437
4073
  set pivot(v: Vector3 | undefined);
4074
+ /**
4075
+ * How mesh particles are lit: `'fixed'` (the default — the renderer's
4076
+ * light, see {@link BatchedRenderer.setMeshLighting}), `'unlit'` (texture
4077
+ * times colour, for emissive meshes) or `'scene'` (the scene's first
4078
+ * directional or hemispheric light). Saved with the material in the effect
4079
+ * JSON. Other render modes ignore it.
4080
+ */
4081
+ get lighting(): MeshLighting;
4082
+ set lighting(lighting: MeshLighting);
4083
+ /**
4084
+ * Rim (Fresnel) term on mesh particles — a glowing edge (`mode: 'add'`) or
4085
+ * an outline (`'mix'`), see {@link MeshRim}. Undefined (the default) draws
4086
+ * none. Fields left out of an assigned rim take their defaults; assign a
4087
+ * new object to change it, editing the returned one does not reach the
4088
+ * renderer. Saved with the material in the effect JSON. Other render modes
4089
+ * ignore it.
4090
+ */
4091
+ get rim(): MeshRim | undefined;
4092
+ set rim(rim: Partial<MeshRim> | undefined);
4093
+ /** `lighting` if it is one of the modes, else the default. */
4094
+ private static validLighting;
4095
+ private static validSortMode;
4096
+ private static validCullingMode;
3438
4097
  private static nonZeroPivot;
3439
4098
  private static nonZeroFlip;
3440
4099
  get softNearFade(): number;
@@ -3449,6 +4108,87 @@ declare class ParticleSystem implements IParticleSystem {
3449
4108
  set renderMode(renderMode: RenderMode);
3450
4109
  get renderOrder(): number;
3451
4110
  set renderOrder(renderOrder: number);
4111
+ /**
4112
+ * Babylon rendering group the particles draw in (`mesh.renderingGroupId`),
4113
+ * 0 by default. Use it to draw an effect after the scene's other transparent
4114
+ * meshes, or before an overlay group.
4115
+ */
4116
+ get renderingGroupId(): number;
4117
+ set renderingGroupId(group: number);
4118
+ /**
4119
+ * Whether the scene's fog applies to the particles, as it does to any other
4120
+ * mesh; true by default. Additive particles fade toward black rather than
4121
+ * the fog colour. Saved in the effect JSON only when switched off.
4122
+ */
4123
+ get applyFog(): boolean;
4124
+ set applyFog(apply: boolean);
4125
+ /**
4126
+ * Multiplier on the time this system is advanced by (Unity's Simulation
4127
+ * Speed): 2 runs the effect twice as fast, 0 freezes it without pausing the
4128
+ * renderer. 1 by default; saved in the effect JSON only when it differs.
4129
+ */
4130
+ playbackSpeed: number;
4131
+ /** What this system does while off screen, see {@link CullingMode}. `'always'` by default. */
4132
+ cullingMode: CullingMode;
4133
+ /**
4134
+ * Whether each particle starts turned along the direction its shape sends
4135
+ * it (Unity's Align To Direction): a mesh particle's +Z is pointed along
4136
+ * the velocity, a billboard's top is turned toward it in the emitter's XY
4137
+ * plane. The start rotation is applied on top. A particle with no speed is
4138
+ * left as it is. False by default.
4139
+ */
4140
+ alignToDirection: boolean;
4141
+ private seedValue?;
4142
+ /** The system's own generator while it steps, when seeded; see {@link seed}. */
4143
+ private rng?;
4144
+ /**
4145
+ * Seed for this system's own random generator. Set, every roll the system
4146
+ * makes while it steps (spawn positions, interval values, random colours
4147
+ * and rotations, burst probability) comes from a generator started from
4148
+ * this seed, and restarted with it on {@link restart}: the effect plays out
4149
+ * identically every time, on every machine — for replays, lock-step
4150
+ * multiplayer and reproducible tests. Systems this one emits into roll on
4151
+ * its generator too. Unset (the default), rolls come from the global source
4152
+ * (`setRandomSource` in quarks.core). Saved in the effect JSON when set.
4153
+ *
4154
+ * Not covered: randomness outside the step, such as a `TurbulenceField`'s
4155
+ * offsets, which are rolled when the behavior is created.
4156
+ */
4157
+ get seed(): number | undefined;
4158
+ set seed(seed: number | undefined);
4159
+ /**
4160
+ * Set by the renderer each frame: true while no active camera sees the
4161
+ * system's bounds and its {@link cullingMode} is not `'always'`.
4162
+ * @internal
4163
+ */
4164
+ culled: boolean;
4165
+ /**
4166
+ * Time a `'pauseAndCatchUp'` system has spent off screen and not yet
4167
+ * simulated, in seconds. Capped, so an effect hidden for a minute does not
4168
+ * replay the minute.
4169
+ */
4170
+ private pendingCatchUp;
4171
+ /**
4172
+ * Time per frame a system coming back into view may spend on the steps it
4173
+ * missed, in milliseconds, when it is advanced without a renderer. The
4174
+ * {@link BatchedRenderer} shares its own budget among all its systems
4175
+ * instead. Steps that do not fit are dropped, not deferred.
4176
+ */
4177
+ static catchUpBudgetMs: number;
4178
+ /** Axis-aligned bounds of the live particles, in simulation space. See {@link getWorldBounds}. */
4179
+ private readonly boundsMin;
4180
+ private readonly boundsMax;
4181
+ /** How far a particle's quad, mesh or stretch can reach past its position, in simulation units. */
4182
+ private boundsPadding;
4183
+ private boundsValid;
4184
+ /** Steps since the last full measurement; between them the bounds are carried and padded. */
4185
+ private stepsSinceBounds;
4186
+ private boundsMaxSize;
4187
+ private boundsMaxSpeedSq;
4188
+ /** True when the bounds are already in world space (a world-space system, or bounds the renderer measured). */
4189
+ private boundsInWorld;
4190
+ private geometryRadiusFor?;
4191
+ private geometryRadius;
3452
4192
  constructor(parameters: ParticleSystemParameters);
3453
4193
  private applyMaterialSettings;
3454
4194
  pause(): void;
@@ -3465,12 +4205,52 @@ declare class ParticleSystem implements IParticleSystem {
3465
4205
  private rebindParticles;
3466
4206
  private growParticlePool;
3467
4207
  private spawn;
4208
+ /** Turns a newborn so that it faces the way its shape sent it; see {@link alignToDirection}. */
4209
+ private alignParticleToDirection;
4210
+ /** Applies the parent particle's inherited properties to a sub emitted newborn; see `EmitSubParticleSystem.inherit`. */
4211
+ private inheritFromParent;
3468
4212
  endEmit(): void;
3469
4213
  dispose(): void;
3470
4214
  restart(): void;
3471
4215
  private firstTimeUpdate;
3472
- /** @internal */
3473
- update(delta: number): void;
4216
+ /**
4217
+ * Advances the system by `delta` seconds of host time.
4218
+ *
4219
+ * `stepDeadline` is a `performance.now()` time after which no further
4220
+ * catch-up step of this frame is run: a frame long enough to need several
4221
+ * steps gets at least one, and the time the rest would have covered is
4222
+ * dropped rather than carried, so one slow frame does not grow the next.
4223
+ * `catchUpDeadline` bounds the steps a `'pauseAndCatchUp'` system runs on
4224
+ * coming back into view; unset, the system allows itself
4225
+ * {@link catchUpBudgetMs}. The renderer supplies both from its budgets.
4226
+ * @internal
4227
+ */
4228
+ update(delta: number, stepDeadline?: number, catchUpDeadline?: number): void;
4229
+ /** Runs the steps a system missed while culled, as many as fit before `deadline`. */
4230
+ private catchUp;
4231
+ /**
4232
+ * Records the bounds the sprite step measured over the live particles.
4233
+ * Trails are measured by their renderer instead, since their ribbons live
4234
+ * outside the store.
4235
+ */
4236
+ private storeBounds;
4237
+ /** Distance of the farthest vertex of the mesh particles' geometry from its origin. */
4238
+ private meshGeometryRadius;
4239
+ /**
4240
+ * World-space axis-aligned bounds of everything this system draws, padded
4241
+ * for particle size, into `min` and `max`. False when the system has no
4242
+ * particles, or none have been measured yet; the caller should then treat
4243
+ * it as visible. Measured in full every few simulated steps and carried,
4244
+ * padded for the motion since, in between: conservative, and at most a
4245
+ * frame behind the display.
4246
+ */
4247
+ getWorldBounds(min: Vector3, max: Vector3): boolean;
4248
+ /**
4249
+ * Records bounds a renderer measured in world space, for systems whose
4250
+ * drawn extent the store does not hold (trail ribbons).
4251
+ * @internal
4252
+ */
4253
+ setWorldBounds(minX: number, minY: number, minZ: number, maxX: number, maxY: number, maxZ: number, padding: number): void;
3474
4254
  /**
3475
4255
  * Time the display is ahead of (positive) or still ahead of the simulation
3476
4256
  * (negative — the simulation ran a hair early), in seconds. Magnitude never
@@ -3510,9 +4290,47 @@ declare class ParticleSystem implements IParticleSystem {
3510
4290
  * change the generated code's indices.
3511
4291
  */
3512
4292
  private behaviorSteps;
3513
- /** Advances emission, behaviors, motion and culling by one fixed timestep. */
4293
+ /**
4294
+ * Advances emission, behaviors, motion and culling by one fixed timestep,
4295
+ * on the system's own random generator when it has a {@link seed}.
4296
+ */
3514
4297
  private simulateStep;
4298
+ private stepOnce;
3515
4299
  private notifyFinished;
4300
+ /** Waves a burst fires per loop: its `cycle`, and never fewer than one. */
4301
+ private static burstWaveCount;
4302
+ /** Seconds between a burst's waves; a missing or negative interval fires them all at once. */
4303
+ private static burstInterval;
4304
+ /**
4305
+ * Fires the burst waves that are due by `emissionState.time`.
4306
+ *
4307
+ * Wave `w` of a burst is due at `burst.time + w * burst.interval`, and the
4308
+ * burst fires `cycle` of them, each rolling `probability` on its own — the
4309
+ * way Unity repeats a burst. Bursts start in time order, as they always
4310
+ * have; their repeats are tracked per burst so a burst that is still
4311
+ * repeating never holds back a later one. Repeats falling past the
4312
+ * system's duration are dropped (a looping system starts them over on its
4313
+ * next loop), matching Unity, which never emits a burst cycle beyond the
4314
+ * end of the duration.
4315
+ */
4316
+ private emitBursts;
4317
+ /** Spawns one wave of `burst`, if its probability roll passes. */
4318
+ private fireBurstWave;
4319
+ /** True while a burst that has started still has a wave due within the duration. */
4320
+ private hasPendingBurstWaves;
4321
+ /**
4322
+ * Spawns `count` particles owed to emission over distance, each where the
4323
+ * emitter crossed its metre mark on the way from `from` to where
4324
+ * `emitterMatrix` has it now, rather than all of them at the end of the
4325
+ * path: a fast emitter then leaves a continuous trail instead of one clump
4326
+ * per step.
4327
+ *
4328
+ * `carried` is how far the emitter had already gone past its last mark
4329
+ * before this step, so the marks keep their spacing across steps. Only the
4330
+ * position is interpolated; the emitter's current rotation and scale are
4331
+ * used for every particle.
4332
+ */
4333
+ private spawnAlongPath;
3516
4334
  emit(delta: number, emissionState: EmissionState, emitterMatrix: Matrix4): void;
3517
4335
  toJSON(metaData?: BabylonMetaData | string, _options?: SerializationOptions): ParticleSystemJSONParameters;
3518
4336
  static fromJSON(json: ParticleSystemJSONParameters, meta: BabylonMetaData, dependencies?: {
@@ -3755,8 +4573,20 @@ declare class QuarksUtil {
3755
4573
  static restart(root: Node): void;
3756
4574
  static setAutoDestroy(root: Node, autoDestroy: boolean): void;
3757
4575
  static endEmit(root: Node): void;
3758
- /** True when every emitter under `root` is a finished non-looping system (or looping). */
4576
+ /**
4577
+ * True when every system under `root` is finished: non-looping ones that
4578
+ * ran their course, looping ones whose emission was ended (see
4579
+ * {@link endEmit}) and whose particles are gone. A looping system still
4580
+ * emitting keeps the effect unfinished.
4581
+ */
3759
4582
  static isEffectFinished(root: Node): boolean;
4583
+ /**
4584
+ * A deep copy of an effect: the node tree under `root` with every particle
4585
+ * system cloned, sub emitter links pointing at the copies, and the same
4586
+ * transforms and enabled state. The copy is not added to any renderer.
4587
+ * Nodes that are neither transform nodes nor emitters are skipped.
4588
+ */
4589
+ static instantiate(root: TransformNode, name?: string): TransformNode;
3760
4590
  private static traverseNode;
3761
4591
  }
3762
4592
 
@@ -3764,21 +4594,21 @@ declare function registerShaderChunks(): void;
3764
4594
  declare function getShaderChunk(chunkName: string): string | undefined;
3765
4595
  declare function getRegisteredShaderChunks(): Readonly<Record<string, string>>;
3766
4596
 
3767
- declare const _default$7: "\nattribute vec3 position;\nattribute vec2 uv;\nattribute vec3 normal;\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute vec4 rotation;\nattribute float uvTile;\n\nuniform mat4 world;\nuniform mat4 view;\nuniform mat4 projection;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\nvarying vec2 vUV;\nvarying vec4 vColor;\nvarying vec3 vNormal;\nvarying vec3 vWorldPos;\n\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n\n#ifdef SOFT_PARTICLES\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\nvec3 applyQuaternion(vec3 v, vec4 q) {\n vec3 qVec = q.xyz;\n float qW = q.w;\n vec3 t = 2.0 * cross(qVec, v);\n return v + qW * t + cross(qVec, t);\n}\n\nvoid main() {\n vec3 scaledPosition = position * size;\n vec3 rotatedPosition = applyQuaternion(scaledPosition, rotation);\n vec3 rotatedNormal = normalize(applyQuaternion(normal, rotation));\n vec3 localPos = rotatedPosition + offset;\n\n vec4 worldPos = world * vec4(localPos, 1.0);\n vec4 viewPos = view * worldPos;\n gl_Position = projection * viewPos;\n\n vWorldPos = worldPos.xyz;\n vNormal = normalize((world * vec4(rotatedNormal, 0.0)).xyz);\n\n#ifdef SOFT_PARTICLES\n projPosition = gl_Position;\n linearDepth = -viewPos.z;\n#endif\n\n#ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = uv / tc + vec2(tileU, tileV);\n #ifdef TILE_BLEND\n float nextTile = ceil(uvTile);\n float nextU = mod(nextTile, tc.x) / tc.x;\n float nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV2 = uv / tc + vec2(nextU, nextV);\n vTileBlend = fract(uvTile);\n #endif\n#else\n vUV = uv;\n#endif\n\n vColor = color;\n}\n";
4597
+ declare const _default$7: string;
3768
4598
 
3769
4599
  declare const _default$6: "\n// Per-vertex attributes\nattribute vec3 position;\nattribute vec2 uv;\n\n// Per-instance attributes\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute vec4 rotation;\nattribute float uvTile;\n\n// Uniforms\nuniform mat4 worldViewProjection;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\n// Varyings\nvarying vec2 vUV;\nvarying vec4 vColor;\n\nvec3 applyQuaternion(vec3 v, vec4 q) {\n vec3 qVec = q.xyz;\n float qW = q.w;\n vec3 t = 2.0 * cross(qVec, v);\n return v + qW * t + cross(qVec, t);\n}\n\nvoid main() {\n vec3 rotatedPosition = applyQuaternion(position * size, rotation);\n vec3 worldPos = rotatedPosition + offset;\n\n gl_Position = worldViewProjection * vec4(worldPos, 1.0);\n\n #ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = uv / tc + vec2(tileU, tileV);\n #else\n vUV = uv;\n #endif\n\n vColor = color;\n}\n";
3770
4600
 
3771
- declare const _default$5: "\nvarying vec2 vUV;\nvarying vec4 vColor;\n\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif\n\n#ifdef SOFT_PARTICLES\nuniform sampler2D depthTexture;\nuniform vec2 softParams;\nuniform vec4 projParams;\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\n#ifdef USE_ALPHATEST\nuniform float alphaTest;\n#endif\n\nvoid main() {\n vec4 baseColor = vColor;\n\n#ifdef USE_MAP\n vec4 texColor = texture2D(map, vUV);\n #ifdef TILE_BLEND\n vec4 texColor2 = texture2D(map, vUV2);\n texColor = mix(texColor, texColor2, vTileBlend);\n #endif\n baseColor *= texColor;\n#endif\n\n#ifdef USE_COLOR_AS_ALPHA\n baseColor.a *= (baseColor.r + baseColor.g + baseColor.b) / 3.0;\n#endif\n\n#ifdef USE_ALPHATEST\n if (baseColor.a < alphaTest) discard;\n#else\n if (baseColor.a < 0.01) discard;\n#endif\n\n gl_FragColor = baseColor;\n\n#ifdef SOFT_PARTICLES\n vec2 p2 = projPosition.xy / projPosition.w;\n p2 = 0.5 * p2 + 0.5;\n float readDepth = texture2D(depthTexture, p2.xy).r;\n float zNear = projParams.x;\n float zFar = projParams.y;\n float viewDepth = (zFar * zNear) / (zFar - readDepth * (zFar - zNear));\n float fade = clamp(softParams.y * ((viewDepth - softParams.x) - linearDepth), 0.0, 1.0);\n gl_FragColor *= fade;\n#endif\n}\n";
4601
+ declare const _default$5: string;
3772
4602
 
3773
- declare const _default$4: "\nvarying vec2 vUV;\nvarying vec4 vColor;\nvarying vec3 vNormal;\nvarying vec3 vWorldPos;\n\nuniform vec3 lightDirection;\nuniform vec3 lightColor;\nuniform vec3 ambientColor;\n\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif\n\n// One 3\u00D72 atlas (px py pz / nx ny nz). Avoids samplerCube and multi-face\n// sampler bindings that raise GL_INVALID_OPERATION on iOS WebKit.\n#ifdef USE_ENVMAP_ATLAS\nuniform sampler2D envAtlas;\nuniform vec3 eyePosition;\nuniform float reflectionLevel;\n\nvec3 sampleEnvAtlas(vec3 r) {\n vec3 a = abs(r);\n vec2 localUV;\n float cellX;\n float cellY;\n // Atlas layout: +X +Y +Z on row 0, -X -Y -Z on row 1.\n if (a.x >= a.y && a.x >= a.z) {\n cellX = 0.0;\n if (r.x >= 0.0) {\n cellY = 0.0;\n localUV = vec2(-r.z, -r.y) / a.x * 0.5 + 0.5;\n } else {\n cellY = 1.0;\n localUV = vec2(r.z, -r.y) / a.x * 0.5 + 0.5;\n }\n } else if (a.y >= a.z) {\n cellX = 1.0;\n if (r.y >= 0.0) {\n cellY = 0.0;\n localUV = vec2(r.x, r.z) / a.y * 0.5 + 0.5;\n } else {\n cellY = 1.0;\n localUV = vec2(r.x, -r.z) / a.y * 0.5 + 0.5;\n }\n } else {\n cellX = 2.0;\n if (r.z >= 0.0) {\n cellY = 0.0;\n localUV = vec2(r.x, -r.y) / a.z * 0.5 + 0.5;\n } else {\n cellY = 1.0;\n localUV = vec2(-r.x, -r.y) / a.z * 0.5 + 0.5;\n }\n }\n vec2 uv = (vec2(cellX, cellY) + clamp(localUV, 0.0, 1.0)) / vec2(3.0, 2.0);\n return texture2D(envAtlas, uv).rgb;\n}\n#endif\n\n#ifdef SOFT_PARTICLES\nuniform sampler2D depthTexture;\nuniform vec2 softParams;\nuniform vec4 projParams;\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\n#ifdef USE_ALPHATEST\nuniform float alphaTest;\n#endif\n\nvoid main() {\n vec4 baseColor = vColor;\n\n#ifdef USE_MAP\n vec4 texColor = texture2D(map, vUV);\n #ifdef TILE_BLEND\n vec4 texColor2 = texture2D(map, vUV2);\n texColor = mix(texColor, texColor2, vTileBlend);\n #endif\n baseColor *= texColor;\n#endif\n\n#ifdef USE_ALPHATEST\n if (baseColor.a < alphaTest) discard;\n#else\n if (baseColor.a < 0.01) discard;\n#endif\n\n vec3 N = normalize(vNormal);\n vec3 L = normalize(-lightDirection);\n float NdotL = max(dot(N, L), 0.0);\n vec3 litColor = ambientColor + lightColor * NdotL;\n\n vec3 color = baseColor.rgb * litColor;\n\n#ifdef USE_ENVMAP_ATLAS\n vec3 viewDir = normalize(vWorldPos - eyePosition);\n vec3 reflectionCoords = reflect(viewDir, N);\n color += sampleEnvAtlas(reflectionCoords) * reflectionLevel;\n#endif\n\n gl_FragColor = vec4(color, baseColor.a);\n\n#ifdef SOFT_PARTICLES\n vec2 p2 = projPosition.xy / projPosition.w;\n p2 = 0.5 * p2 + 0.5;\n float readDepth = texture2D(depthTexture, p2.xy).r;\n float zNear = projParams.x;\n float zFar = projParams.y;\n float viewDepth = (zFar * zNear) / (zFar - readDepth * (zFar - zNear));\n float fade = clamp(softParams.y * ((viewDepth - softParams.x) - linearDepth), 0.0, 1.0);\n gl_FragColor *= fade;\n#endif\n}\n";
4603
+ declare const _default$4: string;
3774
4604
 
3775
- declare const _default$3: "\n// Per-vertex attributes\nattribute vec3 position;\nattribute vec2 uv;\n\n// Per-instance attributes\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute float rotation;\nattribute float uvTile;\n\n// Uniforms\nuniform mat4 world;\nuniform mat4 view;\nuniform mat4 projection;\nuniform mat4 worldViewProjection;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\n#ifdef PIVOT\n// Quad offset in particle-size units: xy in the quad's plane, z toward the camera.\nuniform vec3 pivot;\n#endif\n\n// Varyings\nvarying vec2 vUV;\nvarying vec4 vColor;\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n#ifdef SOFT_PARTICLES\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\nvoid main() {\n float c = cos(rotation);\n float s = sin(rotation);\n\n // A negative size mirrors the quad, which is how flipped particles arrive.\n vec2 alignedPosition = position.xy * size.xy;\n#ifdef PIVOT\n // The pivot turns with the particle but is not mirrored with it.\n alignedPosition += pivot.xy * abs(size.xy);\n#endif\n vec2 rotatedPosition;\n rotatedPosition.x = c * alignedPosition.x - s * alignedPosition.y;\n rotatedPosition.y = s * alignedPosition.x + c * alignedPosition.y;\n\n#ifdef HORIZONTAL\n vec4 mvPosition = world * vec4(offset, 1.0);\n mvPosition.x += rotatedPosition.x;\n mvPosition.z -= rotatedPosition.y;\n#ifdef PIVOT\n mvPosition.y += pivot.z * abs(size.x);\n#endif\n mvPosition = view * mvPosition;\n#elif defined(VERTICAL)\n vec4 mvPosition = world * vec4(offset, 1.0);\n mvPosition.y += rotatedPosition.y;\n mvPosition = view * mvPosition;\n mvPosition.x += rotatedPosition.x;\n#else\n vec4 mvPosition = view * world * vec4(offset, 1.0);\n mvPosition.xy += rotatedPosition;\n#endif\n#ifdef PIVOT\n#ifndef HORIZONTAL\n // Toward the camera along its view axis, whichever way the view space\n // faces: anything in front of the camera has the sign of the far side.\n mvPosition.z -= sign(mvPosition.z) * pivot.z * abs(size.x);\n#endif\n#endif\n\n gl_Position = projection * mvPosition;\n#ifdef SOFT_PARTICLES\n projPosition = gl_Position;\n linearDepth = -mvPosition.z;\n#endif\n\n #ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = uv / tc + vec2(tileU, tileV);\n #ifdef TILE_BLEND\n float nextTile = ceil(uvTile);\n float nextU = mod(nextTile, tc.x) / tc.x;\n float nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV2 = uv / tc + vec2(nextU, nextV);\n vTileBlend = fract(uvTile);\n #endif\n #else\n vUV = uv;\n #endif\n\n vColor = color;\n}\n";
4605
+ declare const _default$3: string;
3776
4606
 
3777
- declare const _default$2: "\n// Per-vertex attributes\nattribute vec3 position;\nattribute vec2 uv;\n\n// Per-instance attributes\nattribute vec3 offset;\nattribute vec4 color;\nattribute vec3 size;\nattribute float rotation;\nattribute float uvTile;\nattribute vec4 velocity;\n\n// Uniforms\nuniform mat4 world;\nuniform mat4 view;\nuniform mat4 projection;\nuniform float speedFactor;\n\n#ifdef UV_TILE\nuniform float tileCountX;\nuniform float tileCountY;\n#endif\n\n#ifdef PIVOT\n// Streak offset in particle-size units: x from head to tail, y across.\nuniform vec3 pivot;\n#endif\n\n// Varyings\nvarying vec2 vUV;\nvarying vec4 vColor;\n#ifdef TILE_BLEND\nvarying vec2 vUV2;\nvarying float vTileBlend;\n#endif\n#ifdef SOFT_PARTICLES\nvarying vec4 projPosition;\nvarying float linearDepth;\n#endif\n\nvoid main() {\n float lengthFactor = velocity.w;\n // A flipped particle arrives with a negative size: the streak keeps its\n // extent and mirrors its texture instead (see quadUV below).\n float avgSize = (abs(size.x) + abs(size.y)) * 0.5;\n vec4 mvPosition = view * world * vec4(offset, 1.0);\n vec3 viewVelocity = mat3(view * world) * velocity.xyz;\n float vlength = length(viewVelocity);\n // Stretch direction is the velocity direction; only a genuinely motionless particle has none.\n // Deriving it via normalize keeps the stretch aligned even when the speed contribution is ~0\n // (e.g. speedFactor 0), instead of collapsing the whole burst onto a fixed screen axis.\n vec3 vdir = vlength > 0.000001 ? viewVelocity / vlength : vec3(0.0, 0.0, 1.0);\n vec3 side = normalize(cross(mvPosition.xyz, vdir));\n mvPosition.xyz += position.y * side * avgSize;\n // Equivalent to viewVelocity * (1.0 + lengthFactor / vlength) for moving particles, but the\n // size-based term (vdir * lengthFactor) survives when the velocity contribution vanishes.\n mvPosition.xyz -= (position.x + 0.5) * (viewVelocity + vdir * lengthFactor) * avgSize;\n#ifdef PIVOT\n // In particle-size units along the quad's own axes: x from head to tail, y across.\n mvPosition.xyz += (pivot.y * side - pivot.x * vdir) * avgSize;\n#endif\n gl_Position = projection * mvPosition;\n vec2 quadUV = vec2(size.x < 0.0 ? 1.0 - uv.x : uv.x, size.y < 0.0 ? 1.0 - uv.y : uv.y);\n#ifdef SOFT_PARTICLES\n projPosition = gl_Position;\n linearDepth = -mvPosition.z;\n#endif\n\n #ifdef UV_TILE\n vec2 tc = vec2(tileCountX, tileCountY);\n float baseTile = floor(uvTile);\n float tileU = mod(baseTile, tc.x) / tc.x;\n float tileV = 1.0 - floor(baseTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV = quadUV / tc + vec2(tileU, tileV);\n #ifdef TILE_BLEND\n float nextTile = ceil(uvTile);\n float nextU = mod(nextTile, tc.x) / tc.x;\n float nextV = 1.0 - floor(nextTile / tc.x) / tc.y - 1.0 / tc.y;\n vUV2 = quadUV / tc + vec2(nextU, nextV);\n vTileBlend = fract(uvTile);\n #endif\n #else\n vUV = quadUV;\n #endif\n\n vColor = color;\n}\n";
4607
+ declare const _default$2: string;
3778
4608
 
3779
- declare const _default$1: "\nvarying vec2 vUV;\nvarying vec4 vColor;\n\n#ifdef USE_MAP\nuniform sampler2D map;\n#endif\n\nvoid main() {\n vec4 baseColor = vColor;\n\n#ifdef USE_MAP\n vec4 texColor = texture2D(map, vUV);\n baseColor *= texColor;\n#endif\n\n if (baseColor.a < 0.01) discard;\n\n gl_FragColor = baseColor;\n}\n";
4609
+ declare const _default$1: string;
3780
4610
 
3781
- declare const _default: "\nattribute vec3 position;\nattribute vec3 previous;\nattribute vec3 next;\nattribute float side;\nattribute float width;\nattribute vec2 uv;\nattribute vec4 color;\n\nuniform mat4 view;\nuniform mat4 projection;\nuniform float lineWidth;\nuniform vec2 resolution;\nuniform float sizeAttenuation;\n\nvarying vec2 vUV;\nvarying vec4 vColor;\n\nvec2 fix(vec4 i, float aspect) {\n vec2 res = i.xy / i.w;\n res.x *= aspect;\n return res;\n}\n\nvoid main() {\n float aspect = resolution.x / resolution.y;\n vec4 finalPosition = projection * view * vec4(position, 1.0);\n vec4 prevPos = projection * view * vec4(previous, 1.0);\n vec4 nextPos = projection * view * vec4(next, 1.0);\n\n vec2 currentP = fix(finalPosition, aspect);\n vec2 prevP = fix(prevPos, aspect);\n vec2 nextP = fix(nextPos, aspect);\n\n float w = lineWidth * width;\n vec2 dir;\n if (distance(nextP, currentP) < 0.0001) {\n dir = normalize(currentP - prevP);\n } else if (distance(prevP, currentP) < 0.0001) {\n dir = normalize(nextP - currentP);\n } else {\n vec2 dir1 = normalize(currentP - prevP);\n vec2 dir2 = normalize(nextP - currentP);\n dir = normalize(dir1 + dir2);\n }\n vec4 normal = vec4(-dir.y, dir.x, 0.0, 1.0);\n normal.xy *= 0.5 * w;\n normal *= projection;\n if (sizeAttenuation == 0.0) {\n normal.xy *= finalPosition.w;\n normal.xy /= (vec4(resolution, 0.0, 1.0) * projection).xy;\n }\n finalPosition.xy += normal.xy * side;\n gl_Position = finalPosition;\n vUV = uv;\n vColor = color;\n}\n";
4611
+ declare const _default: string;
3782
4612
 
3783
4613
  declare class SpriteBatch extends VFXBatch {
3784
4614
  private static whiteTextureByScene;
@@ -3792,6 +4622,10 @@ declare class SpriteBatch extends VFXBatch {
3792
4622
  private velocityBuffer?;
3793
4623
  /** Concretely typed handle on the batch material, see syncStretchedSpeedFactor. */
3794
4624
  private shaderMaterial;
4625
+ /** The `'fixed'` mesh light, as shader uniforms; see applyMeshLighting. */
4626
+ private readonly fixedLightDirection;
4627
+ private readonly fixedLightColor;
4628
+ private readonly fixedAmbientColor;
3795
4629
  private offsetVB;
3796
4630
  private rotationVB;
3797
4631
  private sizeVB;
@@ -3804,7 +4638,33 @@ declare class SpriteBatch extends VFXBatch {
3804
4638
  private disposeExpandableBuffers;
3805
4639
  private buildExpandableBuffers;
3806
4640
  expandBuffers(target: number): void;
4641
+ /** The screen-size limits as a uniform value, or null when the batch has none that apply. */
4642
+ private sizeLimits;
4643
+ private sortScratch?;
4644
+ /** One spare array per attribute buffer, gathered into and swapped in; indexed by buffer slot. */
4645
+ private readonly gatherScratch;
4646
+ /**
4647
+ * Reorders the `count` filled instances by the batch's sort mode, so that
4648
+ * the later (covering) draws are the nearer or the chosen-age particles.
4649
+ * The order is computed once as a permutation and every attribute buffer
4650
+ * is gathered through it into a spare array that then takes its place.
4651
+ */
4652
+ private sortInstances;
4653
+ /** Gathers `source` in `order` into the spare array of `slot` and returns it; the source becomes the spare. */
4654
+ private gatherInto;
3807
4655
  rebuildMaterial(): void;
4656
+ applyMeshLighting(lighting: MeshLightingSettings): void;
4657
+ private storeFixedLighting;
4658
+ private writeFixedLighting;
4659
+ /**
4660
+ * Reads the scene's key light for `'scene'` mesh lighting: the first
4661
+ * enabled directional or hemispheric light, its diffuse colour times its
4662
+ * intensity, plus the scene's ambient colour. A hemispheric light lights
4663
+ * from its `direction` (which points at the sky) and adds its ground colour
4664
+ * to the ambient, which approximates its sky-to-ground blend with the one
4665
+ * directional term the shader has. False when there is no such light.
4666
+ */
4667
+ static readSceneLight(scene: Scene, direction: Vector3$1, color: Vector3$1, ambient: Vector3$1): boolean;
3808
4668
  private vector_;
3809
4669
  private vector2_;
3810
4670
  private vector3_;
@@ -3838,6 +4698,23 @@ declare class SpriteBatch extends VFXBatch {
3838
4698
  * stretched shader reads the sign and mirrors the texture coordinates.
3839
4699
  */
3840
4700
  private static applyFlip;
4701
+ /** The same for a system without a store, read off the particles. */
4702
+ private static applyFlipFromParticles;
4703
+ /**
4704
+ * Writes the mesh rotations for rows `[0, count)` of a store: each
4705
+ * particle's quaternion, carried on by `fraction` of its last turn (see
4706
+ * {@link partialTurn}) and, for a local-space system, turned by the
4707
+ * emitter's rotation `parent`.
4708
+ */
4709
+ private static writeQuaternions;
4710
+ /**
4711
+ * Writes the stretched billboards' velocity attribute for rows `[0, count)`
4712
+ * of a store: the velocity carried on by `fraction` of the last step (see
4713
+ * {@link extrapolate}), turned into world space by `rotation` when the
4714
+ * system simulates locally, scaled by the speed factor, with the length
4715
+ * factor in `w`.
4716
+ */
4717
+ private static writeVelocities;
3841
4718
  /**
3842
4719
  * The fraction `f` of a turn, as a normalised lerp from no rotation toward
3843
4720
  * `step`, written into `out`.
@@ -3901,9 +4778,23 @@ declare class TrailBatch extends VFXBatch {
3901
4778
  private vector2_;
3902
4779
  private vector3_;
3903
4780
  private quaternion_;
3904
- /** Forces the emitter's world matrix to be current before sampling it. */
4781
+ /**
4782
+ * Brings the emitter's world matrix up to date when its transform changed.
4783
+ *
4784
+ * Babylon only recomputes a world matrix once per render id, so a frame that
4785
+ * moves the emitter after that (or a step driven without rendering) would
4786
+ * draw the ribbon against the old one. Recomputing unconditionally every
4787
+ * frame costs a matrix compose per system; checking the transform cache
4788
+ * first makes a still emitter free.
4789
+ */
3905
4790
  private static ensureWorldMatrix;
3906
4791
  update(): void;
4792
+ /**
4793
+ * Records a system's world bounds from the ribbon vertices just written for
4794
+ * it, padded by the widest ribbon. The store only holds each trail's head,
4795
+ * so this is where a trail's extent is known.
4796
+ */
4797
+ private measureSystemBounds;
3907
4798
  /**
3908
4799
  * Uploads the vertex data written by `update` and resizes the sub mesh.
3909
4800
  *
@@ -3925,5 +4816,5 @@ declare class TrailBatch extends VFXBatch {
3925
4816
  dispose(): void;
3926
4817
  }
3927
4818
 
3928
- export { ApplyCollision, ApplyForce, ApplySequences, AxisAngleGenerator, BatchedParticleRenderer, BatchedRenderer, BehaviorFromJSON, BehaviorTypes, Bezier, BoxEmitFrom, BoxEmitter, ChangeEmitDirection, CircleEmitter, ColorBySpeed, ColorGeneratorFromJSON, ColorOverLife, ColorRange, ConeEmitter, ConstantColor, ConstantValue, DEG2RAD, DonutEmitter, EdgeEmitter, EmitSubParticleSystem, EmitterFromJSON, EmitterMode, EmitterShapes, Euler, EulerGenerator, ForceOverLife, FrameOverLife, GeneratorFromJSON, Gradient, GravityForce, GridEmitter, HemisphereEmitter, InheritVelocity, IntervalValue, LimitSpeedOverLife, MathUtils, Matrix3, Matrix4, MeshSurfaceEmitter, MeshSurfaceEmitterPlugin, NodeParticle, Noise, OrbitOverLife, ParticleEmitter, ParticleMeshPhysicsMaterial, ParticleMeshStandardMaterial, ParticleStore, ParticleSystem, PiecewiseBezier, PiecewiseFunction, Plugins, PointEmitter, QuarksLoader, QuarksPrefab, QuarksUtil, Quaternion, RAD2DEG, RandomColor, RandomColorBetweenGradient, RandomQuatGenerator, RecordState, RectangleEmitter, RenderMode, Rotation3DOverLife, RotationBySpeed, RotationGeneratorFromJSON, RotationOverLife, SequencerFromJSON, ShapeTransform, SizeBySpeed, SizeOverLife, SpeedOverLife, SphereEmitter, SpriteBatch, SpriteParticle, SubParticleEmitMode, TextureSequencer, TrailBatch, TrailParticle, TurbulenceField, VFXBatch, ValueGeneratorFromJSON, Vector2, Vector3, Vector3Function, Vector3GeneratorFromJSON, Vector3View, Vector4, Vector4View, VelocityOverLife, WebGLCoordinateSystem, WebGPUCoordinateSystem, WidthOverLength, cacheEnvAtlas, ceilPowerOfTwo, clamp, createEnvAtlasFromFaceUrls, cubeFaceUrls, damp, degToRad, denormalize, ensureEnvAtlasFromCube, euclideanModulo, floorPowerOfTwo, generateUUID, getCachedEnvAtlas, getPhysicsResolver, getRegisteredShaderChunks, getShaderChunk, getValueFromEmitterMode, inverseLerp, isPowerOfTwo, lerp, loadPlugin, _default$7 as localParticlePhysicsVertShader, _default$6 as localParticleVertShader, mapLinear, normalize, _default$5 as particleFragShader, _default$4 as particlePhysicsFragShader, _default$3 as particleVertShader, pingpong, planBehaviorFusion, radToDeg, randFloat, randFloatSpread, randInt, registerShaderChunks, seededRandom, setPhysicsResolver, setQuaternionFromProperEuler, smootherstep, smoothstep, _default$2 as stretchedBillboardVertShader, _default$1 as trailFragShader, _default as trailVertShader, unloadPlugin };
3929
- export type { AdaptivePerformanceOptions, AdaptivePerformanceState, AnimationData, BabylonMetaData, BabylonParticleMaterialParameters, Behavior, BehaviorPlugin, BillBoardSettings, BoxEmitterParameters, BurstParameters, BurstParametersJSON, CircleEmitterParameters, ColorGenerator, ConeEmitterParameters, Constructable, DonutEmitterParameters, EdgeEmitterParameters, EmissionState, EmitterShape, EmitterShapePlugin, EulerOrder, FieldType, FunctionColorGenerator, FunctionJSON, FunctionValueGenerator, FusedPass, FusionStep, GeneratorMemory, GridEmitterParameters, HemisphereEmitterParameters, IAnimationData, IEmitter, IParticle, IParticleSystem, IPrefab, InheritVelocityMode, JsonMetaData, MeshSettings, ParameterPair, ParameterType, Particle, ParticleSystemEvent, ParticleSystemEventType, ParticleSystemJSONParameters, ParticleSystemParameters, Plugin, QuarksBatchLoadOptions, QuarksJSONLoadEntry, QuarksLoaderOptions, QuarksResourceKind, QuarksResourceResolver, QuarksTimelineClip, RectangleEmitterParameters, RendererEmitterSettings, Resource, RotationGenerator, Sequencer, SerializationOptions, ShapeJSON, ShapeTransformJSON, SphereEmitterParameters, StoredBatchSettings, StretchedBillBoardSettings, TrailSettings, VFXBatchSettings, ValueGenerator, Vector3Generator, VelocityOverLifeSpace };
4819
+ export { ApplyCollision, ApplyForce, ApplySequences, AxisAngleGenerator, BatchedParticleRenderer, BatchedRenderer, BehaviorFromJSON, BehaviorTypes, Bezier, BoxEmitFrom, BoxEmitter, ChangeEmitDirection, CircleEmitter, ColorBySpeed, ColorGeneratorFromJSON, ColorOverLife, ColorRange, ConeEmitter, ConstantColor, ConstantValue, DEG2RAD, DonutEmitter, EdgeEmitter, EffectPool, EmitSubParticleSystem, EmitterFromJSON, EmitterMode, EmitterShapes, Euler, EulerGenerator, ForceOverLife, FrameOverLife, GeneratorFromJSON, Gradient, GravityForce, GridEmitter, HemisphereEmitter, InheritVelocity, IntervalValue, LimitSpeedOverLife, MathUtils, Matrix3, Matrix4, MeshSurfaceEmitter, MeshSurfaceEmitterPlugin, NodeParticle, Noise, OrbitOverLife, ParticleEmitter, ParticleMeshPhysicsMaterial, ParticleMeshStandardMaterial, ParticleStore, ParticleSystem, PiecewiseBezier, PiecewiseFunction, Plugins, PointEmitter, QuarksLoader, QuarksPrefab, QuarksUtil, Quaternion, QuaternionView, RAD2DEG, RandomColor, RandomColorBetweenGradient, RandomQuatGenerator, RecordState, RectangleEmitter, RenderMode, Rotation3DOverLife, RotationBySpeed, RotationGeneratorFromJSON, RotationOverLife, SequencerFromJSON, ShapeTransform, SizeBySpeed, SizeOverLife, SpeedOverLife, SphereEmitter, SpriteBatch, SpriteParticle, SubEmitterInheritMask, SubParticleEmitMode, TextureSequencer, TrailBatch, TrailParticle, TurbulenceField, VFXBatch, ValueGeneratorFromJSON, Vector2, Vector3, Vector3Function, Vector3GeneratorFromJSON, Vector3View, Vector4, Vector4View, VelocityOverLife, WebGLCoordinateSystem, WebGPUCoordinateSystem, WidthOverLength, cacheEnvAtlas, ceilPowerOfTwo, clamp, createEnvAtlasFromFaceUrls, createSeededRandom, cubeFaceUrls, damp, defaultMeshLighting, degToRad, denormalize, ensureEnvAtlasFromCube, euclideanModulo, floorPowerOfTwo, generateUUID, getCachedEnvAtlas, getPhysicsResolver, getRandomSource, getRegisteredShaderChunks, getShaderChunk, getValueFromEmitterMode, inverseLerp, isPowerOfTwo, lerp, loadPlugin, _default$7 as localParticlePhysicsVertShader, _default$6 as localParticleVertShader, mapLinear, meshRimEqual, normalize, normalizeMeshRim, _default$5 as particleFragShader, _default$4 as particlePhysicsFragShader, _default$3 as particleVertShader, pingpong, planBehaviorFusion, radToDeg, randFloat, randFloatSpread, randInt, random, registerShaderChunks, seededRandom, setPhysicsResolver, setQuaternionFromProperEuler, setRandomSource, smootherstep, smoothstep, _default$2 as stretchedBillboardVertShader, subEmitterInheritMask, _default$1 as trailFragShader, _default as trailVertShader, unloadPlugin, withRandomSource };
4820
+ export type { AdaptivePerformanceOptions, AdaptivePerformanceState, AnimationData, BabylonMetaData, BabylonParticleMaterialParameters, Behavior, BehaviorPlugin, BillBoardSettings, BoxEmitterParameters, BurstParameters, BurstParametersJSON, CircleEmitterParameters, ColorGenerator, ConeEmitterParameters, Constructable, CullingMode, DonutEmitterParameters, EdgeEmitterParameters, EffectPoolOptions, EmissionState, EmitterShape, EmitterShapePlugin, EulerOrder, FieldType, FunctionColorGenerator, FunctionJSON, FunctionValueGenerator, FusedPass, FusionStep, GeneratorMemory, GridEmitterParameters, HemisphereEmitterParameters, IAnimationData, IEmitter, IParticle, IParticleSystem, IPrefab, InheritVelocityMode, JsonMetaData, MeshLighting, MeshLightingSettings, MeshRim, MeshSettings, ParameterPair, ParameterType, Particle, ParticleSystemEvent, ParticleSystemEventType, ParticleSystemJSONParameters, ParticleSystemParameters, Plugin, QuarksBatchLoadOptions, QuarksJSONLoadEntry, QuarksLoaderOptions, QuarksResourceKind, QuarksResourceResolver, QuarksTimelineClip, RandomSource, RectangleEmitterParameters, RendererEmitterSettings, Resource, RotationGenerator, Sequencer, SerializationOptions, ShapeJSON, ShapeTransformJSON, SortMode, SphereEmitterParameters, StoredBatchSettings, StretchedBillBoardSettings, SubEmitterInheritance, TrailSettings, VFXBatchSettings, ValueGenerator, Vector3Generator, VelocityOverLifeSpace };