@needle-tools/engine 2.26.0-pre → 2.26.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.
@@ -4,21 +4,22 @@ import * as THREE from "three";
4
4
  import { OrbitControls } from "./OrbitControls";
5
5
  import { WebXR, WebXREvent } from "./WebXR";
6
6
  import { AvatarMarker } from "./WebXRAvatar";
7
- import { XRFlag, XRStateFlag } from "./XRFlag";
7
+ import { XRStateFlag } from "./XRFlag";
8
8
  import { SmoothFollow } from "./SmoothFollow";
9
- import { setWorldPosition, setWorldQuaternion, getWorldPosition, getWorldQuaternion } from "../engine/engine_three_utils";
9
+ import { setWorldPosition, setWorldQuaternion, getWorldPosition, getWorldQuaternion, lookAtInverse } from "../engine/engine_three_utils";
10
+ import { ArrayCamera } from "three";
11
+ import { KeyCode } from "../engine/engine_input";
10
12
 
11
13
  export class SpectatorCamera extends Behaviour {
12
14
 
13
15
  cam: Camera | null = null;
14
16
 
15
- private _firstPersonMode: boolean | undefined = false;
17
+ private _firstPersonMode: boolean | undefined = true;
16
18
  get firstPersonMode(): boolean {
17
- return true;
18
19
  return this._firstPersonMode ?? false;
19
20
  }
20
- set firstPersonMode(_val: boolean) {
21
- // this._firstPersonMode = val;
21
+ set firstPersonMode(val: boolean) {
22
+ this._firstPersonMode = val;
22
23
  // if (this._firstPersonMode) this.enableFirstPersonMode();
23
24
  // else this.enableThirdPersonMode();
24
25
  }
@@ -62,7 +63,6 @@ export class SpectatorCamera extends Behaviour {
62
63
  private orbit: OrbitControls | null = null;
63
64
  private firstPersonFollow: SmoothFollow | null = null;
64
65
  private spectatorUIDomElement: HTMLElement | null = null;
65
- private _avatar: AvatarMarker | null = null;
66
66
 
67
67
  private eventSub_WebXRRequestStartEvent: Function | null = null;
68
68
  private eventSub_WebXRStartEvent: Function | null = null;
@@ -72,14 +72,6 @@ export class SpectatorCamera extends Behaviour {
72
72
 
73
73
  GameObject.setActive(this.gameObject, false);
74
74
 
75
- const uiQuery = "#spectator-camera-ui";
76
- this.spectatorUIDomElement = this.context.domElement.querySelector(uiQuery);
77
- if (!this.spectatorUIDomElement) {
78
- console.warn("Could not find spectator camera UI element", uiQuery);
79
- }
80
- this.spectatorUIDomElement?.classList.add("hidden");
81
-
82
-
83
75
  if (!this.isSupportedPlatform()) {
84
76
  console.log("Disable spectator cam", window.navigator.userAgent, this);
85
77
  return;
@@ -93,6 +85,22 @@ export class SpectatorCamera extends Behaviour {
93
85
  // this.cam = GameObject.addNewComponent(this.gameObject, Camera) as Camera;
94
86
  }
95
87
 
88
+ const uiQuery = "#spectator-camera-ui";
89
+ this.spectatorUIDomElement = this.context.domElement.querySelector(uiQuery);
90
+ if (!this.spectatorUIDomElement) {
91
+ console.warn("Could not find spectator camera UI element", uiQuery);
92
+ // this.spectatorUIDomElement = document.createElement("div");
93
+ // this.spectatorUIDomElement.id = "spectator-camera-ui";
94
+ // this.spectatorUIDomElement.classList.add("desktop");
95
+ // this.context.domElement.appendChild(this.spectatorUIDomElement);
96
+
97
+ // const toggle = document.createElement("button");
98
+ // toggle.id = "toggle-spectator-view";
99
+ // this.spectatorUIDomElement.appendChild(toggle);
100
+ }
101
+ this.spectatorUIDomElement?.classList.add("hidden");
102
+
103
+
96
104
  if (this.cam) {
97
105
  this.cam.enabled = true;
98
106
  this._orbitStartPos.copy(getWorldPosition(this.cam.cam));
@@ -189,53 +197,37 @@ export class SpectatorCamera extends Behaviour {
189
197
  private onXRSessionStart(_evt) {
190
198
  this._sessionHasStarted = true;
191
199
  this.updateUI();
200
+
201
+ if (this.context.mainCamera) {
202
+ const cam = this.context.renderer.xr.getCamera(this.context.mainCamera) as ArrayCamera;
203
+ this.setupFollowMode(cam);
204
+ }
192
205
  }
193
206
 
194
207
  private onXRSessionEnded(_evt) {
195
208
  this._sessionHasStarted = false;
209
+ this._firstPersonIsSetup = false;
196
210
  this.spectatorUIDomElement?.classList.add("hidden");
197
211
  GameObject.setActive(this.gameObject, false);
198
212
  }
199
213
 
200
214
  private _sessionHasStarted: boolean = false;
201
- private _isFirstStart = true;
202
215
  private _firstPersonIsSetup: boolean = false;
203
216
  private _orbitStartPos: THREE.Vector3 = new THREE.Vector3();
204
217
  private _orbitStartRot: THREE.Quaternion = new THREE.Quaternion();
205
218
  private _orbitStartPos2: THREE.Vector3 = new THREE.Vector3();
206
219
  private _orbitStartRot2: THREE.Quaternion = new THREE.Quaternion();
207
220
 
208
-
209
221
  // TODO: only show Spectator cam for DesktopVR;
210
222
  // don't show for AR, don't show on Quest
211
223
  // TODO: properly align cameras on enter/exit VR, seems currently spectator cam breaks alignment
212
224
  onAfterRender(): void {
213
225
  if (!this.cam) return;
214
226
 
215
- // if (this.context.time.frameCount % 120 === 0) {
216
- // this.firstPersonMode = !this.firstPersonMode;
217
- // }
218
-
219
- if (this.firstPersonMode) {
220
- if (!this._firstPersonIsSetup) {
221
- if (!this._avatar || this._avatar?.destroyed) {
222
- for (const av of AvatarMarker.instances) {
223
- if (av.avatar && "isLocalAvatar" in av.avatar && av.avatar?.isLocalAvatar) {
224
- this._avatar = av;
225
- const head = av.avatar.head;
226
- if (!head) continue;
227
- this.setupFollowMode(head);
228
- }
229
- }
230
- }
231
- // else {
232
- // if (this.context.mainCamera) {
233
- // this.setupFollowMode(this.context.mainCamera, true);
234
- // }
235
- // }
236
- }
237
- }
238
-
227
+ if(this.context.input.isKeyDown(KeyCode.KEY_S))
228
+ this.firstPersonMode = !this.firstPersonMode;
229
+
230
+ this.updateFollowSettings();
239
231
 
240
232
  const renderer = this.context.renderer;
241
233
  const xrWasEnabled = renderer.xr.enabled;
@@ -295,20 +287,22 @@ export class SpectatorCamera extends Behaviour {
295
287
  this.resetAvatarFlags();
296
288
  }
297
289
 
298
- private setupFollowMode(object: THREE.Object3D, flipForward: boolean = true) {
290
+ private setupFollowMode(object: THREE.Object3D) {
299
291
  if (!object) return;
300
292
  if (!this.cam) return;
301
293
  if (this._firstPersonIsSetup) return;
302
294
  this._firstPersonIsSetup = true;
303
295
 
304
- const target = object.add(new THREE.Object3D());
305
- target.add(new THREE.AxesHelper());
296
+
306
297
  this.firstPersonFollow = GameObject.addNewComponent(this.cam.gameObject, SmoothFollow);
298
+
299
+ const target = new THREE.Object3D();
300
+ object.add(target);
301
+ target.add(new THREE.AxesHelper(.2))
307
302
  this.firstPersonFollow.target = target;
308
- this.firstPersonFollow.followFactor = 12;
309
- this.firstPersonFollow.rotateFactor = 5;
310
- // TODO: figure out why this needs flipping when we use the spectator cam without an Avatar
311
- if (flipForward) this.firstPersonFollow.flipForward = true;
303
+
304
+ this.updateFollowSettings();
305
+
312
306
  const perspectiveCamera = this.context.mainCamera as THREE.PerspectiveCamera;
313
307
  if (perspectiveCamera) {
314
308
  this.cam.cam.near = perspectiveCamera.near;
@@ -318,6 +312,26 @@ export class SpectatorCamera extends Behaviour {
318
312
  if (this.orbit) this.orbit.enabled = false;
319
313
  }
320
314
 
315
+ private updateFollowSettings() {
316
+ const target = this.firstPersonFollow?.target;
317
+ if (!target || !this.firstPersonFollow) return;
318
+ if (this.firstPersonMode === false) {
319
+ this.firstPersonFollow.followFactor = 3;
320
+ this.firstPersonFollow.rotateFactor = 2;
321
+ this.firstPersonFollow.flipForward = false;
322
+ target.position.set(0, .5, 1.5);
323
+ target.quaternion.identity();
324
+ // lookAtInverse(target, new THREE.Vector3(0, 0, 0));
325
+ }
326
+ else {
327
+ target.position.set(0, 0, 0);
328
+ target.quaternion.identity();
329
+ this.firstPersonFollow.followFactor = 12;
330
+ this.firstPersonFollow.rotateFactor = 5;
331
+ this.firstPersonFollow.flipForward = false;
332
+ }
333
+ }
334
+
321
335
  private setAvatarFlagsBeforeRender() {
322
336
  for (const av of AvatarMarker.instances) {
323
337
  if (av.avatar && "isLocalAvatar" in av.avatar) {
@@ -249,6 +249,7 @@ export class WebXRController extends Behaviour {
249
249
  this.webXR.Rig?.add(this.controller);
250
250
  this.webXR.Rig?.add(this.raycastLine);
251
251
  this.raycastLine?.add(this._raycastHitPoint);
252
+ this._raycastHitPoint.visible = false;
252
253
  this.hand.add(this.handPointerModel);
253
254
  console.log("ADDED TO RIG", this.webXR.Rig);
254
255