@needle-tools/engine 2.54.2-pre → 2.55.1-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 (94) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/needle-engine.d.ts +39 -14
  3. package/dist/needle-engine.js +355 -355
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +35 -35
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/dist/needle-engine.tsbuildinfo +1 -1
  8. package/lib/engine/engine_lightdata.js +1 -1
  9. package/lib/engine/engine_lightdata.js.map +1 -1
  10. package/lib/engine/engine_mainloop_utils.js +8 -0
  11. package/lib/engine/engine_mainloop_utils.js.map +1 -1
  12. package/lib/engine/engine_physics.d.ts +1 -1
  13. package/lib/engine/engine_physics.js +44 -3
  14. package/lib/engine/engine_physics.js.map +1 -1
  15. package/lib/engine/engine_physics.types.d.ts +13 -0
  16. package/lib/engine/engine_physics.types.js +7 -0
  17. package/lib/engine/engine_physics.types.js.map +1 -1
  18. package/lib/engine/engine_serialization_core.js +20 -10
  19. package/lib/engine/engine_serialization_core.js.map +1 -1
  20. package/lib/engine/engine_setup.js +2 -2
  21. package/lib/engine/engine_setup.js.map +1 -1
  22. package/lib/engine/engine_time.d.ts +1 -0
  23. package/lib/engine/engine_time.js +7 -0
  24. package/lib/engine/engine_time.js.map +1 -1
  25. package/lib/engine/engine_types.d.ts +4 -1
  26. package/lib/engine/engine_types.js.map +1 -1
  27. package/lib/engine/engine_utils.d.ts +1 -0
  28. package/lib/engine/engine_utils.js +3 -0
  29. package/lib/engine/engine_utils.js.map +1 -1
  30. package/lib/engine/extensions/NEEDLE_lightmaps.js +3 -1
  31. package/lib/engine/extensions/NEEDLE_lightmaps.js.map +1 -1
  32. package/lib/engine-components/Camera.d.ts +1 -2
  33. package/lib/engine-components/Camera.js +8 -10
  34. package/lib/engine-components/Camera.js.map +1 -1
  35. package/lib/engine-components/Collider.d.ts +2 -0
  36. package/lib/engine-components/Collider.js +4 -0
  37. package/lib/engine-components/Collider.js.map +1 -1
  38. package/lib/engine-components/LODGroup.js +9 -0
  39. package/lib/engine-components/LODGroup.js.map +1 -1
  40. package/lib/engine-components/OrbitControls.d.ts +8 -7
  41. package/lib/engine-components/OrbitControls.js +38 -7
  42. package/lib/engine-components/OrbitControls.js.map +1 -1
  43. package/lib/engine-components/ParticleSystem.d.ts +1 -0
  44. package/lib/engine-components/ParticleSystem.js +17 -6
  45. package/lib/engine-components/ParticleSystem.js.map +1 -1
  46. package/lib/engine-components/ParticleSystemModules.d.ts +2 -2
  47. package/lib/engine-components/ParticleSystemModules.js +27 -21
  48. package/lib/engine-components/ParticleSystemModules.js.map +1 -1
  49. package/lib/engine-components/Renderer.d.ts +1 -0
  50. package/lib/engine-components/Renderer.js +21 -2
  51. package/lib/engine-components/Renderer.js.map +1 -1
  52. package/lib/engine-components/RigidBody.js +1 -19
  53. package/lib/engine-components/RigidBody.js.map +1 -1
  54. package/lib/engine-components/SyncedTransform.js +1 -3
  55. package/lib/engine-components/SyncedTransform.js.map +1 -1
  56. package/lib/engine-components/VideoPlayer.d.ts +2 -1
  57. package/lib/engine-components/VideoPlayer.js +54 -51
  58. package/lib/engine-components/VideoPlayer.js.map +1 -1
  59. package/lib/engine-components/WebARSessionRoot.js +5 -0
  60. package/lib/engine-components/WebARSessionRoot.js.map +1 -1
  61. package/lib/engine-components/WebXR.js +13 -13
  62. package/lib/engine-components/WebXR.js.map +1 -1
  63. package/lib/engine-components/WebXRController.js +1 -2
  64. package/lib/engine-components/WebXRController.js.map +1 -1
  65. package/lib/engine-components/js-extensions/RGBAColor.d.ts +2 -0
  66. package/lib/engine-components/js-extensions/RGBAColor.js +2 -0
  67. package/lib/engine-components/js-extensions/RGBAColor.js.map +1 -1
  68. package/lib/tsconfig.tsbuildinfo +1 -1
  69. package/package.json +1 -1
  70. package/src/engine/codegen/register_types.js +2 -2
  71. package/src/engine/engine_lightdata.ts +1 -1
  72. package/src/engine/engine_mainloop_utils.ts +6 -0
  73. package/src/engine/engine_physics.ts +47 -5
  74. package/src/engine/engine_physics.types.ts +17 -0
  75. package/src/engine/engine_serialization_core.ts +25 -13
  76. package/src/engine/engine_setup.ts +2 -2
  77. package/src/engine/engine_time.ts +7 -1
  78. package/src/engine/engine_types.ts +5 -2
  79. package/src/engine/engine_utils.ts +4 -0
  80. package/src/engine/extensions/NEEDLE_lightmaps.ts +3 -1
  81. package/src/engine-components/Camera.ts +10 -15
  82. package/src/engine-components/Collider.ts +3 -0
  83. package/src/engine-components/LODGroup.ts +9 -0
  84. package/src/engine-components/OrbitControls.ts +58 -19
  85. package/src/engine-components/ParticleSystem.ts +18 -6
  86. package/src/engine-components/ParticleSystemModules.ts +29 -22
  87. package/src/engine-components/Renderer.ts +25 -2
  88. package/src/engine-components/RigidBody.ts +1 -20
  89. package/src/engine-components/SyncedTransform.ts +1 -3
  90. package/src/engine-components/VideoPlayer.ts +55 -51
  91. package/src/engine-components/WebARSessionRoot.ts +5 -0
  92. package/src/engine-components/WebXR.ts +15 -13
  93. package/src/engine-components/WebXRController.ts +1 -2
  94. package/src/engine-components/js-extensions/RGBAColor.ts +3 -0
