Corrigiu painel do modo Ar
X-Lovable-Edit-ID: edt-ddabb83a-766e-4d4f-84c8-609c78508f43 Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
This commit is contained in:
@@ -51,10 +51,13 @@ const WristToggle = forwardRef<THREE.Group, { open: boolean; onToggle: () => voi
|
|||||||
export function XRHudInWorld(props: XRHudInWorldProps) {
|
export function XRHudInWorld(props: XRHudInWorldProps) {
|
||||||
const { camera } = useThree();
|
const { camera } = useThree();
|
||||||
const leftCtrl = useXRInputSourceState('controller', 'left');
|
const leftCtrl = useXRInputSourceState('controller', 'left');
|
||||||
|
const rightCtrl = useXRInputSourceState('controller', 'right');
|
||||||
const [open, setOpen] = useState(true);
|
const [open, setOpen] = useState(true);
|
||||||
const [tab, setTab] = useState<Tab>('scene');
|
const [tab, setTab] = useState<Tab>('scene');
|
||||||
/** When pinned, the panel stays fixed in world space and does NOT follow the head. */
|
/** When pinned, the panel stays fixed in world space and does NOT follow the head. */
|
||||||
const [pinned, setPinned] = useState(true);
|
const [pinned, setPinned] = useState(true);
|
||||||
|
/** While true, the panel is glued to the right controller (drag mode). */
|
||||||
|
const [dragging, setDragging] = useState(false);
|
||||||
/** Forces re-anchor on next frame (used by "trazer" / unpin→pin). */
|
/** Forces re-anchor on next frame (used by "trazer" / unpin→pin). */
|
||||||
const reanchorRequested = useRef(true);
|
const reanchorRequested = useRef(true);
|
||||||
|
|
||||||
@@ -63,6 +66,10 @@ export function XRHudInWorld(props: XRHudInWorldProps) {
|
|||||||
const targetPos = useRef(new THREE.Vector3());
|
const targetPos = useRef(new THREE.Vector3());
|
||||||
const targetQuat = useRef(new THREE.Quaternion());
|
const targetQuat = useRef(new THREE.Quaternion());
|
||||||
const lastABtn = useRef(false);
|
const lastABtn = useRef(false);
|
||||||
|
/** Cached offset from controller to panel at drag start. */
|
||||||
|
const dragOffsetPos = useRef(new THREE.Vector3());
|
||||||
|
const dragOffsetQuat = useRef(new THREE.Quaternion());
|
||||||
|
const dragInitialized = useRef(false);
|
||||||
|
|
||||||
useFrame(() => {
|
useFrame(() => {
|
||||||
// Toggle via left A button (Quest Touch buttons[4])
|
// Toggle via left A button (Quest Touch buttons[4])
|
||||||
@@ -79,24 +86,47 @@ export function XRHudInWorld(props: XRHudInWorldProps) {
|
|||||||
// • If unpinned → continuously follow head with damping.
|
// • If unpinned → continuously follow head with damping.
|
||||||
// • On (re)anchor request → snap target once and stop.
|
// • On (re)anchor request → snap target once and stop.
|
||||||
if (panelRef.current && open) {
|
if (panelRef.current && open) {
|
||||||
const fwd = new THREE.Vector3(0, -0.05, -0.7).applyQuaternion(camera.quaternion);
|
// Drag mode → panel rigidly follows right controller using captured offset.
|
||||||
const wantPos = new THREE.Vector3().copy(camera.position).add(fwd);
|
if (dragging) {
|
||||||
const euler = new THREE.Euler().setFromQuaternion(camera.quaternion, 'YXZ');
|
const ctrlObj = rightCtrl?.object;
|
||||||
const wantQuat = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, euler.y, 0, 'YXZ'));
|
if (ctrlObj) {
|
||||||
|
ctrlObj.updateMatrixWorld();
|
||||||
|
const cPos = new THREE.Vector3().setFromMatrixPosition(ctrlObj.matrixWorld);
|
||||||
|
const cQuat = new THREE.Quaternion().setFromRotationMatrix(ctrlObj.matrixWorld);
|
||||||
|
if (!dragInitialized.current) {
|
||||||
|
// Capture current panel pose relative to controller
|
||||||
|
const invQ = cQuat.clone().invert();
|
||||||
|
dragOffsetPos.current
|
||||||
|
.copy(panelRef.current.position).sub(cPos).applyQuaternion(invQ);
|
||||||
|
dragOffsetQuat.current.copy(invQ).multiply(panelRef.current.quaternion);
|
||||||
|
dragInitialized.current = true;
|
||||||
|
}
|
||||||
|
const newPos = dragOffsetPos.current.clone().applyQuaternion(cQuat).add(cPos);
|
||||||
|
const newQuat = cQuat.clone().multiply(dragOffsetQuat.current);
|
||||||
|
panelRef.current.position.copy(newPos);
|
||||||
|
panelRef.current.quaternion.copy(newQuat);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (dragInitialized.current) dragInitialized.current = false;
|
||||||
|
const fwd = new THREE.Vector3(0, -0.05, -0.7).applyQuaternion(camera.quaternion);
|
||||||
|
const wantPos = new THREE.Vector3().copy(camera.position).add(fwd);
|
||||||
|
const euler = new THREE.Euler().setFromQuaternion(camera.quaternion, 'YXZ');
|
||||||
|
const wantQuat = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, euler.y, 0, 'YXZ'));
|
||||||
|
|
||||||
if (reanchorRequested.current) {
|
if (reanchorRequested.current) {
|
||||||
targetPos.current.copy(wantPos);
|
targetPos.current.copy(wantPos);
|
||||||
targetQuat.current.copy(wantQuat);
|
targetQuat.current.copy(wantQuat);
|
||||||
panelRef.current.position.copy(wantPos);
|
panelRef.current.position.copy(wantPos);
|
||||||
panelRef.current.quaternion.copy(wantQuat);
|
panelRef.current.quaternion.copy(wantQuat);
|
||||||
reanchorRequested.current = false;
|
reanchorRequested.current = false;
|
||||||
} else if (!pinned) {
|
} else if (!pinned) {
|
||||||
targetPos.current.copy(wantPos);
|
targetPos.current.copy(wantPos);
|
||||||
targetQuat.current.copy(wantQuat);
|
targetQuat.current.copy(wantQuat);
|
||||||
panelRef.current.position.lerp(targetPos.current, 0.12);
|
panelRef.current.position.lerp(targetPos.current, 0.12);
|
||||||
panelRef.current.quaternion.slerp(targetQuat.current, 0.18);
|
panelRef.current.quaternion.slerp(targetQuat.current, 0.18);
|
||||||
|
}
|
||||||
|
// pinned + already anchored → leave panel where it is.
|
||||||
}
|
}
|
||||||
// pinned + already anchored → leave panel where it is.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrist toggle follows left controller
|
// Wrist toggle follows left controller
|
||||||
@@ -126,6 +156,8 @@ export function XRHudInWorld(props: XRHudInWorldProps) {
|
|||||||
setTab={setTab}
|
setTab={setTab}
|
||||||
pinned={pinned}
|
pinned={pinned}
|
||||||
onTogglePin={() => setPinned((v) => !v)}
|
onTogglePin={() => setPinned((v) => !v)}
|
||||||
|
dragging={dragging}
|
||||||
|
onToggleDrag={() => setDragging((v) => !v)}
|
||||||
onRecenter={() => { reanchorRequested.current = true; }}
|
onRecenter={() => { reanchorRequested.current = true; }}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
@@ -136,12 +168,14 @@ export function XRHudInWorld(props: XRHudInWorldProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function FloatingPanel({
|
function FloatingPanel({
|
||||||
tab, setTab, pinned, onTogglePin, onRecenter, ...p
|
tab, setTab, pinned, onTogglePin, dragging, onToggleDrag, onRecenter, ...p
|
||||||
}: {
|
}: {
|
||||||
tab: Tab;
|
tab: Tab;
|
||||||
setTab: (t: Tab) => void;
|
setTab: (t: Tab) => void;
|
||||||
pinned: boolean;
|
pinned: boolean;
|
||||||
onTogglePin: () => void;
|
onTogglePin: () => void;
|
||||||
|
dragging: boolean;
|
||||||
|
onToggleDrag: () => void;
|
||||||
onRecenter: () => void;
|
onRecenter: () => void;
|
||||||
} & XRHudInWorldProps) {
|
} & XRHudInWorldProps) {
|
||||||
const tabs: { id: Tab; label: string; icon: string }[] = [
|
const tabs: { id: Tab; label: string; icon: string }[] = [
|
||||||
@@ -158,13 +192,20 @@ function FloatingPanel({
|
|||||||
anchorX="left" anchorY="middle">
|
anchorX="left" anchorY="middle">
|
||||||
TrackSteelXR · HUD AR
|
TrackSteelXR · HUD AR
|
||||||
</Text>
|
</Text>
|
||||||
{/* Pin / Recenter controls (replace the previous static "A button" hint) */}
|
{/* Pin / Drag / Recenter — anchored to top-right, kept inside the panel.
|
||||||
<group position={[W / 2 - 0.012, H / 2 - 0.018, 0.002]}>
|
Group origin is at the right edge with margin; buttons extend leftward. */}
|
||||||
<XR3DButton position={[-0.045, 0, 0]} size={[0.05, 0.022]}
|
<group position={[W / 2 - 0.008, H / 2 - 0.018, 0.002]}>
|
||||||
|
{/* Trazer (recenter) — rightmost, half-width 0.029 from origin */}
|
||||||
|
<XR3DButton position={[-0.029, 0, 0]} size={[0.054, 0.022]}
|
||||||
|
label="⎚ Trazer" onClick={onRecenter} fontSize={0.007} />
|
||||||
|
{/* Mover (drag with right controller) */}
|
||||||
|
<XR3DButton position={[-0.088, 0, 0]} size={[0.054, 0.022]}
|
||||||
|
label={dragging ? '✋ Solte' : '✋ Mover'}
|
||||||
|
active={dragging} onClick={onToggleDrag} fontSize={0.007} />
|
||||||
|
{/* Pin */}
|
||||||
|
<XR3DButton position={[-0.144, 0, 0]} size={[0.054, 0.022]}
|
||||||
label={pinned ? '📌 Fixo' : '↻ Solto'}
|
label={pinned ? '📌 Fixo' : '↻ Solto'}
|
||||||
active={pinned} onClick={onTogglePin} fontSize={0.007} />
|
active={pinned} onClick={onTogglePin} fontSize={0.007} />
|
||||||
<XR3DButton position={[0.012, 0, 0]} size={[0.058, 0.022]}
|
|
||||||
label="⎚ Trazer" onClick={onRecenter} fontSize={0.007} />
|
|
||||||
</group>
|
</group>
|
||||||
|
|
||||||
<group position={[0, H / 2 - 0.045, 0.001]}>
|
<group position={[0, H / 2 - 0.045, 0.001]}>
|
||||||
|
|||||||
Reference in New Issue
Block a user