ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Three.js 模型视图教程

Three.js 模型视图教程

模型视图 ·Model Views· ▶ 在线运行案例

  • 案例合集:三维可视化功能案例(threehub.cn)
  • 开源仓库github地址:https://github.com/z2586300277/three-cesium-examples
  • 400个案例代码:网盘链接

你将学到什么

  • 用Box3 + FOV反算「刚好框住模型」的相机距离
  • 绕 Y/X 轴旋转观察方向得到六视图位置
  • gsap 切换camera.position与controls.target

效果说明

加载电脑模型,GUI 按钮前视图 / 右视图 / 上视图,相机平滑飞到对应标准视角,target 始终为模型中心。

核心概念

const box = new THREE.Box3().setFromObject(object);

const center = box.getCenter(new THREE.Vector3()); const radius = box.max.clone().sub(box.min).length() / 2;

// 距离 = 半径 / tan(fov/2) const distance = radius / Math.tan(Math.PI * fov / 360); const dir = object.getWorldDirection(new THREE.Vector3()); const frontView = dir.clone().multiplyScalar(distance).add(center);

// 右视图:方向绕 Y 转 90° const rightView = dir.clone() .applyAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2) .add(center);

这是 CAD/编辑器「正视图」「俯视图」按钮的常用算法。

代码要点

import * as THREE from 'three'

import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js' import { GUI } from 'dat.gui' import gsap from 'gsap'

const box = document.getElementById('box')

const scene = new THREE.Scene()

const camera = new THREE.PerspectiveCamera(75, box.clientWidth / box.clientHeight, 0.1, 100000)

camera.position.set(5, 5, 5)

const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true, logarithmicDepthBuffer: true })

renderer.setSize(box.clientWidth, box.clientHeight)

box.appendChild(renderer.domElement)

const controls = new OrbitControls(camera, renderer.domElement)

controls.enableDamping = true

window.onresize = () => {

renderer.setSize(box.clientWidth, box.clientHeight)

camera.aspect = box.clientWidth / box.clientHeight

camera.updateProjectionMatrix()

}

let model

const gui = new GUI()

new GLTFLoader().load(

FILE_HOST + 'models/glb/computer.glb',

gltf => {

model = scene.add(gltf.scene)

const { frontView, target, rightView, topView, bottomView, backView, maxView } = getObjectViews(model)

const setView = view => {

createGsapAnimation(controls.object.position, view)

createGsapAnimation(controls.target, target)

}

gui.add({ '前视图': () => setView(frontView) }, '前视图')

gui.add({ '右视图': () => setView(rightView) }, '右视图')

gui.add({ '上视图': () => setView(topView) }, '上视图')

}

)

animate()

function animate() {

requestAnimationFrame(animate)

controls.update()

renderer.render(scene, camera)

}

function getObjectViews(object, fov = 50) {

const box = new THREE.Box3().setFromObject(object)

const { max, min } = box

const center = new THREE.Vector3()

box.getCenter(center)

const radius = new THREE.Vector3().subVectors(max, min).length() / 2

const dir = object.getWorldDirection(new THREE.Vector3()) // 物体方向

const distance = radius / Math.tan(Math.PI * fov / 360) // 根据半径和相机视角 计算出距离

const vector = dir.multiplyScalar(distance) // 方向距离向量

const frontView = vector.clone().add(center)

const leftView = vector.clone().applyAxisAngle(new THREE.Vector3(0, 1, 0), -Math.PI / 2).add(center)

const rightView = vector.clone().applyAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI / 2).add(center)

const topView = vector.clone().applyAxisAngle(new THREE.Vector3(1, 0, 0), -Math.PI / 2).add(center)

const bottomView = vector.clone().applyAxisAngle(new THREE.Vector3(1, 0, 0), Math.PI / 2).add(center)

const backView = vector.clone().applyAxisAngle(new THREE.Vector3(0, 1, 0), Math.PI).add(center)

return { frontView, leftView, rightView, topView, bottomView, backView, target: center }

}

function createGsapAnimation(position, position_) {

return gsap.to(

position,

{

...position_,

duration: 1,

ease: 'none',

repeat: 0,

yoyo: false,

yoyoEase: true,

}

)

}

完整源码:GitHub

小结

  • 本文提供模型视图完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
  • 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库
返回列表