@needle-tools/engine 2.28.0-pre → 2.30.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 (130) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/needle-engine.d.ts +232 -139
  3. package/dist/needle-engine.js +349 -345
  4. package/dist/needle-engine.js.map +4 -4
  5. package/dist/needle-engine.min.js +24 -20
  6. package/dist/needle-engine.min.js.map +4 -4
  7. package/lib/engine/engine.d.ts +1 -0
  8. package/lib/engine/engine_input.d.ts +13 -1
  9. package/lib/engine/engine_input.js +47 -16
  10. package/lib/engine/engine_input.js.map +1 -1
  11. package/lib/engine/engine_physics.d.ts +1 -0
  12. package/lib/engine/engine_physics.js +2 -1
  13. package/lib/engine/engine_physics.js.map +1 -1
  14. package/lib/engine/engine_playerview.d.ts +26 -0
  15. package/lib/engine/engine_playerview.js +65 -0
  16. package/lib/engine/engine_playerview.js.map +1 -0
  17. package/lib/engine/engine_serialization.d.ts +1 -0
  18. package/lib/engine/engine_serialization.js +1 -0
  19. package/lib/engine/engine_serialization.js.map +1 -1
  20. package/lib/engine/engine_serialization_core.js +5 -0
  21. package/lib/engine/engine_serialization_core.js.map +1 -1
  22. package/lib/engine/engine_setup.d.ts +8 -0
  23. package/lib/engine/engine_setup.js +23 -0
  24. package/lib/engine/engine_setup.js.map +1 -1
  25. package/lib/engine/engine_utils.d.ts +1 -1
  26. package/lib/engine/engine_utils.js +25 -8
  27. package/lib/engine/engine_utils.js.map +1 -1
  28. package/lib/engine/extensions/NEEDLE_deferred_texture.d.ts +1 -1
  29. package/lib/engine/extensions/NEEDLE_deferred_texture.js +26 -14
  30. package/lib/engine/extensions/NEEDLE_deferred_texture.js.map +1 -1
  31. package/lib/engine/extensions/NEEDLE_lighting_settings.js +6 -2
  32. package/lib/engine/extensions/NEEDLE_lighting_settings.js.map +1 -1
  33. package/lib/engine/extensions/extension_utils.js +24 -13
  34. package/lib/engine/extensions/extension_utils.js.map +1 -1
  35. package/lib/engine/extensions/extensions.js +3 -1
  36. package/lib/engine/extensions/extensions.js.map +1 -1
  37. package/lib/engine-components/Camera.js +7 -0
  38. package/lib/engine-components/Camera.js.map +1 -1
  39. package/lib/engine-components/Component.d.ts +1 -1
  40. package/lib/engine-components/Component.js.map +1 -1
  41. package/lib/engine-components/Light.js +1 -0
  42. package/lib/engine-components/Light.js.map +1 -1
  43. package/lib/engine-components/OrbitControls.js +3 -3
  44. package/lib/engine-components/OrbitControls.js.map +1 -1
  45. package/lib/engine-components/ParticleSystem.d.ts +0 -1
  46. package/lib/engine-components/ParticleSystem.js +24 -27
  47. package/lib/engine-components/ParticleSystem.js.map +1 -1
  48. package/lib/engine-components/PlayerColor.js +1 -2
  49. package/lib/engine-components/PlayerColor.js.map +1 -1
  50. package/lib/engine-components/Renderer.d.ts +1 -0
  51. package/lib/engine-components/Renderer.js +10 -3
  52. package/lib/engine-components/Renderer.js.map +1 -1
  53. package/lib/engine-components/ScreenCapture.d.ts +1 -0
  54. package/lib/engine-components/ScreenCapture.js +265 -1
  55. package/lib/engine-components/ScreenCapture.js.map +1 -1
  56. package/lib/engine-components/SpectatorCamera.d.ts +24 -17
  57. package/lib/engine-components/SpectatorCamera.js +435 -182
  58. package/lib/engine-components/SpectatorCamera.js.map +1 -1
  59. package/lib/engine-components/SyncedCamera.d.ts +8 -4
  60. package/lib/engine-components/SyncedCamera.js +15 -18
  61. package/lib/engine-components/SyncedCamera.js.map +1 -1
  62. package/lib/engine-components/SyncedRoom.js +2 -0
  63. package/lib/engine-components/SyncedRoom.js.map +1 -1
  64. package/lib/engine-components/VideoPlayer.d.ts +10 -1
  65. package/lib/engine-components/VideoPlayer.js +64 -15
  66. package/lib/engine-components/VideoPlayer.js.map +1 -1
  67. package/lib/engine-components/Volume.d.ts +4 -0
  68. package/lib/engine-components/Volume.js +44 -3
  69. package/lib/engine-components/Volume.js.map +1 -1
  70. package/lib/engine-components/WebARSessionRoot.d.ts +9 -2
  71. package/lib/engine-components/WebARSessionRoot.js +69 -24
  72. package/lib/engine-components/WebARSessionRoot.js.map +1 -1
  73. package/lib/engine-components/WebXR.d.ts +6 -3
  74. package/lib/engine-components/WebXR.js +43 -7
  75. package/lib/engine-components/WebXR.js.map +1 -1
  76. package/lib/engine-components/WebXRAvatar.d.ts +3 -0
  77. package/lib/engine-components/WebXRAvatar.js +20 -0
  78. package/lib/engine-components/WebXRAvatar.js.map +1 -1
  79. package/lib/engine-components/WebXRController.js +14 -8
  80. package/lib/engine-components/WebXRController.js.map +1 -1
  81. package/lib/engine-components/WebXRSync.js +3 -3
  82. package/lib/engine-components/WebXRSync.js.map +1 -1
  83. package/lib/engine-components/XRFlag.d.ts +2 -1
  84. package/lib/engine-components/XRFlag.js +1 -0
  85. package/lib/engine-components/XRFlag.js.map +1 -1
  86. package/lib/engine-components/ui/CanvasGroup.d.ts +1 -0
  87. package/lib/engine-components/ui/CanvasGroup.js +1 -0
  88. package/lib/engine-components/ui/CanvasGroup.js.map +1 -1
  89. package/lib/engine-components/ui/EventSystem.js +13 -4
  90. package/lib/engine-components/ui/EventSystem.js.map +1 -1
  91. package/lib/engine-components/ui/Graphic.d.ts +1 -0
  92. package/lib/engine-components/ui/Graphic.js +2 -0
  93. package/lib/engine-components/ui/Graphic.js.map +1 -1
  94. package/lib/engine-components/ui/Interfaces.d.ts +2 -0
  95. package/package.json +2 -2
  96. package/src/engine/engine_components.js +16 -0
  97. package/src/engine/engine_input.ts +62 -20
  98. package/src/engine/engine_physics.ts +2 -1
  99. package/src/engine/engine_playerview.ts +80 -0
  100. package/src/engine/engine_serialization.ts +3 -1
  101. package/src/engine/engine_serialization_core.ts +8 -0
  102. package/src/engine/engine_setup.ts +24 -0
  103. package/src/engine/engine_utils.ts +34 -8
  104. package/src/engine/extensions/NEEDLE_deferred_texture.ts +25 -19
  105. package/src/engine/extensions/NEEDLE_lighting_settings.ts +4 -2
  106. package/src/engine/extensions/extension_utils.ts +24 -12
  107. package/src/engine/extensions/extensions.ts +3 -2
  108. package/src/engine-components/Camera.ts +9 -1
  109. package/src/engine-components/Component.ts +1 -1
  110. package/src/engine-components/Light.ts +3 -0
  111. package/src/engine-components/OrbitControls.ts +3 -3
  112. package/src/engine-components/ParticleSystem.ts +25 -26
  113. package/src/engine-components/PlayerColor.ts +1 -1
  114. package/src/engine-components/Renderer.ts +11 -3
  115. package/src/engine-components/ScreenCapture.ts +312 -2
  116. package/src/engine-components/SpectatorCamera.ts +490 -195
  117. package/src/engine-components/SyncedCamera.ts +23 -22
  118. package/src/engine-components/SyncedRoom.ts +1 -0
  119. package/src/engine-components/VideoPlayer.ts +97 -21
  120. package/src/engine-components/Volume.ts +47 -4
  121. package/src/engine-components/WebARSessionRoot.ts +78 -28
  122. package/src/engine-components/WebXR.ts +51 -15
  123. package/src/engine-components/WebXRAvatar.ts +27 -2
  124. package/src/engine-components/WebXRController.ts +21 -15
  125. package/src/engine-components/WebXRSync.ts +3 -3
  126. package/src/engine-components/XRFlag.ts +1 -0
  127. package/src/engine-components/ui/CanvasGroup.ts +2 -0
  128. package/src/engine-components/ui/EventSystem.ts +21 -15
  129. package/src/engine-components/ui/Graphic.ts +3 -0
  130. package/src/engine-components/ui/Interfaces.ts +2 -0
