Needle Engine

Changes between version 3.46.0-beta.1 and 3.46.0-beta.2
Files changed (4) hide show
  1. src/engine-components/Camera.ts +10 -2
  2. src/engine/xr/NeedleXRSession.ts +2 -1
  3. src/engine-components/webxr/WebARSessionRoot.ts +20 -6
  4. src/engine-components/webxr/controllers/XRControllerMovement.ts +7 -2
src/engine-components/Camera.ts CHANGED
@@ -75,20 +75,28 @@
75
75
  set nearClipPlane(val) {
76
76
  const changed = this._nearClipPlane != val;
77
77
  this._nearClipPlane = val;
78
- if (this._cam && changed) {
78
+ if (this._cam && (changed || this._cam.near != val)) {
79
79
  this._cam.near = val;
80
80
  this._cam.updateProjectionMatrix();
81
81
  }
82
82
  }
83
83
  private _nearClipPlane: number = 0.1;
84
84
 
85
+ applyClippingPlane() {
86
+ if (this._cam) {
87
+ this._cam.near = this._nearClipPlane;
88
+ this._cam.far = this._farClipPlane;
89
+ this._cam.updateProjectionMatrix();
90
+ }
91
+ }
92
+
85
93
  /** The camera's far clipping plane */
86
94
  get farClipPlane(): number { return this._farClipPlane; }
87
95
  @serializable()
88
96
  set farClipPlane(val) {
89
97
  const changed = this._farClipPlane != val;
90
98
  this._farClipPlane = val;
91
- if (this._cam && changed) {
99
+ if (this._cam && (changed || this._cam.far != val)) {
92
100
  this._cam.far = val;
93
101
  this._cam.updateProjectionMatrix();
94
102
  }
src/engine/xr/NeedleXRSession.ts CHANGED
@@ -989,10 +989,11 @@
989
989
  // apply the clearflags at the beginning of the next frame
990
990
  this.context.pre_update_oneshot_callbacks.push(() => {
991
991
  this.context.mainCameraComponent?.applyClearFlags()
992
+ this.context.mainCameraComponent?.applyClippingPlane();
992
993
  });
993
994
 
994
995
  invokeXRSessionEnd({ session: this });
995
-
996
+
996
997
  for (const listener of NeedleXRSession._xrEndListeners) {
997
998
  listener({ xr: this });
998
999
  }
src/engine-components/webxr/WebARSessionRoot.ts CHANGED
@@ -7,7 +7,7 @@
7
7
  import { Gizmos } from "../../engine/engine_gizmos.js";
8
8
  import { InputEventQueue, NEPointerEvent } from "../../engine/engine_input.js";
9
9
  import { serializable } from "../../engine/engine_serialization_decorator.js";
10
- import { getBoundingBox } from "../../engine/engine_three_utils.js";
10
+ import { getBoundingBox, getTempVector } from "../../engine/engine_three_utils.js";
11
11
  import type { IComponent, IGameObject } from "../../engine/engine_types.js";
12
12
  import { getParam, isAndroidDevice } from "../../engine/engine_utils.js";
13
13
  import { NeedleXRController, type NeedleXREventArgs, type NeedleXRHitTestResult, NeedleXRSession } from "../../engine/engine_xr.js";
@@ -213,7 +213,8 @@
213
213
 
214
214
  // in pass through mode we want to place the scene using an XR controller
215
215
  let controllersDidHit = false;
216
- if (args.xr.isPassThrough && args.xr.controllers.length > 0) {
216
+ // when auto placing we just use the user's view
217
+ if (args.xr.isPassThrough && args.xr.controllers.length > 0 && !this.autoPlace) {
217
218
  for (const ctrl of args.xr.controllers) {
218
219
  // with this we can only place with the left / first controller right now
219
220
  // we also only have one reticle... this should probably be refactored a bit so we can have multiple reticles
@@ -273,7 +274,6 @@
273
274
  // save the hit test
274
275
  this._hits[i] = hit.hit;
275
276
  let reticle = this._reticle[i];
276
-
277
277
  if (!reticle) {
278
278
  if (this.customReticle) {
279
279
  if (this.customReticle.asset) {
@@ -300,7 +300,6 @@
300
300
  reticle.matrixAutoUpdate = false;
301
301
  reticle.visible = false;
302
302
  }
303
-
304
303
  reticle["lastPos"] = reticle["lastPos"] || hit.position.clone();
305
304
  reticle["lastQuat"] = reticle["lastQuat"] || hit.quaternion.clone();
306
305
  // reticle["targetPos"] = reticle["targetPos"] || hit.position.clone();
@@ -336,8 +335,23 @@
336
335
  }
337
336
 
338
337
  if (this.autoPlace) {
339
- reticle.visible = false;
340
- this.onPlaceScene(null);
338
+ this.upVec.set(0, 1, 0).applyQuaternion(reticle.quaternion);
339
+ const isUp = this.upVec.dot(getTempVector(0, 1, 0)) > 0.9;
340
+ if (isUp) {
341
+ // We want the reticle to be at a suitable spot for a moment before we place the scene (not place it immediately)
342
+ let autoplace_timer = reticle["autoplace:timer"] || 0;
343
+ if (autoplace_timer >= 1) {
344
+ reticle.visible = false;
345
+ this.onPlaceScene(null);
346
+ }
347
+ else {
348
+ autoplace_timer += this.context.time.deltaTime;
349
+ reticle["autoplace:timer"] = autoplace_timer;
350
+ }
351
+ }
352
+ else {
353
+ reticle["autoplace:timer"] = 0;
354
+ }
341
355
  }
342
356
  }
343
357
 
src/engine-components/webxr/controllers/XRControllerMovement.ts CHANGED
@@ -14,6 +14,7 @@
14
14
  import { Behaviour, GameObject } from "../../Component.js"
15
15
  import { TeleportTarget } from "../TeleportTarget.js";
16
16
  import type { XRMovementBehaviour } from "../types.js";
17
+ import { hasPointerEventComponent } from "../../ui/PointerEvents.js";
17
18
 
18
19
  const debug = getParam("debugwebxr");
19
20
 
@@ -257,8 +258,12 @@
257
258
  continue;
258
259
  }
259
260
 
260
- const hit = this.context.physics.raycastFromRay(ctrl.ray, { testObject: this.hitPointRaycastFilter, precise: false })[0];
261
- this._hitDistances[i] = hit?.distance;
261
+ const hits = this.context.physics.raycastFromRay(ctrl.ray, { testObject: this.hitPointRaycastFilter, precise: false });
262
+ const hit = hits.find(h => {
263
+ // Only render hits on interactable objects
264
+ return hasPointerEventComponent(h.object)
265
+ });
266
+ this._hitDistances[i] = hit?.distance || 0;
262
267
 
263
268
  let disc = this._hitDiscs[i];
264
269
  if (disc) // save the hit object on the disc