fix clique

This commit is contained in:
Rodrigo Bertoldo de Sousa Martins committed 2026-09-11 11:30:46 -03:00
1 parent 3710c18825
commit 4542e8fda0
2 files changed
+64 -14

No files matched your search

+59 -4
View File
@@ -218,6 +218,58 @@ function CameraController({ modelFiles }: { modelFiles: string[] }) {
);
}
// Ossos finos (costela vista de perfil, falange, etc.) são fáceis de
// "errar" clicando — o raio único do clique padrão do three.js precisa
// acertar exatamente um triângulo da malha. Em vez de um único raio no
// pixel exato do clique, lançamos vários raios num pequeno raio ao redor
// dele (como um "dedo gordo") e ficamos com o resultado válido mais
// próximo da câmera — bem mais tolerante sem precisar mexer na geometria.
const CLICK_SAMPLE_OFFSETS: [number, number][] = [
[0, 0],
[5, 0], [-5, 0], [0, 5], [0, -5],
[4, 4], [-4, 4], [4, -4], [-4, -4],
];
function ClickSelector({
bySlug,
onSelect,
}: {
bySlug: Map<string, Structure>;
onSelect: (slug: string) => void;
}) {
const { camera, scene, gl, raycaster } = useThree();
useEffect(() => {
const canvas = gl.domElement;
const ndc = new THREE.Vector2();
function handleClick(event: PointerEvent) {
const rect = canvas.getBoundingClientRect();
let best: { distance: number; slug: string } | null = null;
for (const [dx, dy] of CLICK_SAMPLE_OFFSETS) {
const x = ((event.clientX + dx - rect.left) / rect.width) * 2 - 1;
const y = -((event.clientY + dy - rect.top) / rect.height) * 2 + 1;
if (x < -1 || x > 1 || y < -1 || y > 1) continue;
ndc.set(x, y);
raycaster.setFromCamera(ndc, camera);
const hits = raycaster.intersectObjects(scene.children, true);
const hit = hits.find((h) => h.object.visible && h.object.name && bySlug.has(h.object.name));
if (hit && (!best || hit.distance < best.distance)) {
best = { distance: hit.distance, slug: hit.object.name };
}
}
if (best) onSelect(best.slug);
}
canvas.addEventListener("click", handleClick);
return () => canvas.removeEventListener("click", handleClick);
}, [camera, scene, gl, raycaster, bySlug, onSelect]);
return null;
}
export function Scene({
bySlug,
children,
@@ -296,13 +348,16 @@ export function Scene({
visibleSystems={visibleSystems}
selectedSlug={selectedSlug}
clippingPlanes={clippingPlanes}
onSelect={(slug) => {
const structure = bySlug.get(slug);
if (structure) selectStructure(structure.id);
}}
/>
))}
</Suspense>
<ClickSelector
bySlug={bySlug}
onSelect={(slug) => {
const structure = bySlug.get(slug);
if (structure) selectStructure(structure.id);
}}
/>
<Grid
position={[0, 0, 0]}
args={[4, 4]}