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

Three.js 轨道控制器教程

轨道控制器 ·Orbit Controls· ▶ 在线运行案例

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

你将学到什么

  • OrbitControls全部常用配置项含义
  • 阻尼 enableDamping与每帧update()的关系
  • 距离 / 方位角 / 极角限制如何约束观察范围
  • controls.target轨道中心点的意义

效果说明

贴图平面 + 网格/坐标轴辅助。右侧 GUI 列出 OrbitControls几乎所有公开参数,拖动滑块即可感受:

  • 左键旋转、滚轮缩放、右键平移(可单独开关)
  • 自动旋转、阻尼惯性
  • 最近/最远距离、水平/垂直角度上下限
  • zoomToCursor以鼠标位置为缩放中心

核心概念

OrbitControls 在做什么?

OrbitControls 不改变物体,而是改变相机 position观察目标 target,使相机围绕target(默认原点)做轨道运动

target (观察中心)

● /│\ / │ \ 相机 ● │ 轨道球面 │ 左键拖拽 → 改变方位角/极角 滚轮 → 改变与 target 距离 右键 → 平移 target + 相机

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

controls.target.set(0, 0, 0); // 轨道中心,默认 (0,0,0)

阻尼 autoRotate

| 属性 | 作用 | |------|------| |enableDamping| 开启惯性,松手后缓慢停止 | |dampingFactor| 阻尼系数,通常 0.05~0.1 | |autoRotate| 自动绕 target 水平旋转 | |autoRotateSpeed| 自动旋转速度 |

controls.enableDamping = true;

controls.dampingFactor = 0.05;

function animate() { controls.update(); // 阻尼和 autoRotate 必须每帧调用 renderer.render(scene, camera); }

::: warning 开enableDampingautoRotate却不在 rAF 里controls.update()→ 阻尼无效、自动旋转卡住。 :::

距离与角度限制

| 属性 | 限制内容 | |------|---------| |minDistance/maxDistance| 相机到 target 的最小/最大距离(缩放范围) | |minAzimuthAngle/maxAzimuthAngle| 水平绕圈角度(弧度) | |minPolarAngle/maxPolarAngle| 垂直角度:0=正上方,π/2=水平,π=正下方 | |minTargetRadius/maxTargetRadius| target 移动半径限制(较少用) |

典型用法:建筑漫游常设maxPolarAngle = Math.PI / 2,防止相机钻到地底下。

交互开关与速度

controls.enableRotate = true; // 左键旋转

controls.enableZoom = true; // 滚轮缩放 controls.enablePan = true; // 右键平移 controls.rotateSpeed = 1.0; controls.zoomSpeed = 1.0; controls.panSpeed = 1.0; controls.zoomToCursor = true; // 滚轮以鼠标指向点为缩放中心

两种渲染策略

1. 持续 rAF(本案例,配合阻尼/autoRotate)
function animate() {

requestAnimationFrame(animate); controls.update(); renderer.render(scene, camera); }

2. 按需渲染(静态场景省电)
controls.addEventListener('change', () => renderer.render(scene, camera));

// 无阻尼时可不开 rAF

实现步骤

  • Scene + Camera + Renderer
  • new OrbitControls(camera, renderer.domElement)
  • rAF 中controls.update()+ render
  • GUI 绑定全部 controls 属性,target.x/y/z.listen()观察 Orbit 变化
  • GridHelper + AxesHelper 辅助理解轨道
  • 代码要点

    import * as THREE from 'three'

    import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' import { GUI } from "three/addons/libs/lil-gui.module.min.js"

    const box = document.getElementById('box')

    const scene = new THREE.Scene()

    const camera = new THREE.PerspectiveCamera(50, box.clientWidth / box.clientHeight, 0.1, 1000)

    camera.position.set(0, 1, 4)

    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)

    const geomerty = new THREE.PlaneGeometry(1, 1)

    const map = new THREE.TextureLoader().load(HOST + 'files/author/KallkaGo.jpg')

    const material = new THREE.MeshBasicMaterial({ map , color: 0xf2f2f2, side: THREE.DoubleSide })

    const mesh = new THREE.Mesh(geomerty, material)

    scene.add(mesh)

    animate()

    function animate() {

    requestAnimationFrame(animate)

    controls.update()

    renderer.render(scene, camera)

    }

    scene.add(new THREE.AxesHelper(10), new THREE.GridHelper(10, 10))

    const folder = new GUI()

    folder.add(controls, 'autoRotate').name('自动旋转')

    folder.add(controls, 'autoRotateSpeed').name('自动旋转速度')

    folder.add(controls, 'enableDamping').name('阻尼')

    folder.add(controls, 'dampingFactor').name('阻尼系数').min(0).max(1)

    folder.add(controls, 'minDistance').name('最小距离')

    folder.add(controls, 'maxDistance').name('最大距离')

    folder.add(controls, 'maxAzimuthAngle', -2Math.PI, Math.PI2).name('水平旋转上限')

    folder.add(controls, 'minAzimuthAngle', -2Math.PI, Math.PI2).name('水平旋转下限')

    folder.add(controls, 'maxPolarAngle', 0, Math.PI).name('垂直旋转上限')

    folder.add(controls, 'minPolarAngle', 0, Math.PI).name('垂直旋转下限')

    folder.add(controls, 'maxTargetRadius').name('目标移动上限')

    folder.add(controls, 'minTargetRadius').name('目标移动下限')

    folder.add(controls, 'enablePan').name('平移')

    folder.add(controls, 'panSpeed').name('平移速度')

    folder.add(controls, 'enableRotate').name('旋转')

    folder.add(controls, 'rotateSpeed').name('旋转速度')

    folder.add(controls, 'enableZoom').name('缩放')

    folder.add(controls, 'zoomSpeed').name('缩放速度')

    folder.add(controls, 'zoomToCursor').name('光标为缩放中心')

    folder.add(controls.target, 'x').name('目标位置x').listen()

    folder.add(controls.target, 'y').name('目标位置y').listen()

    folder.add(controls.target, 'z').name('目标位置z').listen()

    folder.add({ '重置': () => folder.reset()}, '重置')

    完整源码:GitHub

    小结

    • 本文提供轨道控制器完整 Three.js 源码与在线 Demo,建议先运行案例再改 uniform/参数做二次实验
    • 更多 Three.js 实战案例见 three-cesium-examples 合集 与 GitHub 开源仓库
