From a2cb9c931cb94167143a0fdfe0976a64b44c2dfb Mon Sep 17 00:00:00 2001 From: FelipeR2U Date: Tue, 27 Jul 2021 13:02:53 -0300 Subject: [PATCH 1/4] Two Fingers - Separate Rotation/Translation --- .../src/three-components/ARRenderer.ts | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/packages/model-viewer/src/three-components/ARRenderer.ts b/packages/model-viewer/src/three-components/ARRenderer.ts index 178cc6db73..2c4e26736d 100644 --- a/packages/model-viewer/src/three-components/ARRenderer.ts +++ b/packages/model-viewer/src/three-components/ARRenderer.ts @@ -33,6 +33,7 @@ const INIT_FRAMES = 30; // estimation, which will be used once available in WebXR. const AR_SHADOW_INTENSITY = 0.3; const ROTATION_RATE = 1.5; +const ROTATION_THRESHOLD = 0.05; // Angle down (towards bottom of screen) from camera center ray to use for hit // testing against the floor. This makes placement faster and more intuitive // assuming the phone is in portrait mode. This seems to be a reasonable @@ -78,9 +79,9 @@ const hitPosition = new Vector3(); const camera = new PerspectiveCamera(45, 1, 0.1, 100); export class ARRenderer extends EventDispatcher { - public threeRenderer: WebGLRenderer; - public currentSession: XRSession|null = null; - public placeOnWall = false; + threeRenderer: WebGLRenderer; + currentSession: XRSession|null = null; + placeOnWall = false; private placementBox: PlacementBox|null = null; private lastTick: number|null = null; @@ -107,6 +108,7 @@ export class ARRenderer extends EventDispatcher { private placementComplete = false; private isTranslating = false; private isRotating = false; + private isScaling = false; private isTwoFingering = false; private lastDragPosition = new Vector3(); private firstRatio = 0; @@ -472,19 +474,20 @@ export class ARRenderer extends EventDispatcher { session.addEventListener('selectend', this.onSelectEnd); session .requestHitTestSourceForTransientInput({profile: 'generic-touchscreen'}) - .then(hitTestSource => { + .then((hitTestSource) => { this.transientHitTestSource = hitTestSource; }); } private getTouchLocation(): Vector3|null { const {axes} = this.inputSource!.gamepad; - let location = this.placementBox!.getExpandedHit( + const location = this.placementBox!.getExpandedHit( this.presentedScene!, axes[0], axes[1]); if (location != null) { vector3.copy(location).sub(this.presentedScene!.getCamera().position); - if (vector3.length() > MAX_DISTANCE) + if (vector3.length() > MAX_DISTANCE) { return null; + } } return location; } @@ -509,7 +512,7 @@ export class ARRenderer extends EventDispatcher { null; } - public moveToFloor(frame: XRFrame) { + moveToFloor(frame: XRFrame) { const hitSource = this.initialHitSource; if (hitSource == null) { return; @@ -577,11 +580,12 @@ export class ARRenderer extends EventDispatcher { private onSelectEnd = () => { this.isTranslating = false; this.isRotating = false; + this.isScaling = false; this.isTwoFingering = false; this.inputSource = null; this.goalPosition.y += this.placementBox!.offsetHeight * this.presentedScene!.scale.x; - this.placementBox!.show = false + this.placementBox!.show = false; }; private fingerPolar(fingers: XRTransientInputHitTestResult[]): @@ -625,10 +629,15 @@ export class ARRenderer extends EventDispatcher { this.isTwoFingering = false; } else { const {separation, deltaYaw} = this.fingerPolar(fingers); - if (this.placeOnWall === false) { + this.isRotating = Math.abs(deltaYaw) > ROTATION_THRESHOLD; + if (!this.isRotating && !this.isScaling) { + this.isScaling = true; + this.firstRatio = separation / scene.scale.x; + } + if (this.placeOnWall === false && this.isRotating) { this.goalYaw += deltaYaw; } - if (scene.canScale) { + if (scene.canScale && this.isScaling) { const scale = separation / this.firstRatio; this.goalScale = (scale < SCALE_SNAP_HIGH && scale > SCALE_SNAP_LOW) ? 1 : scale; @@ -725,7 +734,7 @@ export class ARRenderer extends EventDispatcher { /** * Only public to make it testable. */ - public onWebXRFrame(time: number, frame: XRFrame) { + onWebXRFrame(time: number, frame: XRFrame) { this.frame = frame; ++this.frames; const refSpace = this.threeRenderer.xr.getReferenceSpace()!; @@ -751,7 +760,7 @@ export class ARRenderer extends EventDispatcher { // isn't really supported at this point, but make a best-effort // attempt to render other views also, using the first view // as the main viewpoint. - let isFirstView: boolean = true; + let isFirstView = true; for (const view of pose.views) { this.updateView(view); From d82cb0623eeced56dfc850b90dbd32aab1deaa07 Mon Sep 17 00:00:00 2001 From: FelipeR2U Date: Tue, 27 Jul 2021 13:10:15 -0300 Subject: [PATCH 2/4] Revert auto-fix, rename moveToFloor --- .../src/three-components/ARRenderer.ts | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/model-viewer/src/three-components/ARRenderer.ts b/packages/model-viewer/src/three-components/ARRenderer.ts index 2c4e26736d..4e4fbb9568 100644 --- a/packages/model-viewer/src/three-components/ARRenderer.ts +++ b/packages/model-viewer/src/three-components/ARRenderer.ts @@ -79,9 +79,9 @@ const hitPosition = new Vector3(); const camera = new PerspectiveCamera(45, 1, 0.1, 100); export class ARRenderer extends EventDispatcher { - threeRenderer: WebGLRenderer; - currentSession: XRSession|null = null; - placeOnWall = false; + public threeRenderer: WebGLRenderer; + public currentSession: XRSession|null = null; + public placeOnWall = false; private placementBox: PlacementBox|null = null; private lastTick: number|null = null; @@ -474,20 +474,19 @@ export class ARRenderer extends EventDispatcher { session.addEventListener('selectend', this.onSelectEnd); session .requestHitTestSourceForTransientInput({profile: 'generic-touchscreen'}) - .then((hitTestSource) => { + .then(hitTestSource => { this.transientHitTestSource = hitTestSource; }); } private getTouchLocation(): Vector3|null { const {axes} = this.inputSource!.gamepad; - const location = this.placementBox!.getExpandedHit( + let location = this.placementBox!.getExpandedHit( this.presentedScene!, axes[0], axes[1]); if (location != null) { vector3.copy(location).sub(this.presentedScene!.getCamera().position); - if (vector3.length() > MAX_DISTANCE) { + if (vector3.length() > MAX_DISTANCE) return null; - } } return location; } @@ -512,7 +511,7 @@ export class ARRenderer extends EventDispatcher { null; } - moveToFloor(frame: XRFrame) { + public moveToPlane(frame: XRFrame) { const hitSource = this.initialHitSource; if (hitSource == null) { return; @@ -734,7 +733,7 @@ export class ARRenderer extends EventDispatcher { /** * Only public to make it testable. */ - onWebXRFrame(time: number, frame: XRFrame) { + public onWebXRFrame(time: number, frame: XRFrame) { this.frame = frame; ++this.frames; const refSpace = this.threeRenderer.xr.getReferenceSpace()!; @@ -760,12 +759,12 @@ export class ARRenderer extends EventDispatcher { // isn't really supported at this point, but make a best-effort // attempt to render other views also, using the first view // as the main viewpoint. - let isFirstView = true; + let isFirstView: boolean = true; for (const view of pose.views) { this.updateView(view); if (isFirstView) { - this.moveToFloor(frame); + this.moveToPlane(frame); this.processInput(frame); From 7a6351217123ca00d15a08339cfe3ec26a2b4add Mon Sep 17 00:00:00 2001 From: FelipeR2U Date: Tue, 27 Jul 2021 13:25:58 -0300 Subject: [PATCH 3/4] Fix never setting scaling to false --- packages/model-viewer/src/three-components/ARRenderer.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/model-viewer/src/three-components/ARRenderer.ts b/packages/model-viewer/src/three-components/ARRenderer.ts index 4e4fbb9568..aa0134b43f 100644 --- a/packages/model-viewer/src/three-components/ARRenderer.ts +++ b/packages/model-viewer/src/three-components/ARRenderer.ts @@ -628,8 +628,10 @@ export class ARRenderer extends EventDispatcher { this.isTwoFingering = false; } else { const {separation, deltaYaw} = this.fingerPolar(fingers); - this.isRotating = Math.abs(deltaYaw) > ROTATION_THRESHOLD; - if (!this.isRotating && !this.isScaling) { + if (Math.abs(deltaYaw) > ROTATION_THRESHOLD) { + this.isScaling = false; + this.isRotating = true; + } else if (!this.isScaling) { this.isScaling = true; this.firstRatio = separation / scene.scale.x; } From 9496a5516206dc72efe56e9e5acf9cf6d73c5a15 Mon Sep 17 00:00:00 2001 From: FelipeR2U Date: Tue, 27 Jul 2021 13:31:37 -0300 Subject: [PATCH 4/4] Remove unecessary firstRatio, set scaling to true on second finger --- packages/model-viewer/src/three-components/ARRenderer.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/model-viewer/src/three-components/ARRenderer.ts b/packages/model-viewer/src/three-components/ARRenderer.ts index aa0134b43f..e833a69da0 100644 --- a/packages/model-viewer/src/three-components/ARRenderer.ts +++ b/packages/model-viewer/src/three-components/ARRenderer.ts @@ -571,8 +571,6 @@ export class ARRenderer extends EventDispatcher { } else if (fingers.length === 2) { box.show = true; this.isTwoFingering = true; - const {separation} = this.fingerPolar(fingers); - this.firstRatio = separation / scene.scale.x; } }; @@ -650,6 +648,7 @@ export class ARRenderer extends EventDispatcher { // to scaling instead. this.isTranslating = false; this.isRotating = false; + this.isScaling = true; this.isTwoFingering = true; const {separation} = this.fingerPolar(fingers); this.firstRatio = separation / scale;