@needle-tools/engine 2.42.0-pre → 2.44.0-pre

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 (62) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/needle-engine.d.ts +224 -81
  3. package/dist/needle-engine.js +3836 -422
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +40 -40
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/lib/engine/engine_element_loading.js +22 -6
  8. package/lib/engine/engine_element_loading.js.map +1 -1
  9. package/lib/engine/engine_input.js +17 -6
  10. package/lib/engine/engine_input.js.map +1 -1
  11. package/lib/engine/engine_serialization_builtin_serializer.js +60 -58
  12. package/lib/engine/engine_serialization_builtin_serializer.js.map +1 -1
  13. package/lib/engine/engine_three_utils.d.ts +1 -0
  14. package/lib/engine/engine_three_utils.js +10 -0
  15. package/lib/engine/engine_three_utils.js.map +1 -1
  16. package/lib/engine/engine_time.js +2 -0
  17. package/lib/engine/engine_time.js.map +1 -1
  18. package/lib/engine/extensions/NEEDLE_techniques_webgl.js +42 -0
  19. package/lib/engine/extensions/NEEDLE_techniques_webgl.js.map +1 -1
  20. package/lib/engine-components/Animation.d.ts +3 -1
  21. package/lib/engine-components/Animation.js +25 -1
  22. package/lib/engine-components/Animation.js.map +1 -1
  23. package/lib/engine-components/AnimatorController.js +4 -1
  24. package/lib/engine-components/AnimatorController.js.map +1 -1
  25. package/lib/engine-components/Camera.d.ts +3 -0
  26. package/lib/engine-components/Camera.js +17 -9
  27. package/lib/engine-components/Camera.js.map +1 -1
  28. package/lib/engine-components/ParticleSystem.d.ts +33 -7
  29. package/lib/engine-components/ParticleSystem.js +464 -249
  30. package/lib/engine-components/ParticleSystem.js.map +1 -1
  31. package/lib/engine-components/ParticleSystemBehaviours.d.ts +0 -0
  32. package/lib/engine-components/ParticleSystemBehaviours.js +2 -0
  33. package/lib/engine-components/ParticleSystemBehaviours.js.map +1 -0
  34. package/lib/engine-components/ParticleSystemModules.d.ts +123 -20
  35. package/lib/engine-components/ParticleSystemModules.js +461 -63
  36. package/lib/engine-components/ParticleSystemModules.js.map +1 -1
  37. package/lib/engine-components/WebXRController.d.ts +1 -0
  38. package/lib/engine-components/WebXRController.js +2 -1
  39. package/lib/engine-components/WebXRController.js.map +1 -1
  40. package/lib/engine-components/codegen/components.d.ts +6 -0
  41. package/lib/engine-components/codegen/components.js +6 -0
  42. package/lib/engine-components/codegen/components.js.map +1 -1
  43. package/lib/engine-components/js-extensions/RGBAColor.d.ts +1 -0
  44. package/lib/engine-components/js-extensions/RGBAColor.js +7 -0
  45. package/lib/engine-components/js-extensions/RGBAColor.js.map +1 -1
  46. package/package.json +2 -1
  47. package/src/engine/codegen/register_types.js +24 -0
  48. package/src/engine/engine_element_loading.ts +22 -5
  49. package/src/engine/engine_input.ts +16 -7
  50. package/src/engine/engine_serialization_builtin_serializer.ts +59 -57
  51. package/src/engine/engine_three_utils.ts +11 -2
  52. package/src/engine/engine_time.ts +1 -0
  53. package/src/engine/extensions/NEEDLE_techniques_webgl.ts +43 -1
  54. package/src/engine-components/Animation.ts +18 -2
  55. package/src/engine-components/AnimatorController.ts +5 -1
  56. package/src/engine-components/Camera.ts +17 -10
  57. package/src/engine-components/ParticleSystem.ts +526 -303
  58. package/src/engine-components/ParticleSystemBehaviours.ts +0 -0
  59. package/src/engine-components/ParticleSystemModules.ts +408 -66
  60. package/src/engine-components/WebXRController.ts +2 -1
  61. package/src/engine-components/codegen/components.ts +6 -0
  62. package/src/engine-components/js-extensions/RGBAColor.ts +7 -0
