当前位置: 首页 > news >正文

Three.js 模型视图教程

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

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

你将学到什么

  • Box3 + FOV反算「刚好框住模型」的相机距离
  • 绕 Y/X 轴旋转观察方向得到六视图位置
  • gsap 切换camera.positioncontrols.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 开源仓库
http://www.cnnetsun.cn/news/3107956.html

相关文章:

  • 人工智能浪潮来袭,OverDrive的Libby应用如何应对书籍内容冲击?
  • 生成式引擎优化GEO哪个解决方案好
  • PEO113-PVP44-PS45三嵌段共聚物PS45-PVP44-PEO113
  • 数字控制振荡器(DCO)原理与LTC6903应用设计
  • CodeAgent 技术架构简易介绍
  • 工作中用AI省时又省力?小心“影子AI”导致数据泄露!
  • 拒绝环路+负载分担!MSTP实战配置
  • 拯救你的数字书库:novel-downloader小说下载器完整使用指南
  • 67|技能治理:版本、禁用回滚与共享策略
  • AI浪潮下SaaS行业震荡:估值重估、企业内卷,未来路在何方?
  • MySQL(十八)分库分表详解(介绍、Mycat概述安装、Mycat入门、Mycat配置、Mycat分片、Mycat管理及监控)
  • 这是关于选择器
  • TikTokDownload Cookie自动获取:告别手动烦恼的10分钟终极指南
  • 如何通过HWInfo插件实现FanControl智能风扇控制:完整配置指南
  • 山西干冰医用冷藏
  • Three.js 精灵标签教程
  • 如何3分钟搞定QQ空间数据备份:GetQzonehistory智能导出工具完整指南
  • Three.js 变换 Box3教程
  • 基于Agentic AI的降维算法自动化调优与可视化评估实践
  • TELAPA框架:基于策略档案与共享潜空间的持续强化学习实践
  • 8位MCU安全连接云端:PIC18F2620与A5000加密芯片实践
  • Anthropic Claude‘归零层’技术解析:语义校验环的架构级移除
  • GPT-4的‘2%激活‘真相:MoE稀疏推理原理与工程实践
  • 期权量化交易系列教程(四):经典方向性策略——备兑、保护性看跌与价差组合
  • Angular端到端测试实战:用TestCafe替代Protractor
  • Ubuntu 14.04下MongoDB备份恢复与迁移实战指南
  • Flask生产部署:Gunicorn+Nginx在Ubuntu 20.04上的完整实践
  • 告别手动抢购烦恼:Campus-iMaoTai智能茅台预约系统完全指南
  • 语义一致性仲裁系统:ADK契约引擎+Agent SDK协同验证
  • Debian 8 上安全部署 Django 1.11 的完整实践指南