@@ -153,6 +153,7 @@ class ParticleSystemEmissionOverTime extends BaseValueGenerator {
153
153
  }
154
154
 
155
155
  genValue(): number {
156
+ if (!this.system.emission.enabled) return 0;
156
157
  if (this.system.currentParticles >= this.system.maxParticles) return 0;
157
158
  // emission over time
158
159
  let emission = this.system.emission.rateOverTime.evaluate(this.system.time / this.system.duration, Math.random());
@@ -225,9 +226,15 @@ class TextureSheetAnimationBehaviour extends ParticleSystemBaseBehaviour {
225
226
 
226
227
  }
227
228
 
229
+ const $particleRotation = Symbol("particleRotation")
230
+
228
231
  class RotationBehaviour extends ParticleSystemBaseBehaviour {
229
232
  type: string = "NeedleRotation"
230
233
 
234
+ initialize(particle: Particle) {
235
+ particle[$particleRotation] = Math.random();
236
+ }
237
+
231
238
  update(particle: Particle, delta: number) {
232
239
  if (particle.rotation === undefined) return;
233
240
 
@@ -235,7 +242,7 @@ class RotationBehaviour extends ParticleSystemBaseBehaviour {
235
242
 
236
243
  if (typeof particle.rotation === "number") {
237
244
  if (this.system.rotationOverLifetime.enabled) {
238
- particle.rotation += this.system.rotationOverLifetime.evaluate(t) * delta;
245
+ particle.rotation += this.system.rotationOverLifetime.evaluate(t, particle[$particleRotation]) * delta;
239
246
  }
240
247
  else {
241
248
  if (this.system.renderer.renderMode === ParticleSystemRenderMode.Billboard)
@@ -548,6 +555,8 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
548
555
  private _state?: ParticlesEmissionState;
549
556
  emit(count: number) {
550
557
  if (this._particleSystem) {
558
+ // we need to call update the matrices etc e.g. if we call emit from a physics callback
559
+ this.onUpdate();
551
560
  count = Math.min(count, this.maxParticles - this.currentParticles);
552
561
  if (!this._state) this._state = new ParticlesEmissionState();
553
562
  this._state.waitEmiting = count;
@@ -768,6 +777,14 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
768
777
  }
769
778
 
770
779
  onBeforeRender() {
780
+ this.onUpdate();
781
+ const dt = this.deltaTime;
782
+ this._batchSystem?.update(dt);
783
+ this._time += dt;
784
+ if (this._time > this.duration) this._time = 0;
785
+ }
786
+
787
+ private onUpdate() {
771
788
  if (this._bursts) {
772
789
  this.emission.bursts = this._bursts;
773
790
  delete this._bursts;
@@ -796,17 +813,12 @@ export class ParticleSystem extends Behaviour implements IParticleSystem {
796
813
  this._container.matrix.identity();
797
814
  this._container.matrix.scale(scale);
798
815
  }
799
-
800
816
  this.emission.system = this;
801
- const dt = this.deltaTime;
802
817
  this._interface.update();
803
818
  this.shape.update(this, this.context, this.main.simulationSpace, this.gameObject);
804
819
  this.noise.update(this.context);
805
820
  this.inheritVelocity?.update(this.context);
806
821
  this.velocityOverLifetime.update(this);
807
- this._batchSystem?.update(dt);
808
- this._time += dt;
809
- if (this._time > this.duration) this._time = 0;
810
822
  }
811
823
 
812
824
  private addSubParticleSystems() {
@@ -6,6 +6,11 @@ import { AnimationCurve } from "./AnimationCurve";
6
6
  import { Vec2, Vec3 } from "../engine/engine_types";
7
7
  import { Context } from "../engine/engine_setup";
8
8
  import { EmitterShape, FrameOverLife, Particle, ShapeJSON } from "three.quarks";
9
+ import { createNoise4D, NoiseFunction4D } from 'simplex-noise';
10
+ import { Gizmos } from "../engine/engine_gizmos";
11
+ import { getParam } from "../engine/engine_utils";
12
+
13
+ const debug = getParam("debugparticles");
9
14
 
10
15
  declare type Color4 = { r: number, g: number, b: number, a: number };
11
16
  declare type ColorKey = { time: number, color: Color4 };
@@ -457,10 +462,10 @@ export class SizeOverLifetimeModule {
457
462
 
458
463
  export class ShapeModule implements EmitterShape {
459
464
 
465
+ // Emittershape start
460
466
  get type(): string {
461
467
  return ParticleSystemShapeType[this.shapeType];
462
468
  }
463
-
464
469
  initialize(particle: Particle): void {
465
470
  this.getPosition();
466
471
  particle.position.copy(this._vector);
@@ -471,6 +476,7 @@ export class ShapeModule implements EmitterShape {
471
476
  clone(): EmitterShape {
472
477
  return new ShapeModule();
473
478
  }
479
+ // EmitterShape end
474
480
 
475
481
  @serializable()
476
482
  shapeType: ParticleSystemShapeType = ParticleSystemShapeType.Box;
@@ -574,16 +580,12 @@ export class ShapeModule implements EmitterShape {
574
580
  this.randomConePoint(this.position, this.angle, radius, this.radiusThickness, this.arc, this.arcMode, this._vector);
575
581
  break;
576
582
  case ParticleSystemShapeType.Sphere:
577
- this.randomSpherePoint(this.position, radius, this.radiusThickness, this.arc, this._vector);
578
- this._vector.x *= this.scale.x;
579
- this._vector.y *= this.scale.y;
580
- this._vector.z *= this.scale.z;
583
+ this.randomSpherePoint(this.position, radius, this.radiusThickness, this.arc, this._vector, this.scale);
581
584
  break;
582
585
  case ParticleSystemShapeType.Circle:
583
- this.randomSpherePoint(this.position, radius, this.radiusThickness, this.arc, this._vector);
584
- this._vector.x *= this.scale.x;
585
- this._vector.y *= this.scale.y;
586
- this._vector.z *= 0;
586
+ this._temp.copy(this.scale);
587
+ this._temp.z = 0;
588
+ this.randomSpherePoint(this.position, radius, this.radiusThickness, this.arc, this._vector, this._temp);
587
589
  break;
588
590
  default:
589
591
  this._vector.set(0, 0, 0);
@@ -600,6 +602,7 @@ export class ShapeModule implements EmitterShape {
600
602
  this._vector.applyEuler(this._rotation);
601
603
 
602
604
  if (isWorldSpace) {
605
+ this._vector.applyQuaternion(this.system.worldQuaternion);
603
606
  this._vector.add(this.system.worldPos);
604
607
  }
605
608
  }
@@ -607,7 +610,8 @@ export class ShapeModule implements EmitterShape {
607
610
 
608
611
 
609
612
  private _dir: Vector3 = new Vector3();
610
- getDirection(position): Vector3 {
613
+
614
+ getDirection(pos: Vec3): Vector3 {
611
615
  if (!this.enabled) {
612
616
  this._dir.set(0, 0, 1);
613
617
  return this._dir;
@@ -623,10 +627,11 @@ export class ShapeModule implements EmitterShape {
623
627
  break;
624
628
  case ParticleSystemShapeType.Circle:
625
629
  case ParticleSystemShapeType.Sphere:
626
- const rx = position.x;
627
- const ry = position.y;
628
- const rz = position.z;
629
- this._dir.set(rx, ry, rz).sub(this.position)
630
+ const rx = pos.x;
631
+ const ry = pos.y;
632
+ const rz = pos.z;
633
+ this._dir.set(rx, ry, rz)
634
+ this._dir.sub(this.position)
630
635
  break;
631
636
  default:
632
637
  this._dir.set(0, 0, 1);
@@ -640,7 +645,10 @@ export class ShapeModule implements EmitterShape {
640
645
  this._dir.normalize();
641
646
  this.spherizeDirection(this._dir, this.sphericalDirectionAmount);
642
647
  this.randomizeDirection(this._dir, this.randomDirectionAmount);
643
- // Gizmos.DrawDirection(position, this._dir, 0xff0000, .5);
648
+ if (debug) {
649
+ Gizmos.DrawSphere(pos, .01, 0x883300, .5, true);
650
+ Gizmos.DrawDirection(pos, this._dir, 0x883300, .5, true);
651
+ }
644
652
  return this._dir;
645
653
  }
646
654
 
@@ -677,15 +685,15 @@ export class ShapeModule implements EmitterShape {
677
685
  dir.lerp(v, amount);
678
686
  }
679
687
 
680
- private randomSpherePoint(pos: Vec3, radius: number, thickness: number, arc: number, vec: Vec3) {
688
+ private randomSpherePoint(pos: Vec3, radius: number, thickness: number, arc: number, vec: Vec3, scale: Vec3) {
681
689
  const u = Math.random();
682
690
  const v = Math.random();
683
691
  const theta = 2 * Math.PI * u * (arc / 360);
684
692
  const phi = Math.acos(2 * v - 1);
685
693
  const r = Mathf.lerp(1, 1 - (Math.pow(1 - Math.random(), Math.PI)), thickness) * (radius);
686
- const x = pos.x + (-r * Math.sin(phi) * Math.cos(theta));
687
- const y = pos.y + (r * Math.sin(phi) * Math.sin(theta));
688
- const z = pos.z + (r * Math.cos(phi));
694
+ const x = pos.x + scale.x * (-r * Math.sin(phi) * Math.cos(theta));
695
+ const y = pos.y + scale.y * (r * Math.sin(phi) * Math.sin(theta));
696
+ const z = pos.z + scale.z * (r * Math.cos(phi));
689
697
  vec.x = x;
690
698
  vec.y = y;
691
699
  vec.z = z;
@@ -738,7 +746,6 @@ export class ShapeModule implements EmitterShape {
738
746
 
739
747
 
740
748
 
741
- import { createNoise4D, NoiseFunction4D } from 'simplex-noise';
742
749
 
743
750
  export class NoiseModule {
744
751
  @serializable()
@@ -1110,10 +1117,10 @@ export class RotationOverLifetimeModule {
1110
1117
  @serializable()
1111
1118
  zMultiplier!: number;
1112
1119
 
1113
- evaluate(t01: number): number {
1120
+ evaluate(t01: number, t:number): number {
1114
1121
  if (!this.enabled) return 0;
1115
1122
  if (!this.separateAxes) {
1116
- const rot = this.z.evaluate(t01) * -1;
1123
+ const rot = this.z.evaluate(t01, t) * -1;
1117
1124
  return rot;
1118
1125
  }
1119
1126
  return 0;
@@ -22,6 +22,7 @@ const debugInstancing = getParam("debuginstancing");
22
22
  const debugProgressiveLoading = getParam("debugprogressive");
23
23
  const suppressProgressiveLoading = getParam("noprogressive");
24
24
 
25
+ const showWireframe = getParam("wireframe");
25
26
 
26
27
  export enum ReflectionProbeUsage {
27
28
  Off = 0,
@@ -229,6 +230,12 @@ export class Renderer extends Behaviour implements IRenderer {
229
230
 
230
231
  allowProgressiveLoading: boolean = true;
231
232
 
233
+ registering() {
234
+ if (!this.enabled) {
235
+ this.setVisibility(false);
236
+ }
237
+ }
238
+
232
239
  awake() {
233
240
  this.clearInstancingState();
234
241
 
@@ -279,15 +286,20 @@ export class Renderer extends Behaviour implements IRenderer {
279
286
  this._lightmaps = [];
280
287
 
281
288
  if (type === "Mesh") {
282
- if (!this.gameObject["material"]?.isMeshBasicMaterial === true) {
289
+ const mat = this.gameObject["material"];
290
+ if (!mat?.isMeshBasicMaterial) {
283
291
  const rm = new RendererLightmap(this.gameObject, this.context);// GameObject.addNewComponent(this.gameObject, RendererLightmap);
284
292
  this._lightmaps.push(rm);
285
293
  rm.init(this.lightmapIndex, this.lightmapScaleOffset, tex, debugLightmap);
286
294
  }
295
+ else {
296
+ if (mat)
297
+ console.warn("Lightmapping is not supported on MeshBasicMaterial", mat.name)
298
+ }
287
299
  }
288
300
  // for multi materials we need to loop through children
289
301
  // and then we add a lightmap renderer component to each of them
290
- else if (this.isMultiMaterialObject(this.gameObject)) {
302
+ else if (this.isMultiMaterialObject(this.gameObject) && this.sharedMaterials.length > 0) {
291
303
  for (const child of this.gameObject.children) {
292
304
  if (!child["material"]?.isMeshBasicMaterial) {
293
305
  const rm = new RendererLightmap(child as GameObject, this.context);
@@ -303,6 +315,17 @@ export class Renderer extends Behaviour implements IRenderer {
303
315
  }
304
316
  }
305
317
 
318
+
319
+
320
+ if (showWireframe) {
321
+ for (let i = 0; i < this.sharedMaterials.length; i++) {
322
+ const mat: any = this.sharedMaterials[i];
323
+ if (mat) {
324
+ mat.wireframe = true;
325
+ }
326
+ }
327
+ }
328
+
306
329
  }
307
330
 
308
331
  private _isInstancingEnabled: boolean = false;
@@ -359,26 +359,7 @@ export class Rigidbody extends Behaviour implements IRigidbody {
359
359
  /**d
360
360
  * @deprecated not used anymore
361
361
  */
362
- public setBodyFromGameObject(_velocity: THREE.Vector3 | null | { x: number, y: number, z: number } = null) {
363
- if (this.gameObject && !this.destroyed) {
364
- // this.context.physics.updateBody(this);
365
- // this._ignoreChange = true;
366
- // const wp = this.worldPosition;
367
- // this.body.position.set(wp.x, wp.y, wp.z);
368
- // const wr = this.worldQuaternion;
369
- // this.body.quaternion.set(wr.x, wr.y, wr.z, wr.w);
370
-
371
- // if (velocity) {
372
- // Rigidbody.copyVector3.set(velocity.x, velocity.y, velocity.z);
373
- // this._smoothedVelocity.lerp(Rigidbody.copyVector3, this.context.time.deltaTime / .1);
374
- // const sm = this._smoothedVelocity;
375
- // this.body.velocity.x = sm.x;
376
- // this.body.velocity.y = sm.y;
377
- // this.body.velocity.z = sm.z;
378
- // }
379
- // this._ignoreChange = false;
380
- }
381
- }
362
+ public setBodyFromGameObject(_velocity: THREE.Vector3 | null | { x: number, y: number, z: number } = null) { }
382
363
 
383
364
 
384
365
 
@@ -268,7 +268,6 @@ export class SyncedTransform extends Behaviour {
268
268
  if (this.rb) {
269
269
  this.rb.isKinematic = this._model.isOwned ?? false;
270
270
  this.rb.setVelocity(0, 0, 0);
271
- this.rb.setBodyFromGameObject();
272
271
  }
273
272
  return;
274
273
  }
@@ -288,7 +287,6 @@ export class SyncedTransform extends Behaviour {
288
287
  console.log("RESET", this.name)
289
288
  this.gameObject.position.set(0, 1, 0);
290
289
  this.rb.setVelocity(0, 0, 0);
291
- this.rb.setBodyFromGameObject();
292
290
  }
293
291
  }
294
292
 
@@ -300,7 +298,7 @@ export class SyncedTransform extends Behaviour {
300
298
  console.log("send update", this.context.connection.connectionId, this.guid, this.gameObject.name, this.gameObject.guid);
301
299
 
302
300
  if (this.overridePhysics && this.rb) {
303
- this.rb.setBodyFromGameObject();
301
+ // this.rb.setBodyFromGameObject();
304
302
  }
305
303
 
306
304
  this._needsUpdate = false;
@@ -73,37 +73,37 @@ export class VideoPlayer extends Behaviour {
73
73
  private _playbackSpeed: number = 1;
74
74
  @serializable()
75
75
  get playbackSpeed(): number {
76
- return this.videoElement?.playbackRate ?? this._playbackSpeed;
76
+ return this._videoElement?.playbackRate ?? this._playbackSpeed;
77
77
  }
78
78
  set playbackSpeed(val: number) {
79
79
  this._playbackSpeed = val;
80
- if (this.videoElement)
81
- this.videoElement.playbackRate = val;
80
+ if (this._videoElement)
81
+ this._videoElement.playbackRate = val;
82
82
  }
83
83
 
84
84
  private _isLooping: boolean = false;
85
85
  get isLooping(): boolean {
86
- return this.videoElement?.loop ?? this._isLooping;
86
+ return this._videoElement?.loop ?? this._isLooping;
87
87
  }
88
88
  @serializable()
89
89
  set isLooping(val: boolean) {
90
90
  this._isLooping = val;
91
- if (this.videoElement)
92
- this.videoElement.loop = val;
91
+ if (this._videoElement)
92
+ this._videoElement.loop = val;
93
93
  }
94
94
 
95
95
  get currentTime(): number {
96
- return this.videoElement?.currentTime ?? this.time;
96
+ return this._videoElement?.currentTime ?? this.time;
97
97
  }
98
98
  set currentTime(val: number) {
99
- if (this.videoElement) {
100
- this.videoElement.currentTime = val;
99
+ if (this._videoElement) {
100
+ this._videoElement.currentTime = val;
101
101
  }
102
102
  else this.time = val;
103
103
  }
104
104
 
105
105
  get isPlaying(): boolean {
106
- const video = this.videoElement;
106
+ const video = this._videoElement;
107
107
  if (video) {
108
108
  return video.currentTime > 0 && !video.paused && !video.ended
109
109
  && video.readyState > video.HAVE_CURRENT_DATA;
@@ -112,13 +112,13 @@ export class VideoPlayer extends Behaviour {
112
112
  }
113
113
 
114
114
  get crossOrigin(): string | null {
115
- return this.videoElement?.crossOrigin ?? this._crossOrigin;
115
+ return this._videoElement?.crossOrigin ?? this._crossOrigin;
116
116
  }
117
117
  set crossOrigin(val: string | null) {
118
118
  this._crossOrigin = val;
119
- if (this.videoElement) {
120
- if (val !== null) this.videoElement.setAttribute("crossorigin", val);
121
- else this.videoElement.removeAttribute("crossorigin");
119
+ if (this._videoElement) {
120
+ if (val !== null) this._videoElement.setAttribute("crossorigin", val);
121
+ else this._videoElement.removeAttribute("crossorigin");
122
122
  }
123
123
  }
124
124
 
@@ -126,6 +126,10 @@ export class VideoPlayer extends Behaviour {
126
126
  return this._videoTexture;
127
127
  }
128
128
 
129
+ get videoElement() {
130
+ return this._videoElement;
131
+ }
132
+
129
133
  private _crossOrigin: string | null = "anonymous";
130
134
 
131
135
  private audioOutputMode: VideoAudioOutputMode = VideoAudioOutputMode.AudioSource;
@@ -134,7 +138,7 @@ export class VideoPlayer extends Behaviour {
134
138
  private clip?: string | MediaStream | null = null;
135
139
  private url?: string | null = null;
136
140
 
137
- private videoElement: HTMLVideoElement | null = null;
141
+ private _videoElement: HTMLVideoElement | null = null;
138
142
  private _videoTexture: THREE.VideoTexture | null = null;
139
143
  private videoMaterial: Material | null = null;
140
144
 
@@ -144,12 +148,12 @@ export class VideoPlayer extends Behaviour {
144
148
  setVideo(video: MediaStream) {
145
149
  this.clip = video;
146
150
  this.source = VideoSource.VideoClip;
147
- if (!this.videoElement) this.create(true);
151
+ if (!this._videoElement) this.create(true);
148
152
  else {
149
153
  // TODO: how to prevent interruption error when another video is already playing
150
- this.videoElement.srcObject = video;
154
+ this._videoElement.srcObject = video;
151
155
  if (this._isPlaying)
152
- this.videoElement.play();
156
+ this._videoElement.play();
153
157
  this.updateAspect();
154
158
  }
155
159
  }
@@ -160,9 +164,9 @@ export class VideoPlayer extends Behaviour {
160
164
  this.url = url;
161
165
  this.source = VideoSource.Url;
162
166
  if (debug) console.log("set url", url);
163
- if (!this.videoElement) this.create(true);
167
+ if (!this._videoElement) this.create(true);
164
168
  else {
165
- this.videoElement.src = url;
169
+ this._videoElement.src = url;
166
170
  if (this._isPlaying) {
167
171
  this.stop();
168
172
  this.play();
@@ -201,9 +205,9 @@ export class VideoPlayer extends Behaviour {
201
205
  }
202
206
 
203
207
  onDestroy(): void {
204
- if (this.videoElement) {
205
- this.videoElement.parentElement?.removeChild(this.videoElement);
206
- this.videoElement = null;
208
+ if (this._videoElement) {
209
+ this._videoElement.parentElement?.removeChild(this._videoElement);
210
+ this._videoElement = null;
207
211
  }
208
212
  if (this._videoTexture) {
209
213
  this._videoTexture.dispose();
@@ -231,27 +235,27 @@ export class VideoPlayer extends Behaviour {
231
235
  }
232
236
 
233
237
  play() {
234
- if (!this.videoElement) return;
235
- if (this._isPlaying && !this.videoElement?.ended && !this.videoElement?.paused) return;
238
+ if (!this._videoElement) return;
239
+ if (this._isPlaying && !this._videoElement?.ended && !this._videoElement?.paused) return;
236
240
  this._isPlaying = true;
237
- if (!this._receivedInput) this.videoElement.muted = true;
241
+ if (!this._receivedInput) this._videoElement.muted = true;
238
242
  this.updateVideoElementSettings();
239
- this.videoElement?.play().catch(err => {
243
+ this._videoElement?.play().catch(err => {
240
244
  console.warn(err);
241
245
  });
242
- if (debug) console.log("play", this.videoElement);
246
+ if (debug) console.log("play", this._videoElement);
243
247
  }
244
248
 
245
249
  stop() {
246
250
  this._isPlaying = false;
247
- if (!this.videoElement) return;
248
- this.videoElement.currentTime = 0;
249
- this.videoElement.pause();
251
+ if (!this._videoElement) return;
252
+ this._videoElement.currentTime = 0;
253
+ this._videoElement.pause();
250
254
  }
251
255
 
252
256
  pause(): void {
253
257
  this._isPlaying = false;
254
- this.videoElement?.pause();
258
+ this._videoElement?.pause();
255
259
  }
256
260
 
257
261
 
@@ -270,23 +274,23 @@ export class VideoPlayer extends Behaviour {
270
274
 
271
275
  // console.log(src, this);
272
276
 
273
- if (!this.videoElement) {
274
- this.videoElement = this.createVideoElement();
275
- this.context.domElement?.prepend(this.videoElement);
277
+ if (!this._videoElement) {
278
+ this._videoElement = this.createVideoElement();
279
+ this.context.domElement?.prepend(this._videoElement);
276
280
  // hide it because otherwise it would overlay the website with default css
277
281
  this.updateVideoElementStyles();
278
282
  }
279
283
  if (typeof src === "string") {
280
- this.videoElement.src = src;
281
- const str = this.videoElement["captureStream"]?.call(this.videoElement);
284
+ this._videoElement.src = src;
285
+ const str = this._videoElement["captureStream"]?.call(this._videoElement);
282
286
  this.clip = str;
283
287
  }
284
288
  else
285
- this.videoElement.srcObject = src;
289
+ this._videoElement.srcObject = src;
286
290
 
287
291
 
288
292
  if (!this._videoTexture)
289
- this._videoTexture = new THREE.VideoTexture(this.videoElement);
293
+ this._videoTexture = new THREE.VideoTexture(this._videoElement);
290
294
  this._videoTexture.flipY = false;
291
295
  this._videoTexture.encoding = THREE.sRGBEncoding;
292
296
  this.handleBeginPlaying(playAutomatically);
@@ -327,7 +331,7 @@ export class VideoPlayer extends Behaviour {
327
331
 
328
332
  private handleBeginPlaying(playAutomatically: boolean) {
329
333
  if (!this.enabled) return;
330
- if (!this.videoElement) return;
334
+ if (!this._videoElement) return;
331
335
 
332
336
  this._targetObjects.length = 0;
333
337
 
@@ -385,24 +389,24 @@ export class VideoPlayer extends Behaviour {
385
389
  }
386
390
 
387
391
  private updateVideoElementSettings() {
388
- if (!this.videoElement) return;
389
- this.videoElement.loop = this._isLooping;
390
- this.videoElement.currentTime = this.currentTime;
391
- this.videoElement.playbackRate = this._playbackSpeed;
392
+ if (!this._videoElement) return;
393
+ this._videoElement.loop = this._isLooping;
394
+ this._videoElement.currentTime = this.currentTime;
395
+ this._videoElement.playbackRate = this._playbackSpeed;
392
396
  // dont open in fullscreen on ios
393
- this.videoElement.playsInline = true;
394
- this.videoElement.muted = !this._receivedInput && this.audioOutputMode !== VideoAudioOutputMode.None;
397
+ this._videoElement.playsInline = true;
398
+ this._videoElement.muted = !this._receivedInput && this.audioOutputMode !== VideoAudioOutputMode.None;
395
399
  if (this.playOnAwake || this.playOnEnable)
396
- this.videoElement.autoplay = true;
400
+ this._videoElement.autoplay = true;
397
401
  }
398
402
 
399
403
  private updateVideoElementStyles() {
400
- if (!this.videoElement) return;
404
+ if (!this._videoElement) return;
401
405
  // set style here so preview frame is rendered
402
406
  // set display and selectable because otherwise is interfers with input/focus e.g. breaks orbit control
403
- this.videoElement.style.userSelect = "none";
404
- this.videoElement.style.visibility = "hidden";
405
- this.videoElement.style.display = "none";
407
+ this._videoElement.style.userSelect = "none";
408
+ this._videoElement.style.visibility = "hidden";
409
+ this._videoElement.style.display = "none";
406
410
  this.updateAspect();
407
411
  }
408
412
 
@@ -92,6 +92,9 @@ export class WebARSessionRoot extends Behaviour {
92
92
  placeAt(rig: Object3D | null, mat: Matrix4) {
93
93
  if (!this._placementPose) this._placementPose = new Matrix4();
94
94
  this._placementPose.copy(mat);
95
+ // apply session root offset
96
+ const invertedSessionRoot = this.gameObject.matrixWorld.clone().invert();
97
+ this._placementPose.premultiply(invertedSessionRoot);
95
98
  if (rig) {
96
99
 
97
100
  if (this.invertForward) {
@@ -146,9 +149,11 @@ export class WebARSessionRoot extends Behaviour {
146
149
  if (!rig || !this._placementPose) {
147
150
  return;
148
151
  }
152
+ // Capture the rig position before the first time we move it during a session
149
153
  if (!this._rigStartPose) {
150
154
  this._rigStartPose = rig.matrix.clone();
151
155
  }
156
+ // we apply the transform to the rig because we want to move the user's position for easy networking
152
157
  rig.matrixAutoUpdate = false;
153
158
  rig.matrix.multiplyMatrices(new Matrix4().makeScale(scale, scale, scale), this._placementPose);
154
159
  rig.matrix.decompose(rig.position, rig.quaternion, rig.scale);
@@ -143,6 +143,7 @@ export class WebXR extends Behaviour {
143
143
  return this.rig;
144
144
  }
145
145
 
146
+
146
147
  private controllers: WebXRController[] = [];
147
148
  public get Controllers(): WebXRController[] {
148
149
  return this.controllers;
@@ -249,17 +250,21 @@ export class WebXR extends Behaviour {
249
250
  // TODO: figure out why screen is black if we enable the code written here
250
251
  // const referenceSpace = renderer.xr.getReferenceSpace();
251
252
  const session = this.context.renderer.xr.getSession();
253
+
252
254
 
253
255
  if (session) {
254
256
  const pose = frame.getViewerPose(this.context.renderer.xr.getReferenceSpace());
257
+ if(!pose) return;
255
258
  this._currentHeadPose = pose;
256
- if (!pose) return; // e.g. if user is not wearing headset
257
259
  const transform: XRRigidTransform = pose?.transform;
258
-
259
260
  if (transform) {
260
261
  this._transformOrientation.set(transform.orientation.x, transform.orientation.y, transform.orientation.z, transform.orientation.w);
261
262
  }
262
263
 
264
+ if (WebXR._isInXr === false && session) {
265
+ this.onEnterXR(session, frame);
266
+ }
267
+
263
268
  for (const ctrl of this.controllers) {
264
269
  ctrl.onUpdate(session);
265
270
  }
@@ -269,9 +274,6 @@ export class WebXR extends Behaviour {
269
274
  }
270
275
  }
271
276
 
272
- if (WebXR._isInXr === false && session) {
273
- this.onEnterXR(session, frame);
274
- }
275
277
  WebXR.events.dispatchEvent({ type: WebXREvent.XRUpdate, frame: frame, xr: this.context.renderer.xr, rig: this.rig });
276
278
  }
277
279
 
@@ -329,7 +331,7 @@ export class WebXR extends Behaviour {
329
331
  if (xrRig) {
330
332
  // make it match unity forward
331
333
  this.rig = xrRig.gameObject;
332
- this.rig.rotateY(Math.PI);
334
+ // this.rig.rotateY(Math.PI);
333
335
  // this.rig.position.copy(existing.worldPosition);
334
336
  // this.rig.quaternion.premultiply(existing.worldQuaternion);
335
337
  }
@@ -577,7 +579,7 @@ export class WebAR {
577
579
  this.reticleParent.name = "AR Reticle Parent";
578
580
  this.reticleParent.matrixAutoUpdate = false;
579
581
  this.reticleParent.add(this.reticle);
580
- this.reticleParent.matrix.copy(this.sessionRoot.gameObject.matrixWorld);
582
+ // this.reticleParent.matrix.copy(this.sessionRoot.gameObject.matrixWorld);
581
583
 
582
584
  if (this.webxr.scene) {
583
585
  this.context.scene.add(this.reticleParent);
@@ -632,11 +634,11 @@ export class WebAR {
632
634
  this.didPlaceARSessionRoot = true;
633
635
  const rig = this.webxr.Rig;
634
636
  const placementMatrix = arPlacementWithoutHitTestMatrix.clone();
635
- if (rig) {
636
- const positionFromRig = new Vector3(0, 0, 0).add(rig.position).divideScalar(this.sessionRoot?.arScale ?? 1);
637
- placementMatrix.multiply(new Matrix4().makeTranslation(positionFromRig.x, positionFromRig.y, positionFromRig.z));
638
- // placementMatrix.setPosition(positionFromRig);
639
- }
637
+ // if (rig) {
638
+ // const positionFromRig = new Vector3(0, 0, 0).add(rig.position).divideScalar(this.sessionRoot?.arScale ?? 1);
639
+ // placementMatrix.multiply(new Matrix4().makeTranslation(positionFromRig.x, positionFromRig.y, positionFromRig.z));
640
+ // // placementMatrix.setPosition(positionFromRig);
641
+ // }
640
642
  this.sessionRoot?.placeAt(rig, placementMatrix);
641
643
  }
642
644
  return;
@@ -676,4 +678,4 @@ export class WebAR {
676
678
  }
677
679
  }
678
680
 
679
- const arPlacementWithoutHitTestMatrix = new Matrix4().identity().makeTranslation(0, -0.5, 0);
681
+ const arPlacementWithoutHitTestMatrix = new Matrix4().identity().makeTranslation(0, 0, 0);