fix clique
This commit is contained in:
1 parent
3710c18825
commit
4542e8fda0
2 files changed
+64
-14
No files matched your search
@@ -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]}
|
||||
|
||||
Reference in new issue
Block a user