forked from mns/mini-skamja
75 lines
2.5 KiB
TypeScript
75 lines
2.5 KiB
TypeScript
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
|
||
} |