c6d50b07a4
Co-authored-by: Reifonas <211114984+Reifonas@users.noreply.github.com>
5.1 KiB
5.1 KiB
Objetivo
Alinhar o comportamento dos controles Touch Plus (Meta Quest 3) ao padrão pedido:
- Grip = único responsável por mover a peça (pan, zoom, orbit).
- Trigger = apenas seleção, medição e ações pontuais (nunca move/rotaciona a peça).
- Thumbstick = navegação do usuário (teletransporte/recuar/girar a câmera), nunca mais ajuste fino do modelo.
- Botão Menu = mantém comportamento nativo (não tocar).
Mapeamento alvo
Mão Botão Ação
─────────────────────────────────────────────────────────
Esquerda/Direita Grip (1 mão) Pan da peça (translação 6DOF, sem rotação)
Ambas as mãos Grip + afastar Zoom uniforme (escala)
Ambas as mãos Grip + giro oposto Orbitar/rotacionar a peça
Direita Trigger Selecionar componente / adicionar ponto de medida
Esquerda Trigger Alternar snap de vértice (já existe)
Direita Botão A Desfazer última medida (já existe)
Direita Botão B Limpar medidas (já existe)
Thumbstick Frente + soltar Teletransporte para o ponto apontado
Thumbstick Lados Snap-rotate da câmera (±30°)
Thumbstick Trás Recuar o usuário (passo)
Mudanças no código
1. src/components/three/XRGrabbable.tsx
- One-hand grip: passar a aplicar apenas translação (pan). Hoje aplica matriz completa do grip → leva rotação junto. Vou capturar o offset de posição e atualizar só
group.position, mantendoquaternionescale. - Two-hand grip: manter rotação pelo eixo entre as mãos + forçar
allowScale = truesempre (zoom passa a vir do grip, não depende mais do toggle do HUD). - Remover a prop
allowScaleda assinatura (ou ignorar e tratar comotrue).
2. src/pages/XRSession.tsx
- Remover o estado
allowScalee os toggles correspondentes nas duas instâncias de<XRGrabbable>. - Substituir
<ControllerFineTuning />por um novo<ControllerLocomotion />(ver item 4) — o joystick não deve mais editarfineTuningdo modelo. - Garantir que
XRHitTestPlacementsó consomeonSelect(trigger) quandoplacementMode === true; fora disso o trigger é roteado integralmente paraXRControllerMeasure.
3. src/components/XRHud.tsx e src/components/three/XRHudInWorld.tsx
- Remover botão/toggle “Permitir escala” (
allowScale) — agora é sempre via grip duplo. - Remover/relabelar o toggle “Movimento livre” (
freeMove) já que o joystick deixa de ajustar o modelo; manter apenas se ainda fizer sentido para outra função (caso não, remover prop também deXRSession.tsx).
4. Novo src/components/three/ControllerLocomotion.tsx
Componente que substitui ControllerFineTuning. Lê useXR().session e implementa:
- Joystick esquerdo (ou ambos, configurável):
axes[1] < -0.7mantido por ~200 ms → dispara teleport: raycast a partir do controle direito contrascene.childrenno plano horizontal mais próximo; aplicaxrOrigin.positionpara reposicionar.axes[1] > 0.7→ recua oXROriginem passos de 0.3 m por trigger.axes[0]cruzando ±0.7 (com histerese) → snap-rotate de ±30° noXROrigin.rotation.y.
- Usar a API
XROriginjá montada emXRSession.tsx(referência viauseRefou store) para escrever pose. - Desligar tudo se
lockedActive(modelo travado) — locomoção do usuário ainda funciona, só não move o modelo.
5. src/components/three/XRControllerMeasure.tsx
- Sem mudanças funcionais — já usa apenas trigger e botões A/B. Apenas confirmar que o early-return
(!measureMode && !selectionMode)continua: quando nenhum dos modos está ativo, o trigger não dispara nada relacionado à medição (e não interfere emXRHitTestPlacement, que respeitaplacementMode).
6. src/components/three/XRHitTestPlacement.tsx
- Garantir que o handler
onSelect(trigger) verificaplacementModeantes de colocar o modelo. Hoje o tap-plane invisível pode estar capturando o select mesmo fora do placement — adicionar guarda explícita evisible={placementMode}.
Validação
- Desktop SimXR (devkit): pressionar Q/W (grip simulado) move a peça; pressionar A/S (trigger simulado) não muda pose nenhuma.
- Quest 3 real (passthrough):
- Grip único arrasta a peça sem rotacionar.
- Dois grips afastando = zoom; dois grips em rotação oposta = orbit.
- Trigger direito fora dos modos medir/selecionar/colocar = nada acontece.
- Trigger direito em modo Selecionar = seleciona componente IFC.
- Trigger direito em modo Medir = adiciona ponto com snap.
- Joystick esquerdo para frente = teletransporte; lados = snap-rotate; trás = recua.
- Logs
[XR][grab]continuam mostrando início/fim de one-hand e two-hand.
Fora do escopo
- Não mexer no botão Menu (Universal Menu do Quest é nativo).
- Não alterar handlers DOM/mouse do modo desktop (Viewer).
- Não tocar em RLS, store de dados ou backend.