fix exame fisico
This commit is contained in:
1 parent
43df670a55
commit
7e8834fbfd
1 file changed
+38
-7
@@ -119,30 +119,61 @@ function CameraController({ modelFiles }: { modelFiles: string[] }) {
|
|||||||
// outro ponto) — em vez de assumir uma posição de câmera fixa, sempre
|
// outro ponto) — em vez de assumir uma posição de câmera fixa, sempre
|
||||||
// que o conjunto de arquivos carregados muda, enquadra a câmera no
|
// que o conjunto de arquivos carregados muda, enquadra a câmera no
|
||||||
// bounding box real de tudo que está na cena.
|
// bounding box real de tudo que está na cena.
|
||||||
|
//
|
||||||
|
// O carregamento do .glb é assíncrono (Suspense) e pode levar bem mais
|
||||||
|
// que 1 frame — um único requestAnimationFrame às vezes media a cena
|
||||||
|
// ainda vazia/parcial (só 1-2 ossos montados) e nunca corrige depois,
|
||||||
|
// porque "modelFiles" não muda de novo uma vez carregado. Por isso agora
|
||||||
|
// fica tentando de novo a cada 200ms até o tamanho do conteúdo ficar
|
||||||
|
// ESTÁVEL (duas leituras seguidas iguais = terminou de montar), só então
|
||||||
|
// enquadra a câmera.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!controlsRef.current || modelFiles.length === 0) return;
|
if (modelFiles.length === 0) return;
|
||||||
const id = requestAnimationFrame(() => {
|
let cancelled = false;
|
||||||
|
let attempts = 0;
|
||||||
|
let lastSize = -1;
|
||||||
|
let timer: ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
|
function tryFit() {
|
||||||
|
if (cancelled || !controlsRef.current) return;
|
||||||
const box = computeVisibleBoundingBox(scene);
|
const box = computeVisibleBoundingBox(scene);
|
||||||
if (box.isEmpty()) return;
|
attempts += 1;
|
||||||
|
if (box.isEmpty()) {
|
||||||
|
if (attempts < 50) timer = setTimeout(tryFit, 200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const size = box.getSize(new THREE.Vector3()).length();
|
||||||
|
const stable = Math.abs(size - lastSize) < lastSize * 0.01;
|
||||||
|
lastSize = size;
|
||||||
|
if (!stable && attempts < 50) {
|
||||||
|
timer = setTimeout(tryFit, 200);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
setContentBox({
|
setContentBox({
|
||||||
min: [box.min.x, box.min.y, box.min.z],
|
min: [box.min.x, box.min.y, box.min.z],
|
||||||
max: [box.max.x, box.max.y, box.max.z],
|
max: [box.max.x, box.max.y, box.max.z],
|
||||||
});
|
});
|
||||||
const size = box.getSize(new THREE.Vector3()).length();
|
|
||||||
// Ajusta os planos de corte da câmera ao tamanho real do conteúdo —
|
// Ajusta os planos de corte da câmera ao tamanho real do conteúdo —
|
||||||
// um "far" fixo pequeno cortaria (tornaria invisível) um modelo bem
|
// um "far" fixo pequeno cortaria (tornaria invisível) um modelo bem
|
||||||
// maior do que o esperado.
|
// maior do que o esperado.
|
||||||
camera.near = Math.max(size / 1000, 0.001);
|
camera.near = Math.max(size / 1000, 0.001);
|
||||||
camera.far = size * 100;
|
camera.far = size * 100;
|
||||||
if (camera instanceof THREE.PerspectiveCamera) camera.updateProjectionMatrix();
|
if (camera instanceof THREE.PerspectiveCamera) camera.updateProjectionMatrix();
|
||||||
controlsRef.current?.fitToBox(box, true, {
|
controlsRef.current.fitToBox(box, true, {
|
||||||
paddingLeft: 0.2,
|
paddingLeft: 0.2,
|
||||||
paddingRight: 0.2,
|
paddingRight: 0.2,
|
||||||
paddingTop: 0.2,
|
paddingTop: 0.2,
|
||||||
paddingBottom: 0.2,
|
paddingBottom: 0.2,
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
return () => cancelAnimationFrame(id);
|
|
||||||
|
const id = requestAnimationFrame(tryFit);
|
||||||
|
return () => {
|
||||||
|
cancelled = true;
|
||||||
|
cancelAnimationFrame(id);
|
||||||
|
clearTimeout(timer);
|
||||||
|
};
|
||||||
}, [modelFiles, scene, camera, setContentBox]);
|
}, [modelFiles, scene, camera, setContentBox]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Reference in new issue
Block a user