diff --git a/frontend/src/components/viewer/Mannequin.tsx b/frontend/src/components/viewer/Mannequin.tsx index d86737d..1471099 100644 --- a/frontend/src/components/viewer/Mannequin.tsx +++ b/frontend/src/components/viewer/Mannequin.tsx @@ -1,26 +1,43 @@ import { useMemo } from "react"; import { useGLTF } from "@react-three/drei"; import * as THREE from "three"; +import { modelUrl } from "../../lib/api.js"; -const MODEL_URL = "/mannequin/body-male-realistic.glb"; +// "Regions of human body100.fbx" do próprio Z-Anatomy (já convertido pelo +// pipeline como regioes.glb, o mesmo arquivo usado pelo sistema "Regiões +// Anatômicas" no Atlas) — corpo inteiro, dado REAL, já em posição +// anatômica de verdade (não T-pose/A-pose), montado a partir de ~170 +// regiões de superfície nomeadas. +// +// Trocamos por esse depois de repetidas tentativas de reposicionar um +// basemesh CC0 de terceiros (Blender Studio Human Base Meshes) via script +// no Blender — sem rig, cada ajuste (braço, pulso) criava um novo defeito +// de malha em algum lugar (pernas deformadas, dedos rasgados...). Esse +// arquivo já vem correto, sem precisar editar nenhum vértice: zero risco +// de defeito de pose, ao custo de não ter a definição muscular esculpida +// do basemesh (é a malha de superfície do Z-Anatomy, não um sculpt). +const MODEL_FILE = "regioes.glb"; // Altura alvo em metros, decidida pra bater com as âncoras de seta/plano já // calibradas em PlanesPage.tsx (ex: ombro em y≈1.4, quadril em y≈0.9). const TARGET_HEIGHT = 1.78; +const SKIN_MATERIAL = new THREE.MeshStandardMaterial({ color: "#c99a7a", roughness: 0.75, metalness: 0.02 }); -useGLTF.preload(MODEL_URL); +useGLTF.preload(modelUrl(MODEL_FILE)); -// Corpo humano esculpido de verdade (não caixas/cilindros) em posição -// anatômica, usado só pela página de Planos Anatômicos — ver -// data-pipeline/scripts/mannequin-asset/README.md pra origem (Blender -// Studio "Human Base Meshes", CC0), licença e como essa malha foi -// reposicionada da pose original (braços afastados) pra anatômica (braços -// ao lado do corpo). Não tem nenhuma relação com o dataset Z-Anatomy usado -// no Atlas — é só uma silhueta externa, sem estruturas internas. export function Mannequin() { - const { scene } = useGLTF(MODEL_URL); + const { scene } = useGLTF(modelUrl(MODEL_FILE)); const normalized = useMemo(() => { const clone = scene.clone(true); + // O arquivo real vem com um material por região (a cor "arco-íris" que + // demos pro sistema de Regiões Anatômicas no Atlas) — aqui queremos só + // uma silhueta neutra, então trocamos TUDO por um material de pele + // único, compartilhado (a mesma instância em todo mesh, sem custo + // extra de draw call por isso). + clone.traverse((obj) => { + if (obj instanceof THREE.Mesh) obj.material = SKIN_MATERIAL; + }); + const box = new THREE.Box3().setFromObject(clone); const size = new THREE.Vector3(); box.getSize(size); @@ -32,7 +49,7 @@ export function Mannequin() { group.add(clone); // Centraliza em X/Z e põe o pé no chão (y=0) ANTES de escalar, depois // aplica a escala no grupo pai — assim o pivô da escala é a origem já - // corrigida, em vez do pivô torto que a malha trouxe do Blender. + // corrigida, em vez de um pivô torto vindo da malha original. clone.position.set(-center.x, -box.min.y, -center.z); group.scale.setScalar(scale); return group;