@@ -12,6 +12,7 @@ import { serializeable } from "../engine/engine_serialization_decorator";
12
12
  import { Object3D } from "three";
13
13
  import { AvatarMarker } from "./WebXRAvatar";
14
14
  import { AssetReference } from "../engine/engine_addressables";
15
+ import { ViewDevice } from "../engine/engine_playerview";
15
16
 
16
17
  const SyncedCameraModelIdentifier = "SCAM";
17
18
  registerType(SyncedCameraModelIdentifier, SyncedCameraModel.getRootAsSyncedCameraModel);
@@ -33,8 +34,7 @@ class CameraModel {
33
34
  this.userId = connectionId;
34
35
  }
35
36
 
36
- send(sync: SyncedCamera, con: NetworkConnection) {
37
- const cam = sync.cam?.cam;
37
+ send(cam: THREE.Camera | null | undefined, con: NetworkConnection) {
38
38
  if (cam) {
39
39
  builder.clear();
40
40
  const guid = builder.createString(this.guid);
@@ -53,23 +53,22 @@ class CameraModel {
53
53
  }
54
54
  }
55
55
 
56
- declare type UserCamInfo =
57
- {
58
- obj: THREE.Object3D,
59
- lastUpdate: number;
60
- userId: string;
61
- };
56
+ declare type UserCamInfo = {
57
+ obj: THREE.Object3D,
58
+ lastUpdate: number;
59
+ userId: string;
60
+ };
62
61
 
63
62
  export class SyncedCamera extends Behaviour {
64
63
 
65
- getUserCamera(userId: string): THREE.Object3D | null {
64
+ static instances: UserCamInfo[] = [];
65
+
66
+ getCameraObject(userId: string): THREE.Object3D | null {
66
67
  const guid = this.userToCamMap[userId];
67
68
  if (!guid) return null;
68
69
  return this.remoteCams[guid].obj;
69
70
  }
70
71
 
71
- @serializeable(Camera)
72
- public cam: Camera | null = null;
73
72
  @serializeable([Object3D, AssetReference])
74
73
  public cameraPrefab: THREE.Object3D | null | AssetReference = null;
75
74
 
@@ -97,15 +96,8 @@ export class SyncedCamera extends Behaviour {
97
96
  if (this.cameraPrefab && "isObject3D" in this.cameraPrefab) {
98
97
  this.cameraPrefab.visible = false;
99
98
  }
100
-
101
99
  }
102
- }
103
100
 
104
- start() {
105
- if (!this.cam) {
106
- console.warn("Missing camera, fallback to main camera", this);
107
- this.cam = this.context.mainCameraComponent as Camera ?? null;
108
- }
109
101
  }
110
102
 
111
103
  onEnable(): void {
@@ -129,13 +121,17 @@ export class SyncedCamera extends Behaviour {
129
121
  delete this.remoteCams[guid];
130
122
  if (cam)
131
123
  delete this.userToCamMap[cam.userId];
124
+
125
+ SyncedCamera.instances.push(cam);
126
+ this.context.players.removePlayerView(cam.userId, ViewDevice.Browser);
132
127
  continue;
133
128
  }
134
129
  }
135
130
 
136
131
  if (WebXR.IsInWebXR) return;
137
132
 
138
- if (this.cam === null) {
133
+ const cam = this.context.mainCamera
134
+ if (cam === null) {
139
135
  this.enabled = false;
140
136
  return;
141
137
  }
@@ -146,8 +142,8 @@ export class SyncedCamera extends Behaviour {
146
142
  this._model = new CameraModel(this.context.connection.connectionId, this.context.connection.connectionId + "_camera");
147
143
  }
148
144
 
149
- const wp = utils.getWorldPosition(this.cam.cam);
150
- const wq = utils.getWorldQuaternion(this.cam.cam);
145
+ const wp = utils.getWorldPosition(cam);
146
+ const wq = utils.getWorldQuaternion(cam);
151
147
  if (wp.distanceTo(this._lastWorldPosition) > 0.001 || wq.angleTo(this._lastWorldQuaternion) > 0.01) {
152
148
  this._needsUpdate = true;
153
149
  }
@@ -163,7 +159,9 @@ export class SyncedCamera extends Behaviour {
163
159
 
164
160
  this._lastUpdateTime = this.context.time.realtimeSinceStartup;
165
161
  this._needsUpdate = false;
166
- this._model.send(this, this.context.connection);
162
+ this._model.send(cam, this.context.connection);
163
+ if (!this.context.isInXR)
164
+ this.context.players.setPlayerView(this.context.connection.connectionId, cam, ViewDevice.Browser);
167
165
  }
168
166
 
169
167
  private onReceivedRemoteCameraInfoBin(model: SyncedCameraModel) {
@@ -183,10 +181,12 @@ export class SyncedCamera extends Behaviour {
183
181
  rc.obj.visible = true;
184
182
  this.gameObject.add(instance);
185
183
  this.userToCamMap[userId] = guid;
184
+ SyncedCamera.instances.push(rc);
186
185
 
187
186
  const marker = GameObject.getOrAddComponent(instance, AvatarMarker);
188
187
  marker.connectionId = userId;
189
188
  marker.avatar = instance;
189
+
190
190
  }
191
191
  else {
192
192
  return;
@@ -194,6 +194,7 @@ export class SyncedCamera extends Behaviour {
194
194
  // console.log(this.remoteCams);
195
195
  }
196
196
  const obj = rc.obj;
197
+ this.context.players.setPlayerView(userId, obj, ViewDevice.Browser);
197
198
  rc.lastUpdate = this.context.time.realtimeSinceStartup;
198
199
  InstancingUtil.markDirty(obj);
199
200
  const pos = model.pos();
@@ -44,6 +44,7 @@ export class SyncedRoom extends Behaviour {
44
44
  }
45
45
 
46
46
  tryJoinRoom(call: number = 0): boolean {
47
+ if(call === undefined) call = 0;
47
48
  let hasRoomParameter = false;
48
49
  if (this.urlParameterName) {
49
50
  const val = utils.getParam(this.urlParameterName);
@@ -2,9 +2,10 @@ import { Behaviour } from "./Component";
2
2
  import * as THREE from "three";
3
3
  import { Material } from "material/Material";
4
4
  import { serializeable } from "../engine/engine_serialization_decorator";
5
- import { Object3D } from "three";
5
+ import { LinearFilter, Object3D, Texture } from "three";
6
6
  import { awaitInput } from "../engine/engine_input_utils";
7
7
  import { getParam } from "../engine/engine_utils";
8
+ import { Renderer } from "./Renderer";
8
9
 
9
10
  const debug = getParam("debugvideo");
10
11
 
@@ -20,22 +21,17 @@ export enum VideoSource {
20
21
  }
21
22
 
22
23
  export enum VideoAudioOutputMode {
23
- /// <summary>
24
- /// <para>Disable the embedded audio.</para>
25
- /// </summary>
26
- None,
27
- /// <summary>
28
- /// <para>Send the embedded audio into a specified AudioSource.</para>
29
- /// </summary>
30
- AudioSource,
31
- /// <summary>
32
- /// <para>Send the embedded audio direct to the platform's audio hardware.</para>
33
- /// </summary>
34
- Direct,
35
- /// <summary>
36
- /// <para>Send the embedded audio to the associated AudioSampleProvider.</para>
37
- /// </summary>
38
- APIOnly,
24
+ None = 0,
25
+ AudioSource = 1,
26
+ Direct = 2,
27
+ APIOnly = 3,
28
+ }
29
+
30
+ export enum VideoRenderMode {
31
+ CameraFarPlane = 0,
32
+ CameraNearPlane = 1,
33
+ RenderTexture = 2,
34
+ MaterialOverride = 3,
39
35
  }
40
36
 
41
37
  export class VideoPlayer extends Behaviour {
@@ -48,7 +44,16 @@ export class VideoPlayer extends Behaviour {
48
44
  playOnEnable?: boolean;
49
45
 
50
46
  @serializeable()
51
- targetMaterialProperty?: string;
47
+ private renderMode?: VideoRenderMode;
48
+
49
+ @serializeable()
50
+ private targetMaterialProperty?: string;
51
+
52
+ @serializeable(Renderer)
53
+ private targetMaterialRenderer?: Renderer;
54
+
55
+ @serializeable(Texture)
56
+ private targetTexture?: Texture;
52
57
 
53
58
  @serializeable()
54
59
  private time: number = 0;
@@ -250,11 +255,26 @@ export class VideoPlayer extends Behaviour {
250
255
  if (!this.enabled) return;
251
256
  if (!this.videoElement) return;
252
257
 
253
- const mat = this.gameObject["material"];
258
+ let target: Object3D | undefined = this.gameObject;
259
+
260
+ switch (this.renderMode) {
261
+ case VideoRenderMode.MaterialOverride:
262
+ target = this.targetMaterialRenderer?.gameObject;
263
+ break;
264
+ case VideoRenderMode.RenderTexture:
265
+ console.error("VideoPlayer renderTexture not implemented yet. Please use material override instead");
266
+ return;
267
+ }
268
+
269
+ if (!target) {
270
+ console.error("Missing target for video material renderer", this);
271
+ return;
272
+ }
273
+ const mat = target["material"];
254
274
  if (mat) {
255
275
  if (mat !== this.videoMaterial) {
256
276
  this.videoMaterial = mat.clone();
257
- this.gameObject["material"] = this.videoMaterial;
277
+ target["material"] = this.videoMaterial;
258
278
  }
259
279
 
260
280
  if (!this.targetMaterialProperty) {
@@ -305,4 +325,60 @@ export class VideoPlayer extends Behaviour {
305
325
  this.videoElement.style.visibility = "hidden";
306
326
  this.videoElement.style.display = "none";
307
327
  }
308
- }
328
+ }
329
+
330
+
331
+
332
+
333
+ // class VideoTexture extends Texture {
334
+
335
+ // get isVideoTexture() { return true; }
336
+
337
+ // constructor( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {
338
+
339
+ // super( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );
340
+
341
+ // this.minFilter = minFilter !== undefined ? minFilter : LinearFilter;
342
+ // this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
343
+
344
+ // this.generateMipmaps = false;
345
+
346
+ // const scope = this;
347
+
348
+ // function updateVideo() {
349
+
350
+ // scope.needsUpdate = true;
351
+ // video.requestVideoFrameCallback( updateVideo );
352
+
353
+ // }
354
+
355
+ // if ( 'requestVideoFrameCallback' in video ) {
356
+
357
+ // video.requestVideoFrameCallback( updateVideo );
358
+
359
+ // }
360
+
361
+ // }
362
+
363
+ // // clone() {
364
+
365
+ // // return new this.constructor( this.image ).copy( this );
366
+
367
+ // // }
368
+
369
+ // update() {
370
+
371
+ // const video = this.image;
372
+ // const hasVideoFrameCallback = 'requestVideoFrameCallback' in video;
373
+
374
+ // if ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) {
375
+
376
+ // this.needsUpdate = true;
377
+
378
+ // }
379
+
380
+ // }
381
+
382
+ // }
383
+
384
+ // export { VideoTexture };
@@ -2,6 +2,9 @@ import { Behaviour } from "./Component";
2
2
  import { NoToneMapping, LinearToneMapping, ACESFilmicToneMapping, ReinhardToneMapping } from "three";
3
3
  import { serializeable } from "../engine/engine_serialization_decorator";
4
4
  import { Context } from "../engine/engine_setup";
5
+ import { getParam } from "../engine/engine_utils";
6
+
7
+ const debug = getParam("debugvolume");
5
8
 
6
9
  export enum TonemappingMode {
7
10
  None = 0,
@@ -35,21 +38,41 @@ function resolveComponentType(data) {
35
38
  return VolumeComponent;
36
39
  }
37
40
 
41
+ const volumeKey = Symbol("volumeprofile");
42
+
38
43
  export class VolumeProfile {
39
44
  @serializeable([d => resolveComponentType(d), VolumeComponent])
40
45
  components?: VolumeComponent[];
41
46
 
42
-
43
47
  apply(context: Context) {
48
+ this.onUpdate(context, false);
49
+ }
50
+
51
+ unapply(context: Context) {
52
+ this.onUpdate(context, true);
53
+ }
54
+
55
+ private onUpdate(context: Context, remove: boolean) {
44
56
  if (!this.components) return;
57
+ const renderer = context.renderer;
58
+ const currentProfile = renderer[volumeKey];
59
+ const isActive = currentProfile !== undefined;
60
+ if (remove) {
61
+ // can not remove volume profile that is not active
62
+ if (!isActive) return;
63
+ }
64
+ else {
65
+ renderer[volumeKey] = this;
66
+ }
45
67
  for (const component of this.components) {
46
68
 
47
69
  if (component instanceof ToneMapping) {
48
70
  const tonemapping = component as ToneMapping;
49
- if (!component.active) {
71
+ if (!component.active || remove) {
50
72
  context.renderer.toneMapping = LinearToneMapping;
51
73
  continue;
52
74
  }
75
+ if (debug) console.log("VOLUME:", TonemappingMode[tonemapping.mode?.value ?? 0]);
53
76
  switch (tonemapping.mode?.value ?? 0) {
54
77
  case TonemappingMode.None:
55
78
  context.renderer.toneMapping = LinearToneMapping;
@@ -66,9 +89,11 @@ export class VolumeProfile {
66
89
  const colorAdjustments = component as ColorAdjustments;
67
90
  // unity range goes from -15..15
68
91
  // three.js range goes from 0..inf
69
- console.log(colorAdjustments.postExposure);
92
+ if (debug)
93
+ console.log(colorAdjustments.postExposure);
70
94
  const exposure = Math.pow(2, colorAdjustments.postExposure?.value ?? 0);
71
- context.renderer.toneMappingExposure = colorAdjustments.postExposure?.overrideState ? exposure : 1;
95
+ const useExposure = colorAdjustments.postExposure?.overrideState && !remove;
96
+ context.renderer.toneMappingExposure = useExposure ? exposure : 1;
72
97
  }
73
98
  }
74
99
  }
@@ -80,7 +105,25 @@ export class Volume extends Behaviour {
80
105
  @serializeable(VolumeProfile)
81
106
  sharedProfile?: VolumeProfile;
82
107
 
108
+ awake() {
109
+ if (debug) {
110
+ console.log(this);
111
+ console.log("Press P to toggle post processing");
112
+ window.addEventListener("keydown", (e) => {
113
+ if (e.key === "p") {
114
+ console.log("Toggle volume: " + this.name, !this.enabled);
115
+ this.enabled = !this.enabled;
116
+ }
117
+ });
118
+ }
119
+ }
120
+
83
121
  onEnable() {
122
+ if (debug) console.log("APPLY VOLUME", this)
84
123
  this.sharedProfile?.apply(this.context);
85
124
  }
125
+
126
+ onDisable() {
127
+ this.sharedProfile?.unapply(this.context);
128
+ }
86
129
  }
@@ -1,7 +1,7 @@
1
- import { Behaviour } from "./Component";
1
+ import { Behaviour, GameObject } from "./Component";
2
2
  import * as THREE from 'three'
3
- import { Object3D, XRPose } from "three";
4
- import { WebAR } from "./WebXR";
3
+ import { Matrix4, Object3D, XRPose } from "three";
4
+ import { WebAR, WebXR } from "./WebXR";
5
5
  import { InstancingUtil } from "./Renderer";
6
6
  import { serializeable } from "../engine/engine_serialization_decorator";
7
7
 
@@ -11,6 +11,10 @@ export class WebARSessionRoot extends Behaviour {
11
11
 
12
12
  webAR: WebAR | null = null;
13
13
 
14
+ get rig(): THREE.Object3D | undefined {
15
+ return this.webAR?.webxr.Rig;
16
+ }
17
+
14
18
  @serializeable()
15
19
  invertForward: boolean = false;
16
20
 
@@ -24,46 +28,57 @@ export class WebARSessionRoot extends Behaviour {
24
28
  this.setScale(val);
25
29
  }
26
30
 
31
+ private readonly _initalMatrix = new THREE.Matrix4();
32
+ private readonly _selectStartFn = this.onSelectStart.bind(this);
33
+ private readonly _selectEndFn = this.onSelectEnd.bind(this);
34
+
35
+ start() {
36
+ const xr = GameObject.findObjectOfType(WebXR);
37
+ if (xr) {
38
+ xr.Rig.updateMatrix();
39
+ this._initalMatrix.copy(xr.Rig.matrix);
40
+ }
41
+ }
42
+
27
43
  private _arScale: number = 5;
28
44
  private _rig: THREE.Object3D | null = null;
29
45
  private _startPose: THREE.Matrix4 | null = null;
30
46
  private _placementPose: THREE.Matrix4 | null = null;
31
47
  private _isTouching: boolean = false;
48
+ private _rigStartPose: THREE.Matrix4 | undefined | null = null;
32
49
 
33
50
  onBegin(session: THREE.XRSession) {
34
51
  this._placementPose = null;
35
52
  this.gameObject.visible = false;
36
53
  this.gameObject.matrixAutoUpdate = false;
37
54
  this._startPose = this.gameObject.matrix.clone();
38
- session.addEventListener('selectstart', this.onSelectStart.bind(this));
39
- session.addEventListener('selectend', this.onSelectEnd.bind(this));
40
- setTimeout(() => this.gameObject.visible = false, 1000);
55
+ this._rigStartPose = this.rig?.matrix.clone();
56
+ session.addEventListener('selectstart', this._selectStartFn);
57
+ session.addEventListener('selectend', this._selectEndFn);
58
+ // setTimeout(() => this.gameObject.visible = false, 1000); // TODO test on phone AR and Hololens if this was still needed
59
+
60
+ // console.log(this.rig?.position, this.rig?.quaternion, this.rig?.scale);
61
+ this.gameObject.visible = false;
62
+
63
+ if (this.rig) {
64
+ // reset rig to initial pose, this is helping the mix of immersive AR and immersive VR that we now have on quest
65
+ // where the rig can be moved and scaled by the user in VR mode and we use the rig position when entering
66
+ // immersive Ar right now to place the user/offset the session
67
+ this.rig.matrixAutoUpdate = true;
68
+ this._initalMatrix.decompose(this.rig.position, this.rig.quaternion, this.rig.scale);
69
+ }
41
70
  }
42
71
 
43
- onUpdate(rig: THREE.Object3D | null, _session: THREE.XRSession, pose: XRPose | null | undefined) {
72
+ onUpdate(rig: THREE.Object3D | null, _session: THREE.XRSession, pose: XRPose | null | undefined): boolean {
44
73
 
45
74
  if (pose && !this._placementPose) {
46
75
  if (this._isTouching) {
47
76
  if (this.webAR) this.webAR.setReticleActive(false);
48
- this._placementPose = new THREE.Matrix4().fromArray(pose.transform.matrix).invert();
49
- if (rig) {
50
-
51
- if (this.invertForward) {
52
- const rot = new THREE.Matrix4().makeRotationY(Math.PI);
53
- this._placementPose.premultiply(rot);
54
- }
55
- this._rig = rig;
56
-
57
- this.setScale(this.arScale);
58
- }
59
- else this._rig = null;
60
- // this.gameObject.matrix.copy(this._placementPose);
61
- // if (rig) {
62
- // this.gameObject.matrix.premultiply(rig.matrixWorld)
63
- // }
64
- this.gameObject.visible = true;
77
+ this.placeAt(rig, new THREE.Matrix4().fromArray(pose.transform.matrix).invert());
78
+ return true;
65
79
  }
66
80
  }
81
+ return false;
67
82
 
68
83
  // if (this._placementPose) {
69
84
  // this.gameObject.matrixAutoUpdate = false;
@@ -75,16 +90,47 @@ export class WebARSessionRoot extends Behaviour {
75
90
  // }
76
91
  }
77
92
 
93
+ placeAt(rig: THREE.Object3D | null, mat: Matrix4) {
94
+ if (!this._placementPose) this._placementPose = new THREE.Matrix4();
95
+ this._placementPose.copy(mat);
96
+ if (rig) {
97
+
98
+ if (this.invertForward) {
99
+ const rot = new THREE.Matrix4().makeRotationY(Math.PI);
100
+ this._placementPose.premultiply(rot);
101
+ }
102
+ this._rig = rig;
103
+
104
+ this.setScale(this.arScale);
105
+ }
106
+ else this._rig = null;
107
+ // this.gameObject.matrix.copy(this._placementPose);
108
+ // if (rig) {
109
+ // this.gameObject.matrix.premultiply(rig.matrixWorld)
110
+ // }
111
+ this.gameObject.visible = true;
112
+ }
113
+
78
114
  onEnd(rig: THREE.Object3D | null, _session: THREE.XRSession) {
79
115
  this._placementPose = null;
80
116
  this.gameObject.visible = false;
81
- if (this._startPose)
117
+ this.gameObject.matrixAutoUpdate = false;
118
+ if (this._startPose) {
82
119
  this.gameObject.matrix.copy(this._startPose);
83
- this.gameObject.matrixAutoUpdate = true;
84
- if (rig) rig.matrixAutoUpdate = true;
120
+ }
121
+ if (rig) {
122
+ rig.matrixAutoUpdate = true;
123
+ if (this._rigStartPose) {
124
+ this._rigStartPose.decompose(rig.position, rig.quaternion, rig.scale);
125
+ // console.log(rig.position, rig.quaternion, rig.scale);
126
+ }
127
+ }
85
128
  InstancingUtil.markDirty(this.gameObject, true);
86
129
  // HACK to fix physics being not in correct place after exiting AR
87
- setTimeout(() => this.gameObject.visible = true, 100);
130
+ setTimeout(() => {
131
+ this.gameObject.matrixAutoUpdate = true;
132
+ this.gameObject.visible = true;
133
+ }, 100);
88
134
  }
89
135
 
90
136
 
@@ -101,9 +147,13 @@ export class WebARSessionRoot extends Behaviour {
101
147
  if (!rig || !this._placementPose) {
102
148
  return;
103
149
  }
150
+ if (!this._rigStartPose) {
151
+ this._rigStartPose = rig.matrix.clone();
152
+ }
104
153
  rig.matrixAutoUpdate = false;
105
154
  rig.matrix.multiplyMatrices(new THREE.Matrix4().makeScale(scale, scale, scale), this._placementPose);
106
155
  rig.matrix.decompose(rig.position, rig.quaternion, rig.scale);
107
156
  rig.updateMatrixWorld();
157
+ console.log("Place", rig.position);
108
158
  }
109
159
  }