Skip to content

Commit 64167d4

Browse files
fix rotation which twisting happens with two fingers in ar mode (#5058)
1 parent 0548040 commit 64167d4

File tree

1 file changed

+34
-16
lines changed

1 file changed

+34
-16
lines changed

packages/model-viewer/src/three-components/ARRenderer.ts

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ export class ARRenderer extends EventDispatcher<
157157
private pitchDamper = new Damper();
158158
private rollDamper = new Damper();
159159
private scaleDamper = new Damper();
160+
private wasTwoFingering = false;
160161

161162
private onExitWebXRButtonContainerClick = () => this.stopPresenting();
162163

@@ -813,8 +814,15 @@ export class ARRenderer extends EventDispatcher<
813814
} else if (fingers.length === 2) {
814815
box.show = true;
815816
this.isTwoHandInteraction = true;
816-
const {separation} = this.fingerPolar(fingers);
817-
this.firstRatio = separation / scene.pivot.scale.x;
817+
const {separation, angle} = this.fingerPolar(fingers);
818+
this.lastAngle = angle; // Initialize lastAngle, do not update goalYaw
819+
if (this.firstRatio === 0) {
820+
this.firstRatio = separation / scene.pivot.scale.x;
821+
}
822+
if (scene.canScale) {
823+
this.setScale(separation);
824+
}
825+
return;
818826
}
819827
};
820828

@@ -829,7 +837,7 @@ export class ARRenderer extends EventDispatcher<
829837
};
830838

831839
private fingerPolar(fingers: XRTransientInputHitTestResult[]):
832-
{separation: number, deltaYaw: number} {
840+
{separation: number, deltaYaw: number, angle: number} {
833841
const fingerOne = fingers[0].inputSource.gamepad!.axes;
834842
const fingerTwo = fingers[1].inputSource.gamepad!.axes;
835843
const deltaX = fingerTwo[0] - fingerOne[0];
@@ -841,10 +849,10 @@ export class ARRenderer extends EventDispatcher<
841849
} else if (deltaYaw < -Math.PI) {
842850
deltaYaw += 2 * Math.PI;
843851
}
844-
this.lastAngle = angle;
845852
return {
846853
separation: Math.sqrt(deltaX * deltaX + deltaY * deltaY),
847-
deltaYaw: deltaYaw
854+
deltaYaw: deltaYaw,
855+
angle: angle
848856
};
849857
}
850858

@@ -862,24 +870,34 @@ export class ARRenderer extends EventDispatcher<
862870
const scene = this.presentedScene!;
863871
const scale = scene.pivot.scale.x;
864872

865-
// Check for two-finger interaction first
873+
// Robust two-finger gesture handling
866874
if (fingers.length === 2) {
867-
this.isTranslating = false;
868-
this.isRotating = false;
869-
this.isTwoHandInteraction = true;
870-
const {separation} = this.fingerPolar(fingers);
871-
if (this.firstRatio === 0) {
875+
if (!this.wasTwoFingering) {
876+
// New two-finger gesture starting
877+
const {separation, angle} = this.fingerPolar(fingers);
872878
this.firstRatio = separation / scale;
879+
this.lastAngle = angle;
880+
this.wasTwoFingering = true;
881+
this.isTwoHandInteraction = true;
882+
// Do not apply rotation or scale on this frame
883+
return;
873884
}
885+
// Ongoing two-finger gesture
886+
const {separation, deltaYaw, angle} = this.fingerPolar(fingers);
887+
this.goalYaw += deltaYaw;
888+
this.lastAngle = angle;
874889
if (scene.canScale) {
875890
this.setScale(separation);
876891
}
892+
this.isTwoHandInteraction = true;
877893
return;
878-
} else if (this.isTwoHandInteraction && fingers.length < 2) {
879-
// If we lose the second finger, stop scaling
880-
this.isTwoHandInteraction = false;
881-
this.firstRatio = 0;
882-
return;
894+
} else {
895+
if (this.wasTwoFingering) {
896+
// Two-finger gesture ended
897+
this.wasTwoFingering = false;
898+
this.isTwoHandInteraction = false;
899+
this.firstRatio = 0;
900+
}
883901
}
884902

885903
if (!this.isTranslating && !this.isTwoHandInteraction && !this.isRotating) {

0 commit comments

Comments
 (0)