Changes
Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
This commit is contained in:
@@ -53,6 +53,10 @@ export function XRHudInWorld(props: XRHudInWorldProps) {
|
|||||||
const leftCtrl = useXRInputSourceState('controller', 'left');
|
const leftCtrl = useXRInputSourceState('controller', 'left');
|
||||||
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. */
|
||||||
|
const [pinned, setPinned] = useState(true);
|
||||||
|
/** Forces re-anchor on next frame (used by "trazer" / unpin→pin). */
|
||||||
|
const reanchorRequested = useRef(true);
|
||||||
|
|
||||||
const panelRef = useRef<THREE.Group>(null);
|
const panelRef = useRef<THREE.Group>(null);
|
||||||
const wristRef = useRef<THREE.Group>(null);
|
const wristRef = useRef<THREE.Group>(null);
|
||||||
@@ -70,15 +74,30 @@ export function XRHudInWorld(props: XRHudInWorldProps) {
|
|||||||
lastABtn.current = pressed;
|
lastABtn.current = pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Floating panel ~70cm in front of head, yaw-locked, damped
|
// Floating panel:
|
||||||
|
// • If pinned and already anchored once → don't move it (fixed in space).
|
||||||
|
// • If unpinned → continuously follow head with damping.
|
||||||
|
// • 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);
|
const fwd = new THREE.Vector3(0, -0.05, -0.7).applyQuaternion(camera.quaternion);
|
||||||
targetPos.current.copy(camera.position).add(fwd);
|
const wantPos = new THREE.Vector3().copy(camera.position).add(fwd);
|
||||||
const euler = new THREE.Euler().setFromQuaternion(camera.quaternion, 'YXZ');
|
const euler = new THREE.Euler().setFromQuaternion(camera.quaternion, 'YXZ');
|
||||||
targetQuat.current.setFromEuler(new THREE.Euler(0, euler.y, 0, 'YXZ'));
|
const wantQuat = new THREE.Quaternion().setFromEuler(new THREE.Euler(0, euler.y, 0, 'YXZ'));
|
||||||
|
|
||||||
|
if (reanchorRequested.current) {
|
||||||
|
targetPos.current.copy(wantPos);
|
||||||
|
targetQuat.current.copy(wantQuat);
|
||||||
|
panelRef.current.position.copy(wantPos);
|
||||||
|
panelRef.current.quaternion.copy(wantQuat);
|
||||||
|
reanchorRequested.current = false;
|
||||||
|
} else if (!pinned) {
|
||||||
|
targetPos.current.copy(wantPos);
|
||||||
|
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.
|
||||||
|
}
|
||||||
|
|
||||||
// Wrist toggle follows left controller
|
// Wrist toggle follows left controller
|
||||||
if (wristRef.current) {
|
if (wristRef.current) {
|
||||||
@@ -102,7 +121,14 @@ export function XRHudInWorld(props: XRHudInWorldProps) {
|
|||||||
<WristToggle ref={wristRef} open={open} onToggle={() => setOpen((v) => !v)} />
|
<WristToggle ref={wristRef} open={open} onToggle={() => setOpen((v) => !v)} />
|
||||||
{open && (
|
{open && (
|
||||||
<group ref={panelRef}>
|
<group ref={panelRef}>
|
||||||
<FloatingPanel tab={tab} setTab={setTab} {...props} />
|
<FloatingPanel
|
||||||
|
tab={tab}
|
||||||
|
setTab={setTab}
|
||||||
|
pinned={pinned}
|
||||||
|
onTogglePin={() => setPinned((v) => !v)}
|
||||||
|
onRecenter={() => { reanchorRequested.current = true; }}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
</group>
|
</group>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user