Three.js 简介

OrbitControls 轨道控制器

使用 OrbitControls 为 3D 场景添加鼠标交互:拖拽旋转、滚轮缩放、右键平移,并掌握阻尼等常用配置。

🎯 引言

好用的 3D 页面都允许用户“动手”:拖一拖转着看、滚轮拉远近。如果自己监听鼠标事件再换算成相机位置,要写不少数学代码。Three.js 官方提供了现成的 OrbitControls(轨道控制器),几行代码就能让场景支持鼠标交互。学完这篇文章,你能给场景接上 OrbitControls,并掌握阻尼、自动旋转等常用配置。


🧱 什么是 OrbitControls

OrbitControls 是 Three.js 自带的相机控制器,装上之后用户就能:

  • 左键拖拽:围绕场景中心旋转视角。
  • 滚轮滚动:拉近、拉远相机。
  • 右键拖拽:平移画面。

“轨道”这个名字很形象:相机始终围着目标点转,就像卫星在轨道上围着地球转。


🚀 引入方式

OrbitControls 不在 Three.js 核心代码里,而是放在附加组件目录中,通过 three/addons/ 这个别名引入:

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
这个路径依赖打包工具对 three/addons 别名的解析。Vite、Webpack5 等现代工具都内置支持,直接用即可,不需要单独安装其他包。

🛠 接入控制器

创建时传入相机和渲染器的画布,它就接管了鼠标事件:

views/ControlCube.vue
<template>
    <div ref="containerRef" class="container"></div>
</template>

<script setup>
import { onMounted, ref } from 'vue';
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const containerRef = ref(null);

onMounted(() => {
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(75, 320 / 240, 0.1, 1000);
    camera.position.set(2, 2, 4);
    camera.lookAt(0, 0, 0);

    const cube = new THREE.Mesh(
        new THREE.BoxGeometry(1.5, 1.5, 1.5),
        new THREE.MeshStandardMaterial({ color: 0x44aa88 })
    );
    scene.add(cube);

    scene.add(new THREE.AmbientLight(0xffffff, 0.5));
    const directionalLight = new THREE.DirectionalLight(0xffffff, 1.5);
    directionalLight.position.set(3, 5, 4);
    scene.add(directionalLight);

    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(320, 240);
    containerRef.value.appendChild(renderer.domElement);

    // 创建控制器:传入相机 + 渲染器的画布
    const controls = new OrbitControls(camera, renderer.domElement);

    const animate = () => {
        requestAnimationFrame(animate);
        controls.update(); // 每帧更新控制器状态
        renderer.render(scene, camera);
    };
    animate();
});
</script>

<style scoped>
.container {
    width: 320px;
    height: 240px;
}
</style>

相比上一篇的动画代码,改动只有三处:

  1. 引入 OrbitControls
  2. new OrbitControls(camera, renderer.domElement) 创建控制器。
  3. 渲染循环里调用 controls.update()

用户拖动画布时,OrbitControls 会自动修改相机的位置和朝向,我们什么都不用算。

交互功能按课程约定不提供在线演示,请在自己电脑上运行代码体验:按住左键拖一拖,滚轮滚一滚,感受亲手转动立方体的效果。

🧱 常用配置

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

controls.enableDamping = true; // 阻尼:松手后惯性滑动一小段,手感更顺滑
controls.dampingFactor = 0.05; // 阻尼系数,越小滑得越远

controls.autoRotate = true; // 自动旋转:无人操作时相机自己绕场转
controls.autoRotateSpeed = 1.0; // 自动旋转速度

controls.minDistance = 2; // 最多只能拉近到 2,防止穿进物体里
controls.maxDistance = 20; // 最多只能拉远到 20,防止场景缩成一个小点

几个使用经验:

  • enableDamping 建议常开,开了之后必须在渲染循环里调用 controls.update(),否则阻尼不生效。
  • autoRotate 适合产品展示页:用户不动时场景自己慢慢转,用户上手拖拽时会自动暂停。
  • minDistance / maxDistance 是体验保护,建议设置,避免用户把相机拉丢。

🧾 小节总结

  • OrbitControls 提供鼠标交互:左键旋转、滚轮缩放、右键平移。
  • three/addons/controls/OrbitControls.js 引入,无需额外安装。
  • 创建时传入相机和 renderer.domElement,循环里调用 controls.update()
  • enableDamping 提供顺滑惯性,必须配合 controls.update() 使用。
  • autoRotate 自动旋转展示;minDistance / maxDistance 限制缩放范围。

❓ 知识问答

Q1:OrbitControls 和我自己写的相机动画冲突吗?

会。两者都想控制相机,画面会来回打架。用了 OrbitControls,就把相机的控制权交给它;物体自己的动画(自转、浮动)不受影响,可以正常写。

Q2:右键平移想禁用怎么办?

controls.enablePan = false。同理还有 enableRotate(旋转)、enableZoom(缩放),都可以单独开关。

Q3:控制器监听的事件会自己销毁吗?

不会。组件卸载时要调用 controls.dispose() 移除事件监听,写法在下一篇“Vue3 实战”里统一演示。

Q4:手机端能用 OrbitControls 吗?

可以。它同时支持触屏:单指旋转、双指缩放、双指平移,不需要额外配置。


🧪 小练习

给上一篇的“跳动的球”装上交互:

  1. 引入 OrbitControls,开启阻尼。
  2. 设置 minDistance = 3maxDistance = 15
  3. 开启 autoRotate,然后拖拽一下画布,观察自动旋转暂停又恢复的过程。
views/InteractiveBall.vue
<template>
    <div ref="containerRef" class="container"></div>
</template>

<script setup>
import { onMounted, ref } from 'vue';
import * as THREE from 'three';
// 请在这里引入 OrbitControls

const containerRef = ref(null);

onMounted(() => {
    // 请在这里编写代码
});
</script>

<style scoped>
.container {
    width: 320px;
    height: 240px;
}
</style>

🎉 恭喜你已经掌握轨道控制器啦!下一篇我们把前面学到的知识整合起来,封装一个可以在 Vue3 项目里反复使用的 3D 组件。