@@ -3,6 +3,7 @@
|
|
3
3
|
export * from "./engine_addressables.js";
|
4
4
|
export * from "./engine_application.js";
|
5
5
|
export * from "./engine_assetdatabase.js";
|
6
|
+
export { getCameraController,setAutoFitEnabled, setCameraController, useForAutoFit } from "./engine_camera.js"
|
6
7
|
export * from "./engine_components.js";
|
7
8
|
export * from "./engine_components_internal.js";
|
8
9
|
export * from "./engine_components_internal.js";
|
@@ -20,7 +21,7 @@
|
|
20
21
|
export * from "./engine_hot_reload.js";
|
21
22
|
export * from "./engine_input.js";
|
22
23
|
export { InstancingUtil } from "./engine_instancing.js";
|
23
|
-
export { hasCommercialLicense,hasIndieLicense, hasProLicense } from "./engine_license.js";
|
24
|
+
export { hasCommercialLicense, hasIndieLicense, hasProLicense } from "./engine_license.js";
|
24
25
|
export * from "./engine_lifecycle_api.js";
|
25
26
|
export * from "./engine_math.js";
|
26
27
|
export * from "./engine_networking.js";
|
@@ -32,8 +32,9 @@
|
|
32
32
|
return obj[autofit] !== false;
|
33
33
|
}
|
34
34
|
|
35
|
-
/**
|
35
|
+
/**
|
36
|
+
* Enable or disable autofitting for the given object
|
37
|
+
*/
|
36
38
|
export function setAutoFitEnabled(obj: Object3D, enabled: boolean): void {
|
37
39
|
obj[autofit] = enabled;
|
38
|
-
|
39
40
|
}
|
@@ -1,14 +1,13 @@
|
|
1
|
-
import { AxesHelper, DoubleSide, Matrix4, Mesh, MeshBasicMaterial, Object3D, Plane,
|
1
|
+
import { AxesHelper, DoubleSide, Matrix4, Mesh, MeshBasicMaterial, Object3D, Plane, Raycaster, RingGeometry, Scene, Vector3 } from "three";
|
2
2
|
|
3
3
|
import { isDevEnvironment, showBalloonWarning } from "../../engine/debug/index.js";
|
4
4
|
import { AssetReference } from "../../engine/engine_addressables.js";
|
5
5
|
import { Context } from "../../engine/engine_context.js";
|
6
|
-
import { ObjectUtils, PrimitiveType } from "../../engine/engine_create_objects.js";
|
7
6
|
import { destroy, instantiate } from "../../engine/engine_gameobject.js";
|
8
7
|
import { InputEventQueue, NEPointerEvent } from "../../engine/engine_input.js";
|
9
8
|
import { serializable } from "../../engine/engine_serialization_decorator.js";
|
10
9
|
import type { IComponent, IGameObject } from "../../engine/engine_types.js";
|
11
|
-
import { getParam, isAndroidDevice
|
10
|
+
import { getParam, isAndroidDevice } from "../../engine/engine_utils.js";
|
12
11
|
import { NeedleXRController, type NeedleXREventArgs, type NeedleXRHitTestResult, NeedleXRSession } from "../../engine/engine_xr.js";
|
13
12
|
import { Behaviour, GameObject } from "../Component.js";
|
14
13
|
|
@@ -190,6 +189,7 @@
|
|
190
189
|
|
191
190
|
}
|
192
191
|
else {
|
192
|
+
// Update anchors, if any
|
193
193
|
if (this._anchor && args.xr.referenceSpace) {
|
194
194
|
const pose = args.xr.frame.getPose(this._anchor.anchorSpace, args.xr.referenceSpace);
|
195
195
|
if (pose && this.context.time.frame % 20 === 0) {
|
@@ -204,7 +204,7 @@
|
|
204
204
|
}
|
205
205
|
}
|
206
206
|
|
207
|
-
//
|
207
|
+
// Scene has been placed
|
208
208
|
if (this.arTouchTransform) {
|
209
209
|
if (!this.userInput) this.userInput = new WebXRSessionRootUserInput(this.context);
|
210
210
|
this.userInput?.enable();
|
@@ -255,9 +255,22 @@
|
|
255
255
|
reticle.visible = false;
|
256
256
|
}
|
257
257
|
|
258
|
-
reticle.position.
|
259
|
-
reticle.quaternion.
|
258
|
+
reticle["lastPos"] = reticle["lastPos"] || hit.position.clone();
|
259
|
+
reticle["lastQuat"] = reticle["lastQuat"] || hit.quaternion.clone();
|
260
|
+
// reticle["targetPos"] = reticle["targetPos"] || hit.position.clone();
|
261
|
+
// reticle["targetQuat"] = reticle["targetQuat"] || hit.quaternion.clone();
|
262
|
+
|
263
|
+
// TODO we likely want the reticle itself to be placed _exactly_ and then the visuals being lerped,
|
264
|
+
// Right now this leads to a "rotation glitch" when going from a horizontal to a vertical surface
|
265
|
+
reticle.position.copy(reticle["lastPos"].lerp(hit.position, this.context.time.deltaTime / .1));
|
266
|
+
reticle["lastPos"].copy(reticle.position);
|
267
|
+
reticle.quaternion.copy(reticle["lastQuat"].slerp(hit.quaternion, this.context.time.deltaTime / .05));
|
268
|
+
reticle["lastQuat"].copy(reticle.quaternion);
|
269
|
+
|
270
|
+
// TODO make sure original reticle asset scale is respected, or document it should be uniformly scaled
|
271
|
+
// scale *= this.customReticle?.asset?.scale?.x || 1;
|
260
272
|
reticle.scale.set(scale, scale, scale);
|
273
|
+
|
261
274
|
// if (this.invertForward) {
|
262
275
|
// reticle.rotateY(Math.PI);
|
263
276
|
// }
|
@@ -317,6 +330,10 @@
|
|
317
330
|
|
318
331
|
this.onRevertSceneChanges();
|
319
332
|
|
333
|
+
// TODO: we should probably use the non-lerped position and quaternion here
|
334
|
+
reticle.position.copy(reticle["lastPos"]);
|
335
|
+
reticle.quaternion.copy(reticle["lastQuat"]);
|
336
|
+
|
320
337
|
this.onApplyPose(reticle);
|
321
338
|
|
322
339
|
if (this.useXRAnchor) {
|
@@ -362,7 +379,12 @@
|
|
362
379
|
}
|
363
380
|
}
|
364
381
|
|
382
|
+
private upVec: Vector3 = new Vector3(0, 1, 0);
|
383
|
+
private lookPoint: Vector3 = new Vector3();
|
384
|
+
private worldUpVec: Vector3 = new Vector3(0, 1, 0);
|
385
|
+
|
365
386
|
private applyViewBasedTransform(reticle: Object3D) {
|
387
|
+
|
366
388
|
// Make reticle face the user to unify the placement experience across devices.
|
367
389
|
// The pose that we're receiving from the hit test varies between devices:
|
368
390
|
// - Quest: currently aligned to the mesh that was hit (depends on room setup), has changed a couple times
|
@@ -372,10 +394,37 @@
|
|
372
394
|
const reticleGo = reticle as GameObject;
|
373
395
|
const camWP = camGo.worldPosition;
|
374
396
|
const reticleWp = reticleGo.worldPosition;
|
375
|
-
|
376
|
-
|
377
|
-
reticle.lookAt(camWP);
|
397
|
+
|
398
|
+
this.upVec.set(0,1,0).applyQuaternion(reticle.quaternion);
|
378
399
|
|
400
|
+
// upVec may be pointing AWAY from us, we have to flip it if that's the case
|
401
|
+
const camPos = camGo.worldPosition;
|
402
|
+
if (camPos) {
|
403
|
+
const camToReticle = reticle.position.clone().sub(camPos);
|
404
|
+
const angle = camToReticle.angleTo(this.upVec);
|
405
|
+
if (angle < Math.PI / 2) {
|
406
|
+
this.upVec.negate();
|
407
|
+
}
|
408
|
+
}
|
409
|
+
|
410
|
+
const upAngle = this.upVec.angleTo(this.worldUpVec) * 180 / Math.PI;
|
411
|
+
// For debugging look angle for AR placement
|
412
|
+
// Gizmos.DrawDirection(reticle.position, upVec, "blue", 0.1);
|
413
|
+
// Gizmos.DrawLabel(reticle.position, upAngle.toFixed(2), 0.1);
|
414
|
+
|
415
|
+
const angleForWallPlacement = 30;
|
416
|
+
if ((upAngle > angleForWallPlacement && upAngle < 180 - angleForWallPlacement) ||
|
417
|
+
(upAngle < -angleForWallPlacement && upAngle > -180 + angleForWallPlacement)) {
|
418
|
+
|
419
|
+
this.lookPoint.copy(reticle.position).add(this.upVec);
|
420
|
+
this.lookPoint.y = reticle.position.y;
|
421
|
+
reticle.lookAt(this.lookPoint);
|
422
|
+
}
|
423
|
+
else {
|
424
|
+
camWP.y = reticleWp.y;
|
425
|
+
reticle.lookAt(camWP);
|
426
|
+
}
|
427
|
+
|
379
428
|
// TODO: ability to scale the reticle so that we can fit the scene depending on the view angle or distance to the reticle.
|
380
429
|
// Currently, doing this leads to wrong placement of the scene.
|
381
430
|
/*
|