🚀 Auto-deploy: melhoria no snap e medição AR em 28/05/2026 21:40:54

This commit is contained in:
2026-05-28 21:40:54 +00:00
parent b270ca0bfd
commit d47fb9dd37
3 changed files with 34 additions and 8 deletions
+14 -5
View File
@@ -21,6 +21,8 @@ interface SingleGrabRecord {
hand: 'left' | 'right';
/** Offset (world) = groupWorldPos - controllerWorldPos at grab start. */
offsetWorld: THREE.Vector3;
/** Altura Y de mundo da peça no momento em que o grab iniciou, para travar horizontalmente */
startWorldY: number;
}
interface DualGrabRecord {
@@ -44,8 +46,8 @@ const _tmpQuat = new THREE.Quaternion();
/**
* Touch Plus grip mapping (Meta Quest 3):
*
* • One-hand grip → **PAN ONLY** (translação). A rotação e a escala
* da peça NÃO mudam — o grip simples só arrasta.
* • One-hand grip → **PAN ONLY (RESTRICTED HORIZONTALLY)** (translação). A rotação e a escala
* da peça NÃO mudam — o grip simples só arrasta no plano horizontal X/Z para preservar a altura Y calibrada.
* • Two-hand grip → ORBIT (eixo entre as mãos) + ZOOM uniforme
* (distância entre os controles). O zoom está sempre ligado.
*
@@ -144,7 +146,7 @@ export function XRGrabbable({ allowScale = true, lockedActive = false, onGrabSta
dual.current = null;
}
// ─── One-hand mode (PAN ONLY) ────────────────────────────────
// ─── One-hand mode (PAN ONLY - HORIZONTAL X/Z) ────────────────
const activeHand: 'left' | 'right' | null = lActive ? 'left' : rActive ? 'right' : null;
if (activeHand) {
const slot = activeHand === 'left' ? L : R;
@@ -154,14 +156,21 @@ export function XRGrabbable({ allowScale = true, lockedActive = false, onGrabSta
group.updateMatrixWorld();
const groupWorldPos = new THREE.Vector3().setFromMatrixPosition(group.matrixWorld);
const offsetWorld = new THREE.Vector3().subVectors(groupWorldPos, ctrlPos);
single.current = { hand: activeHand, offsetWorld };
// Salva a altura Y original de mundo
const startWorldY = groupWorldPos.y;
single.current = { hand: activeHand, offsetWorld, startWorldY };
if (!everGrabbed.current) { everGrabbed.current = true; onGrabStart?.(); }
console.log(`[XR][grab] ● ONE-HAND start (${activeHand}) — pan only`);
console.log(`[XR][grab] ● ONE-HAND start (${activeHand}) — horizontal pan`);
}
// Target world position = controller + initial offset
const targetWorldPos = new THREE.Vector3().addVectors(ctrlPos, single.current.offsetWorld);
// Trava a translação no plano horizontal (XZ de mundo), preservando a altura Y original de calibração!
targetWorldPos.y = single.current.startWorldY;
// Convert to parent-local position (preserve current rotation/scale)
if (group.parent) {
group.parent.updateMatrixWorld();
+5
View File
@@ -615,6 +615,9 @@ function GridFloorRow() {
const setGridAutoFollow = useModelStore((s) => s.setGridAutoFollow);
const setGridY = useModelStore((s) => s.setGridY);
const nudgeGridY = useModelStore((s) => s.nudgeGridY);
const gridCalibMode = useModelStore((s) => s.gridCalibMode);
const setGridCalibMode = useModelStore((s) => s.setGridCalibMode);
const placeAtFloor = () => {
// Headset eye Y minus avg standing eye height (1.6 m)
const floor = camera.position.y - 1.6;
@@ -635,6 +638,8 @@ function GridFloorRow() {
onClick={() => nudgeGridY(0.01)} />
<XR3DButton position={[0.07, -0.175, 0]} size={[0.075, 0.022]} label="Pousar chão"
onClick={placeAtFloor} />
<XR3DButton position={[0.155, -0.175, 0]} size={[0.075, 0.022]} label={gridCalibMode ? "Calibrando" : "Calibrar"}
active={gridCalibMode} onClick={() => setGridCalibMode(!gridCalibMode)} />
</group>
);
}