mns
/
urna
forked from mns/mini-skamja
4
0
Fork 0
urna/utils/calculateScaleToFit.ts

75 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Box3, PerspectiveCamera, Vector3, Mesh, Camera } from 'three'
import { degToRad } from 'three/src/math/MathUtils.js'
export default function calculateScaleToFit(
object: any,
camera: ComputedRef<Camera | undefined>,
controls: any,
distance: number,
cameraOffset: { x: number; y: number; z: number }
) {
// Создаем новый BoundingBox
const bbox = new Box3()
// Обновляем мировую матрицу объекта
object.updateWorldMatrix(true, true)
// Перебираем все дочерние элементы объекта
object.traverse((child: any) => {
if (child.isMesh) {
// Добавляем геометрию каждого меша в bounding box
const geometry = child.geometry
if (geometry) {
geometry.computeBoundingBox() // Убедимся, что bounding box геометрии вычислен
const meshBBox = geometry.boundingBox.clone()
if (meshBBox) {
// Применяем мировую матрицу к bounding box
meshBBox.applyMatrix4(child.matrixWorld)
bbox.union(meshBBox) // Объединяем с общим bounding box
}
}
}
})
// Вычисляем центр и размер bounding box
const center = new Vector3()
bbox.getCenter(center)
const size = new Vector3()
bbox.getSize(size)
// Центрируем объект
object.position.sub(center)
object.updateWorldMatrix(true, true)
// Рассчитываем масштаб
const fov = (camera.value as PerspectiveCamera).fov
const aspect = (camera.value as PerspectiveCamera).aspect
const vFOV = degToRad(fov)
const visibleHeight = 2 * Math.tan(vFOV / 2) * distance
const visibleWidth = visibleHeight * aspect
const scaleX = visibleWidth / size.x
const scaleY = visibleHeight / size.y
const scaleZ = visibleWidth / size.z
const scale = Math.min(scaleX, scaleY, scaleZ)
// Масштабируем объект
object.scale.setScalar(scale)
object.updateWorldMatrix(true, true)
if (camera.value) {
const [x, y, z] = Object.values(cameraOffset).map(el => el * distance);
camera.value.position.set(x, y, z);
}
// Настройка OrbitControls
if (controls.value) {
controls.value.target.set(...Object.values(center.multiplyScalar(1)))
controls.value.update()
}
return object
}