@@ -1,11 +1,12 @@
1
1
  import { init } from "@dimforge/rapier3d-compat";
2
2
  import * as THREE from "three";
3
- import { Color, Matrix4, Object3D, Vector3 } from "three";
3
+ import { Color, Matrix4, Object3D, PointLightShadow, Quaternion, Vector3 } from "three";
4
4
  import { Mathf } from "../engine/engine_math";
5
5
  import { serializeable } from "../engine/engine_serialization";
6
6
  import { RGBAColor } from "./js-extensions/RGBAColor";
7
7
  import { AnimationCurve } from "./AnimationCurve";
8
- import { Vec3 } from "../engine/engine_types";
8
+ import { Vec2, Vec3 } from "../engine/engine_types";
9
+ import { EmitterShape, FrameOverLife, Particle, ShapeJSON } from "three.quarks";
9
10
 
10
11
  declare type Color4 = { r: number, g: number, b: number, a: number };
11
12
  declare type ColorKey = { time: number, color: Color4 };
@@ -17,6 +18,10 @@ export interface IParticleSystem {
17
18
  get time(): number;
18
19
  get duration(): number;
19
20
  readonly main: MainModule;
21
+ get container(): Object3D;
22
+ get worldQuaternion(): Quaternion;
23
+ get worldQuaternionInverted(): Quaternion;
24
+ get worldScale() : Vector3;
20
25
  }
21
26
 