http://www.jsqmd.com/news/1099607/

相关文章:

  • 量子态制备的哈密顿量框架与硬件优化实践
  • MH Markets将亮相2026香港Wiki Finance Expo,深化全球金融行业交流
  • 单链表反转:Python/Java/C++三解
  • 保姆级教程:用Halcon的Socket算子5分钟搞定机器视觉与PLC的TCP通讯
  • 简单选择排序算法
  • 2026年本地部署的AI数字人直播系统 Top5 实测
  • 独立开发推荐安装的skills
  • WS2812FX使用过程中的疑惑点记录
  • OpenClaw 核心组件全解:Gateway、Agent、Skills、Memory 的职责与协作关系
  • LeetCode 32 最长有效括号:python3 题解
  • Linux入门实践作业(一)
  • AI教材生成秘籍:低查重AI写教材,快速产出优质教材书稿!
  • ArkUI 底部操作栏及卡片整体美化布局开发
  • 参考文献格式乱如麻?高校导师推荐这几个AI论文写作工具
  • 从“工作记忆”到“资源博弈”:AI Agent 的 Context Window 为何是最核心的工程约束?
  • 示波器 CAN 总线波形解读与 CAN 通信观测实操
  • 【无标题】当工具返回 50KB 结果时发生了什么?—— OpenClaw 处理大工具输出的工程实践
  • 【题解-信息学奥赛一本通】1228:书架
  • 第一单元:在 Kotlin 中创建和使用函数
  • 20260630 - 看门狗
  • 垃圾自动分类技术:从AI识别到机械分拣的工程实践与选型指南
  • 谷歌研究院打造“论文助手工具“,AI审稿时代正在悄然开启
  • 王建:GEO的效果与信源密不可分 企业不要再一味追求“效率”
  • 【实证分析】地级市互联网综合发展指数(2003-2024年)
  • ArkTS 双向绑定输入框代码完整详解和 个人信息卡片代码完整详解(ArkTS)
  • Agent Skill 学习笔记
  • LeetCode 902 最大为 N 的数字组合:python3 题解
  • 基于.NET AgentFramework开发OpenClaw智能体框架
  • OpenClaw Ubuntu 部署经验总结
  • Go语言面试遇到,面试官问什么是协程、什么是协程泄漏和数组跟切片是用该如何回答