Reverted to commit c93e56640d
This commit is contained in:
@@ -1,25 +1,9 @@
|
||||
import { useRef, ReactNode, useEffect } from 'react';
|
||||
import { useFrame, useThree } from '@react-three/fiber';
|
||||
import { useFrame } from '@react-three/fiber';
|
||||
import * as THREE from 'three';
|
||||
import { useControllerGrab, ControllerGrabSnapshot } from '@/hooks/useControllerGrab';
|
||||
import { useModelStore } from '@/stores/useModelStore';
|
||||
|
||||
function triggerHaptic(session: XRSession | null, handedness: 'left' | 'right', intensity = 0.5, duration = 40) {
|
||||
if (!session) return;
|
||||
try {
|
||||
for (const source of session.inputSources) {
|
||||
if (source.handedness === handedness) {
|
||||
const gp = source.gamepad;
|
||||
if (gp && gp.hapticActuators && gp.hapticActuators.length > 0) {
|
||||
gp.hapticActuators[0].pulse(intensity, duration).catch(() => {});
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('[XR][Haptic] erro ao vibrar controle no grab:', e);
|
||||
}
|
||||
}
|
||||
|
||||
interface XRGrabbableProps {
|
||||
/**
|
||||
* Quando true (padrão), o grip duplo aplica ZOOM uniforme além da rotação.
|
||||
@@ -75,7 +59,6 @@ export function XRGrabbable({ allowScale = true, lockedActive = false, onGrabSta
|
||||
const dual = useRef<DualGrabRecord | null>(null);
|
||||
const haloRef = useRef<THREE.Mesh>(null);
|
||||
const everGrabbed = useRef(false);
|
||||
const pendingReset = useRef(false);
|
||||
|
||||
// Reset scale to 1 (position/rotation kept) whenever resetScale() is called.
|
||||
const scaleResetNonce = useModelStore((s) => s.scaleResetNonce);
|
||||
@@ -87,21 +70,9 @@ export function XRGrabbable({ allowScale = true, lockedActive = false, onGrabSta
|
||||
single.current = null;
|
||||
}, [scaleResetNonce]);
|
||||
|
||||
const { gl } = useThree();
|
||||
|
||||
useFrame((_state) => {
|
||||
useFrame(() => {
|
||||
const group = groupRef.current;
|
||||
if (!group) return;
|
||||
|
||||
if (pendingReset.current) {
|
||||
group.position.set(0, 0, 0);
|
||||
group.rotation.set(0, 0, 0);
|
||||
group.scale.set(1, 1, 1);
|
||||
pendingReset.current = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const session = gl.xr.getSession();
|
||||
const snap: ControllerGrabSnapshot = grab.current;
|
||||
const L = snap.left;
|
||||
const R = snap.right;
|
||||
@@ -124,50 +95,6 @@ export function XRGrabbable({ allowScale = true, lockedActive = false, onGrabSta
|
||||
haloRef.current.visible = maxGrip > 0.05;
|
||||
}
|
||||
|
||||
const commitGrabTransforms = () => {
|
||||
const activeId = useModelStore.getState().activeModelId;
|
||||
if (!activeId) return;
|
||||
const active = useModelStore.getState().models.find(m => m.id === activeId);
|
||||
if (!active) return;
|
||||
|
||||
const ft = { ...active.fineTuning };
|
||||
|
||||
// 1. ESCALA DO MODELO: Lê o fator de escala do filho imediato para converter a translação do mundo real
|
||||
const child = group.children[0];
|
||||
const finalScaleFactor = child ? child.scale.x : 1.0;
|
||||
|
||||
ft.posX += group.position.x / finalScaleFactor;
|
||||
ft.posY += group.position.y / finalScaleFactor;
|
||||
ft.posZ += group.position.z / finalScaleFactor;
|
||||
|
||||
// 2. ROTAÇÃO TRIDIMENSIONAL: Combina quaternions de rotação para evitar gimbal lock ao soltar
|
||||
const currentQuat = new THREE.Quaternion().setFromEuler(
|
||||
new THREE.Euler(
|
||||
(active.fineTuning.rotX * Math.PI) / 180,
|
||||
(active.fineTuning.rotY * Math.PI) / 180,
|
||||
(active.fineTuning.rotZ * Math.PI) / 180,
|
||||
'XYZ'
|
||||
)
|
||||
);
|
||||
const finalQuat = group.quaternion.clone().multiply(currentQuat);
|
||||
const finalEuler = new THREE.Euler().setFromQuaternion(finalQuat, 'XYZ');
|
||||
|
||||
ft.rotX = (finalEuler.x * 180) / Math.PI;
|
||||
ft.rotY = (finalEuler.y * 180) / Math.PI;
|
||||
ft.rotZ = (finalEuler.z * 180) / Math.PI;
|
||||
|
||||
// 3. ESCALA LOCAL DO GRAB: Multiplica a escala anterior
|
||||
ft.scale = (ft.scale ?? 1) * group.scale.x;
|
||||
|
||||
useModelStore.getState().setFineTuning(ft);
|
||||
|
||||
// Sinaliza reset pendente para o próximo frame
|
||||
pendingReset.current = true;
|
||||
|
||||
triggerHaptic(session, 'left', 0.25, 12);
|
||||
triggerHaptic(session, 'right', 0.25, 12);
|
||||
};
|
||||
|
||||
// ─── Two-hand mode (orbit + zoom, sempre) ────────────────────
|
||||
if (lActive && rActive) {
|
||||
_tmpVecL.setFromMatrixPosition(L.gripWorld);
|
||||
@@ -189,13 +116,12 @@ export function XRGrabbable({ allowScale = true, lockedActive = false, onGrabSta
|
||||
};
|
||||
single.current = null;
|
||||
if (!everGrabbed.current) { everGrabbed.current = true; onGrabStart?.(); }
|
||||
triggerHaptic(session, 'left', 0.5, 30);
|
||||
triggerHaptic(session, 'right', 0.5, 30);
|
||||
console.log('[XR][grab] ◆ TWO-HAND start (orbit+zoom)');
|
||||
}
|
||||
|
||||
const d = dual.current;
|
||||
const deltaQuat = new THREE.Quaternion().setFromUnitVectors(d.startAxis, axisNow);
|
||||
// ZOOM só quando allowScale=true. Caso contrário, mantém escala 1× (só orbita).
|
||||
const scaleRatio = allowScale
|
||||
? THREE.MathUtils.clamp(distNow / d.startDist, 0.1, 10)
|
||||
: 1;
|
||||
@@ -215,7 +141,6 @@ export function XRGrabbable({ allowScale = true, lockedActive = false, onGrabSta
|
||||
return;
|
||||
} else if (dual.current) {
|
||||
console.log('[XR][grab] ◆ TWO-HAND end');
|
||||
commitGrabTransforms();
|
||||
dual.current = null;
|
||||
}
|
||||
|
||||
@@ -231,7 +156,6 @@ export function XRGrabbable({ allowScale = true, lockedActive = false, onGrabSta
|
||||
const offsetWorld = new THREE.Vector3().subVectors(groupWorldPos, ctrlPos);
|
||||
single.current = { hand: activeHand, offsetWorld };
|
||||
if (!everGrabbed.current) { everGrabbed.current = true; onGrabStart?.(); }
|
||||
triggerHaptic(session, activeHand, 0.45, 25);
|
||||
console.log(`[XR][grab] ● ONE-HAND start (${activeHand}) — pan only`);
|
||||
}
|
||||
|
||||
@@ -244,11 +168,8 @@ export function XRGrabbable({ allowScale = true, lockedActive = false, onGrabSta
|
||||
const invParent = new THREE.Matrix4().copy(group.parent.matrixWorld).invert();
|
||||
targetWorldPos.applyMatrix4(invParent);
|
||||
}
|
||||
|
||||
group.position.copy(targetWorldPos);
|
||||
} else if (single.current) {
|
||||
console.log('[XR][grab] ● ONE-HAND end');
|
||||
commitGrabTransforms();
|
||||
single.current = null;
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user