22
27
  export enum ParticleSystemRenderMode {
@@ -165,14 +170,14 @@ export class MinMaxCurve {
165
170
  case ParticleSystemCurveMode.Constant:
166
171
  return this.constant;
167
172
  case ParticleSystemCurveMode.Curve:
168
- t01 %= this.curve!.duration;
169
- return this.curve!.evaluate(t01);
173
+ t01 = Mathf.clamp01(t01);
174
+ return this.curve!.evaluate(t01) * this.curveMultiplier!;
170
175
  case ParticleSystemCurveMode.TwoCurves:
171
176
  const t1 = t01 * this.curveMin!.duration;
172
177
  const t2 = t01 * this.curveMax!.duration;
173
- return Mathf.lerp(this.curveMin!.evaluate(t1), this.curveMax!.evaluate(t2), t % 1);
178
+ return Mathf.lerp(this.curveMin!.evaluate(t1), this.curveMax!.evaluate(t2), t % 1) * this.curveMultiplier!;
174
179
  case ParticleSystemCurveMode.TwoConstants:
175
- return Mathf.lerp(this.constantMin, this.constantMax, t % 1);
180
+ return Mathf.lerp(this.constantMin, this.constantMax, t % 1)
176
181
  default:
177
182
  this.curveMax!.evaluate(t01) * this.curveMultiplier!;
178
183
  break;
@@ -208,7 +213,8 @@ export class MinMaxGradient {
208
213
  this.gradient.evaluate(t01, MinMaxGradient._temp);
209
214
  return MinMaxGradient._temp
210
215
  case ParticleSystemGradientMode.TwoColors:
211
- return MinMaxGradient._temp.lerpColors(this.colorMin, this.colorMax, t);
216
+ const col1 = MinMaxGradient._temp.lerpColors(this.colorMin, this.colorMax, t);
217
+ return col1;
212
218
  case ParticleSystemGradientMode.TwoGradients:
213
219
  const t2 = Math.random();
214
220
  this.gradientMin.evaluate(t2, MinMaxGradient._temp);
@@ -372,38 +378,23 @@ export class EmissionModule {
372
378
 
373
379
  /** set from system */
374
380
  system!: IParticleSystem;
375
- get time() { return this.system.time; }
376
381
 
377
- private _summed: number = 0;
378
- // private _didEmit: boolean = false;
379
-
380
- /** called by nebula */
381
- init() {
382
+ reset() {
383
+ this.bursts?.forEach(b => b.reset());
382
384
  }
383
385
 
384
- /** called by nebula */
385
- getValue(deltaTime: number) {
386
- if (this.system.currentParticles >= this.system.maxParticles)
387
- return 0;
388
- if (!this.enabled) return 0;
389
- let count = this.rateOverTime.evaluate(this.time / this.system.duration, Math.random());
390
- this._summed += count * deltaTime;
391
- let amount = Math.floor(this._summed);
392
- this._summed -= amount;
393
-
386
+ getBurst() {
387
+ let amount = 0;
394
388
  if (this.burstCount > 0) {
395
389
  for (let i = 0; i < this.burstCount; i++) {
396
390
  const burst = this.bursts[i];
397
- if (burst.time >= this.time) {
391
+ if (burst.time >= this.system.time) {
398
392
  burst.reset();
399
- continue;
400
393
  }
401
- amount += Math.round(burst.run(this.time));
394
+ amount += Math.round(burst.run(this.system.time));
402
395
  }
403
396
  }
404
-
405
- // dont emit more than we are allowed to
406
- return amount;//Mathf.clamp(amount, 0, this.system.maxParticles - this.system.currentParticles);
397
+ return amount;
407
398
  }
408
399
  }
409
400
 
@@ -420,18 +411,26 @@ export class SizeOverLifetimeModule {
420
411
  size!: MinMaxCurve;
421
412
  sizeMultiplier!: number;
422
413
  @serializeable(MinMaxCurve)
423
- sizeX!: MinMaxCurve;
424
- sizeXMultiplier!: number;
414
+ x!: MinMaxCurve;
415
+ xMultiplier!: number;
425
416
  @serializeable(MinMaxCurve)
426
- sizeY!: MinMaxCurve;
427
- sizeYMultiplier!: number;
417
+ y!: MinMaxCurve;
418
+ yMultiplier!: number;
428
419
  @serializeable(MinMaxCurve)
429
- sizeZ!: MinMaxCurve;
430
- sizeZMultiplier!: number;
420
+ z!: MinMaxCurve;
421
+ zMultiplier!: number;
431
422
 
432
423
  private _time: number = 0;
424
+ private _temp = new Vector3();
425
+
426
+ evaluate(t01: number, target?: Vec3) {
427
+ if (!target) target = this._temp;
428
+
429
+ if (!this.enabled) {
430
+ target.x = target.y = target.z = 1;
431
+ return target;
432
+ }
433
433
 
434
- evaluate(t01: number, target: Vec3) {
435
434
  if (!this.separateAxes) {
436
435
  const scale = this.size.evaluate(t01) * this.sizeMultiplier;
437
436
  target.x = scale;
@@ -439,15 +438,31 @@ export class SizeOverLifetimeModule {
439
438
  // target.z = scale;
440
439
  }
441
440
  else {
442
- target.x = this.sizeX.evaluate(this._time) * this.sizeXMultiplier;
443
- // target.y = this.sizeY.evaluate(this._time) * this.sizeYMultiplier;
444
- // target.z = this.sizeZ.evaluate(this._time) * this.sizeZMultiplier;
441
+ target.x = this.x.evaluate(t01) * this.xMultiplier;
442
+ target.y = this.y.evaluate(t01) * this.yMultiplier;
443
+ target.z = this.z.evaluate(t01) * this.zMultiplier;
445
444
  }
446
445
  return target;
447
446
  }
448
447
  }
449
448
 
450
- export class ShapeModule {
449
+ export class ShapeModule implements EmitterShape {
450
+
451
+ get type(): string {
452
+ return ParticleSystemShapeType[this.shapeType];
453
+ }
454
+
455
+ initialize(particle: Particle): void {
456
+ this.getPosition();
457
+ particle.position.copy(this._vector);
458
+ }
459
+ toJSON(): ShapeJSON {
460
+ return this;
461
+ }
462
+ clone(): EmitterShape {
463
+ return new ShapeModule();
464
+ }
465
+
451
466
  @serializeable()
452
467
  shapeType: ParticleSystemShapeType = ParticleSystemShapeType.Box;
453
468
  @serializeable()
@@ -479,17 +494,21 @@ export class ShapeModule {
479
494
  @serializeable()
480
495
  sphericalDirectionAmount!: number;
481
496
 
497
+ private system! : IParticleSystem;
482
498
  private _space?: ParticleSystemSimulationSpace;
483
- private readonly _worldSpacePosition: Matrix4 = new Matrix4();
499
+ private readonly _worldSpaceMatrix: Matrix4 = new Matrix4();
500
+ private readonly _worldSpaceMatrixInverse: Matrix4 = new Matrix4();
484
501
 
485
- update(_context: Context, simulationSpace: ParticleSystemSimulationSpace, obj: Object3D) {
502
+ update(system : IParticleSystem, _context: Context, simulationSpace: ParticleSystemSimulationSpace, obj: Object3D) {
503
+ this.system = system;
486
504
  this._space = simulationSpace;
487
505
  if (simulationSpace === ParticleSystemSimulationSpace.World) {
488
- this._worldSpacePosition.copy(obj.matrixWorld);
506
+ this._worldSpaceMatrix.copy(obj.matrixWorld);
489
507
  // set scale to 1
490
- this._worldSpacePosition.elements[0] = 1;
491
- this._worldSpacePosition.elements[5] = 1;
492
- this._worldSpacePosition.elements[10] = 1;
508
+ this._worldSpaceMatrix.elements[0] = 1;
509
+ this._worldSpaceMatrix.elements[5] = 1;
510
+ this._worldSpaceMatrix.elements[10] = 1;
511
+ this._worldSpaceMatrixInverse.copy(this._worldSpaceMatrix).invert();
493
512
  }
494
513
  }
495
514
 
@@ -502,7 +521,6 @@ export class ShapeModule {
502
521
  get vector() {
503
522
  return this._vector;
504
523
  }
505
- /** called by nebula */
506
524
  getPosition(): void {
507
525
  switch (this.shapeType) {
508
526
  case ParticleSystemShapeType.Box:
@@ -511,14 +529,18 @@ export class ShapeModule {
511
529
  this._vector.z = Math.random() * this.scale.z - this.scale.z / 2;
512
530
  break;
513
531
  case ParticleSystemShapeType.Sphere:
514
- randomSpherePoint(this.position.x, this.position.y, this.position.z, this.radius, this.radiusThickness, this.arc, this._vector);
532
+ randomSpherePoint(this.position.x, this.position.y, this.position.z, this.radius * this.system.worldScale.x, this.radiusThickness, this.arc, this._vector);
533
+ // this._vector.y += 1;
534
+ break;
535
+ default:
536
+ this._vector.set(0, 0, 0);
515
537
  break;
516
538
  // case ParticleSystemShapeType.Hemisphere:
517
539
  // randomSpherePoint(this.position.x, this.position.y, this.position.z, this.radius, this.radiusThickness, 180, this._vector);
518
540
  // break;
519
541
  }
520
542
  if (this._space === ParticleSystemSimulationSpace.World) {
521
- this._vector.applyMatrix4(this._worldSpacePosition);
543
+ this._vector.applyMatrix4(this._worldSpaceMatrix);
522
544
  }
523
545
  }
524
546
 
@@ -528,14 +550,24 @@ export class ShapeModule {
528
550
  getDirection(position): Vector3 {
529
551
  switch (this.shapeType) {
530
552
  case ParticleSystemShapeType.Box:
531
- return this._dir.set(0, 0, 1);
553
+ this._dir.set(0, 0, 1);
554
+ break;
532
555
  case ParticleSystemShapeType.Sphere:
533
556
  const rx = position.x;
534
557
  const ry = position.y;
535
558
  const rz = position.z;
536
- return this._dir.set(rx, ry, rz).normalize();
559
+ this._dir.set(rx, ry, rz);
560
+ break;
561
+ default:
562
+ this._dir.set(0, 0, 1);
563
+ break;
537
564
  }
538
- return this._dir.set(0, 1, 0);
565
+ if (this._space === ParticleSystemSimulationSpace.World) {
566
+ this._dir.applyMatrix4(this._worldSpaceMatrixInverse);
567
+ }
568
+ this._dir.normalize();
569
+ // Gizmos.DrawDirection(position, this._dir, 0xff0000, .5);
570
+ return this._dir;
539
571
  }
540
572
  }
541
573
 
@@ -559,6 +591,8 @@ function randomSpherePoint(x0: number, y0: number, z0: number, radius: number, t
559
591
 
560
592
  import { createNoise4D, NoiseFunction4D } from 'simplex-noise';
561
593
  import { Context } from "../engine/engine_setup";
594
+ import { getWorldQuaternion } from "../engine/engine_three_utils";
595
+ import { Gizmos } from "../engine/engine_gizmos";
562
596
 
563
597
  export class NoiseModule {
564
598
  @serializeable()
@@ -626,34 +660,342 @@ export class NoiseModule {
626
660
 
627
661
  /** nebula implementations: */
628
662
  private _temp: Vector3 = new Vector3();
629
- applyNoise(index: number, pos: Vec3, vel: Vec3, deltaTime: number, age: number, life: number) {
663
+ apply(_index: number, pos: Vec3, vel: Vec3, _deltaTime: number, age: number, life: number) {
630
664
  if (!this.enabled) return;
631
665
  if (!this._noise) {
632
666
  this._noise = createNoise4D(() => 0);
633
667
  }
634
- const t = age / life;
635
- const dt = Context.Current.time.deltaTime;
636
668
  const temp = this._temp.set(pos.x, pos.y, pos.z).multiplyScalar(this.frequency);
637
669
  const nx = this._noise(temp.x, temp.y, temp.z, this._time);
638
- const ny = this._noise(temp.x, temp.y, temp.z, this._time + .2);
639
- const nz = this._noise(temp.x, temp.y, temp.z, this._time + .5);
640
- this._temp.set(nx, ny, nz).normalize();
670
+ const ny = this._noise(temp.x, temp.y, temp.z, this._time + .3);
671
+ const nz = this._noise(temp.x, temp.y, temp.z, this._time + 1);
672
+ this._temp.set(nx, ny, nz).normalize()
641
673
 
674
+ const t = age / life;
642
675
  let strengthFactor = this.positionAmount.evaluate(t);
643
676
  if (!this.separateAxes) {
644
- if (this.strengthX)
645
- strengthFactor *= this.strengthX.evaluate(t, index * 1.1);
646
- else strengthFactor *= this.strengthMultiplier;
647
- strengthFactor *= deltaTime;
677
+ if (this.strengthX) {
678
+ strengthFactor *= this.strengthX.evaluate(t) * Math.PI;
679
+ }
680
+ // strengthFactor *= this.strengthMultiplier;
681
+ // strengthFactor *= deltaTime;
648
682
  this._temp.multiplyScalar(strengthFactor);
649
683
  }
650
- if (this.separateAxes) {
651
- this._temp.x *= strengthFactor * deltaTime * this.strengthXMultiplier
652
- this._temp.y *= strengthFactor * deltaTime * this.strengthYMultiplier;
653
- this._temp.z *= strengthFactor * deltaTime * this.strengthZMultiplier;
684
+ else {
685
+ this._temp.x *= strengthFactor * this.strengthXMultiplier
686
+ this._temp.y *= strengthFactor * this.strengthYMultiplier;
687
+ this._temp.z *= strengthFactor * this.strengthZMultiplier;
688
+ }
689
+ // this._temp.setLength(strengthFactor * deltaTime);
690
+ vel.x += this._temp.x;
691
+ vel.y += this._temp.y;
692
+ vel.z += this._temp.z;
693
+ }
694
+ }
695
+
696
+ export class TrailModule {
697
+
698
+ @serializeable()
699
+ enabled!: boolean;
700
+ }
701
+
702
+ export class VelocityOverLifetimeModule {
703
+ @serializeable()
704
+ enabled!: boolean;
705
+
706
+ /* orbital settings */
707
+
708
+
709
+ @serializeable()
710
+ space: ParticleSystemSimulationSpace = ParticleSystemSimulationSpace.Local;
711
+
712
+ @serializeable(MinMaxCurve)
713
+ speedModifier!: MinMaxCurve;
714
+ @serializeable()
715
+ speedModifierMultiplier!: number;
716
+ @serializeable(MinMaxCurve)
717
+ x!: MinMaxCurve;
718
+ @serializeable()
719
+ xMultiplier!: number;
720
+ @serializeable(MinMaxCurve)
721
+ y!: MinMaxCurve;
722
+ @serializeable()
723
+ yMultiplier!: number;
724
+ @serializeable(MinMaxCurve)
725
+ z!: MinMaxCurve;
726
+ @serializeable()
727
+ zMultiplier!: number;
728
+
729
+ private _system?: IParticleSystem;
730
+ // private _worldRotation: Quaternion = new Quaternion();
731
+
732
+ update(system: IParticleSystem) {
733
+ this._system = system;
734
+ }
735
+
736
+ private _temp: Vector3 = new Vector3();
737
+
738
+ apply(_index: number, _pos: Vec3, vel: Vec3, _dt: number, age: number, life: number) {
739
+ if (!this.enabled) return;
740
+ const t = age / life;
741
+
742
+ const speed = this.speedModifier.evaluate(t) * this.speedModifierMultiplier;
743
+ const x = this.x.evaluate(t) * speed;
744
+ const y = this.y.evaluate(t) * speed;
745
+ const z = this.z.evaluate(t) * speed;
746
+ this._temp.set(-x, y, z);
747
+ if (this._system) {
748
+ if (this.space === ParticleSystemSimulationSpace.World) {
749
+ this._temp.applyQuaternion(this._system.worldQuaternionInverted);
750
+ }
751
+ if (this._system.main.simulationSpace === ParticleSystemSimulationSpace.World) {
752
+ this._temp.applyQuaternion(this._system.worldQuaternion);
753
+ }
654
754
  }
655
755
  vel.x += this._temp.x;
656
756
  vel.y += this._temp.y;
657
757
  vel.z += this._temp.z;
658
758
  }
759
+ }
760
+
761
+
762
+
763
+ enum ParticleSystemAnimationTimeMode {
764
+ Lifetime,
765
+ Speed,
766
+ FPS,
767
+ }
768
+
769
+ enum ParticleSystemAnimationMode {
770
+ Grid,
771
+ Sprites,
772
+ }
773
+
774
+ enum ParticleSystemAnimationRowMode {
775
+ Custom,
776
+ Random,
777
+ MeshIndex,
778
+ }
779
+
780
+ enum ParticleSystemAnimationType {
781
+ WholeSheet,
782
+ SingleRow,
783
+ }
784
+
785
+ export class TextureSheetAnimationModule {
786
+
787
+ @serializeable()
788
+ animation!: ParticleSystemAnimationType;
789
+
790
+ @serializeable()
791
+ enabled!: boolean;
792
+
793
+ @serializeable()
794
+ cycleCount!: number;
795
+
796
+ @serializeable(MinMaxCurve)
797
+ frameOverTime!: MinMaxCurve;
798
+ @serializeable()
799
+ frameOverTimeMultiplier!: number;
800
+
801
+ @serializeable()
802
+ numTilesX!: number;
803
+ @serializeable()
804
+ numTilesY!: number;
805
+
806
+ @serializeable(MinMaxCurve)
807
+ startFrame!: MinMaxCurve;
808
+ @serializeable()
809
+ startFrameMultiplier!: number;
810
+
811
+ @serializeable()
812
+ rowMode!: ParticleSystemAnimationRowMode;
813
+ @serializeable()
814
+ rowIndex!: number;
815
+
816
+ @serializeable()
817
+ spriteCount!: number;
818
+
819
+ @serializeable()
820
+ timeMode!: ParticleSystemAnimationTimeMode;
821
+
822
+ private sampleOnceAtStart(): boolean {
823
+ if (this.timeMode === ParticleSystemAnimationTimeMode.Lifetime) {
824
+ switch (this.frameOverTime.mode) {
825
+ case ParticleSystemCurveMode.Constant:
826
+ case ParticleSystemCurveMode.TwoConstants:
827
+ return true;
828
+ }
829
+ }
830
+ return false;
831
+ }
832
+
833
+ getStartIndex(): number {
834
+ if (this.sampleOnceAtStart()) {
835
+ return this.frameOverTime.evaluate(Math.random())
836
+ }
837
+ return 0;
838
+ }
839
+
840
+ evaluate(t01: number): number | undefined {
841
+ if (this.sampleOnceAtStart()) {
842
+ return;
843
+ }
844
+ return this.getIndex(t01);
845
+ }
846
+
847
+ private getIndex(t01: number): number {
848
+ const tiles = this.numTilesX * this.numTilesY;
849
+ // let pos = t01 * this.cycleCount;
850
+ let index = this.frameOverTime.evaluate(t01 % 1);
851
+ index *= this.frameOverTimeMultiplier;
852
+ index *= tiles;
853
+ index = index % tiles;
854
+ index = Math.floor(index);
855
+ // console.log(index);
856
+ return index;
857
+ }
858
+ }
859
+
860
+
861
+ export class RotationOverLifetimeModule {
862
+ @serializeable()
863
+ enabled!: boolean;
864
+
865
+ @serializeable()
866
+ separateAxes!: boolean;
867
+
868
+ @serializeable(MinMaxCurve)
869
+ x!: MinMaxCurve;
870
+ @serializeable()
871
+ xMultiplier!: number;
872
+ @serializeable(MinMaxCurve)
873
+ y!: MinMaxCurve;
874
+ @serializeable()
875
+ yMultiplier!: number;
876
+ @serializeable(MinMaxCurve)
877
+ z!: MinMaxCurve;
878
+ @serializeable()
879
+ zMultiplier!: number;
880
+
881
+ evaluate(t01: number): number {
882
+ if (!this.enabled) return 0;
883
+ if (!this.separateAxes) {
884
+ const rot = this.z.evaluate(t01) * -1;
885
+ return rot;
886
+ }
887
+ return 0;
888
+ }
889
+ }
890
+
891
+ export class RotationBySpeedModule {
892
+ @serializeable()
893
+ enabled!: boolean;
894
+
895
+ @serializeable()
896
+ range!: Vec2;
897
+
898
+ @serializeable()
899
+ separateAxes!: boolean;
900
+
901
+ @serializeable(MinMaxCurve)
902
+ x!: MinMaxCurve;
903
+ @serializeable()
904
+ xMultiplier!: number;
905
+ @serializeable(MinMaxCurve)
906
+ y!: MinMaxCurve;
907
+ @serializeable()
908
+ yMultiplier!: number;
909
+ @serializeable(MinMaxCurve)
910
+ z!: MinMaxCurve;
911
+ @serializeable()
912
+ zMultiplier!: number;
913
+
914
+ evaluate(_t01: number, speed: number): number {
915
+ if (!this.enabled) return 0;
916
+ if (!this.separateAxes) {
917
+ const t = Mathf.lerp(this.range.x, this.range.y, speed);
918
+ const rot = this.z.evaluate(t) * -1;
919
+ return rot;
920
+ }
921
+ return 0;
922
+ }
923
+ }
924
+
925
+
926
+ export class LimitVelocityOverLifetimeModule {
927
+ @serializeable()
928
+ enabled!: boolean;
929
+
930
+ @serializeable()
931
+ dampen!: number;
932
+
933
+ @serializeable(MinMaxCurve)
934
+ drag!: MinMaxCurve;
935
+ @serializeable()
936
+ dragMultiplier!: number;
937
+
938
+ @serializeable(MinMaxCurve)
939
+ limit!: MinMaxCurve;
940
+ @serializeable()
941
+ limitMultiplier!: number;
942
+
943
+ @serializeable()
944
+ separateAxes!: boolean;
945
+
946
+ @serializeable(MinMaxCurve)
947
+ limitX!: MinMaxCurve;
948
+ @serializeable()
949
+ limitXMultiplier!: number;
950
+ @serializeable(MinMaxCurve)
951
+ limitY!: MinMaxCurve;
952
+ @serializeable()
953
+ limitYMultiplier!: number;
954
+ @serializeable(MinMaxCurve)
955
+ limitZ!: MinMaxCurve;
956
+ @serializeable()
957
+ limitZMultiplier!: number;
958
+
959
+ @serializeable()
960
+ multiplyDragByParticleSize: boolean = false;
961
+ @serializeable()
962
+ multiplyDragByParticleVelocity: boolean = false;
963
+
964
+ @serializeable()
965
+ space!: ParticleSystemSimulationSpace;
966
+
967
+ private _temp: Vector3 = new Vector3();
968
+ private _temp2: Vector3 = new Vector3();
969
+
970
+ apply(_position: Vec3, baseVelocity: Vector3, currentVelocity: Vector3, _size: number, t01: number, _dt: number, _scale: number) {
971
+ if (!this.enabled) return;
972
+ // if (this.separateAxes) {
973
+ // // const maxX = this.limitX.evaluate(t01) * this.limitXMultiplier;
974
+ // // const maxY = this.limitY.evaluate(t01) * this.limitYMultiplier;
975
+ // // const maxZ = this.limitZ.evaluate(t01) * this.limitZMultiplier;
976
+
977
+ // }
978
+ // else
979
+ {
980
+ const max = this.limit.evaluate(t01) * this.limitMultiplier;
981
+ const speed = baseVelocity.length();
982
+ if (speed > max) {
983
+ this._temp.copy(baseVelocity).normalize().multiplyScalar(max);
984
+ let t = this.dampen * .5;
985
+ // t *= scale;
986
+ baseVelocity.x = Mathf.lerp(baseVelocity.x, this._temp.x, t);
987
+ baseVelocity.y = Mathf.lerp(baseVelocity.y, this._temp.y, t);
988
+ baseVelocity.z = Mathf.lerp(baseVelocity.z, this._temp.z, t);
989
+
990
+ // this._temp2.set(0, 0, 0);
991
+ currentVelocity.x = Mathf.lerp(currentVelocity.x, this._temp.x, t);
992
+ currentVelocity.y = Mathf.lerp(currentVelocity.y, this._temp.y, t);
993
+ currentVelocity.z = Mathf.lerp(currentVelocity.z, this._temp.z, t);
994
+ }
995
+ // vel.multiplyScalar(dragFactor);
996
+ }
997
+ // vel.x *= 0.3;
998
+ // vel.y *= 0.3;
999
+ // vel.z *= 0.3;
1000
+ }
659
1001
  }
@@ -162,6 +162,7 @@ export class WebXRController extends Behaviour {
162
162
  public grabbed: AttachedObject | null = null;
163
163
  public input: XRInputSource | null = null;
164
164
  public type: ControllerType = ControllerType.PhysicalDevice;
165
+ public showRaycastLine : boolean = true;
165
166
 
166
167
  get isUsingHands(): boolean {
167
168
  const r = this.input?.hand;
@@ -396,7 +397,7 @@ export class WebXRController extends Behaviour {
396
397
  setWorldQuaternion(this.raycastLine, this.rayRotation);
397
398
  }
398
399
  else {
399
- this.raycastLine.visible = true;
400
+ this.raycastLine.visible = this.showRaycastLine;
400
401
  setWorldQuaternion(this.raycastLine, this.rayRotation);
401
402
  setWorldPosition(this.raycastLine, wp);
402
403
  }
@@ -60,6 +60,12 @@ export { ColorOverLifetimeModule } from "../ParticleSystemModules";
60
60
  export { SizeOverLifetimeModule } from "../ParticleSystemModules";
61
61
  export { ShapeModule } from "../ParticleSystemModules";
62
62
  export { NoiseModule } from "../ParticleSystemModules";
63
+ export { TrailModule } from "../ParticleSystemModules";
64
+ export { VelocityOverLifetimeModule } from "../ParticleSystemModules";
65
+ export { TextureSheetAnimationModule } from "../ParticleSystemModules";
66
+ export { RotationOverLifetimeModule } from "../ParticleSystemModules";
67
+ export { RotationBySpeedModule } from "../ParticleSystemModules";
68
+ export { LimitVelocityOverLifetimeModule } from "../ParticleSystemModules";
63
69
  export { PlayerColor } from "../PlayerColor";
64
70
  export { ReflectionProbe } from "../ReflectionProbe";
65
71
  export { FieldWithDefault } from "../Renderer";
@@ -32,6 +32,13 @@ export class RGBAColor extends Color {
32
32
  return super.lerp(color, alpha);
33
33
  }
34
34
 
35
+ lerpColors(color1: Color, color2: Color, alpha: number): this {
36
+ const rgba1 = color1 as RGBAColor;
37
+ const rgba2 = color2 as RGBAColor;
38
+ if(rgba1.alpha && rgba2.alpha) this.alpha = Mathf.lerp(rgba1.alpha, rgba2.alpha, alpha);
39
+ return super.lerpColors(color1, color2, alpha);
40
+ }
41
+
35
42
  multiply(color: Color): this {
36
43
  const rgba = color as RGBAColor;
37
44
  if(rgba.alpha) this.alpha = this.alpha * rgba.alpha;