TrackballControls是 Three.js 中的一种视角控制器,提供了一种自由、灵活的 3D 交互方式,允许用户通过鼠标围绕目标进行旋转、缩放和平移,类似于轨迹球的操作。TrackballControls可以实现任意方向的视角控制,常用于 3D 模型查看、设计展示等场景。
这个在相机控制中具有最高灵活性。
TrackballControls 三个事件,十六个属性,二个方法
TrackballControls( camera : Camera, domElement : HTMLDOMElement ) camera: 渲染场景的摄像机。 domElement: 用于事件监听的HTML元素。(可选) 创建一个新的 TrackballControls 实例。
<template>
<div id="parkingLot" ref="parkingLot">
</div>
</template>
<script setup>
import { ref, onMounted, onUnmounted } from "vue";
import * as THREE from 'three';
import Stats from 'three/addons/libs/stats.module.js';
import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
import { TrackballControls } from 'three/addons/controls/TrackballControls.js';
const parkingLot = ref();
onMounted(async () => {
const DOMEl = parkingLot.value;
// 获取 DOMEl 的宽度和高度,以设置渲染器的大小。
const width = DOMEl.clientWidth;
const height = DOMEl.clientHeight;
// 声明全局变量
let perspectiveCamera, orthographicCamera, controls, scene, renderer, stats;
const params = {
orthographicCamera: false // 用于控制是否使用正交相机,默认为 false,即使用透视相机
};
const frustumSize = 400; // 用于设置正交相机的视椎体大小
// 初始化函数
init();
function init() {
// 获取屏幕的宽高比
const aspect = width / height;
// 创建透视相机
perspectiveCamera = new THREE.PerspectiveCamera(60, aspect, 1, 1000);
perspectiveCamera.position.z = 500; // 将相机放置在 Z 轴正方向
// 创建正交相机
orthographicCamera = new THREE.OrthographicCamera(
frustumSize * aspect / -2, // left
frustumSize * aspect / 2, // right
frustumSize / 2, // top
frustumSize / -2, // bottom
1, // near
1000 // far
);
orthographicCamera.position.z = 500; // 将正交相机放置在 Z 轴正方向
// 创建场景
scene = new THREE.Scene();
scene.background = new THREE.Color(0xcccccc); // 设置场景背景色
scene.fog = new THREE.FogExp2(0xcccccc, 0.002); // 设置雾化效果
// 创建几何体和材质
const geometry = new THREE.ConeGeometry(10, 30, 4, 1);
const material = new THREE.MeshPhongMaterial({ color: 0xffffff, flatShading: true });
// 添加多个立方体到场景中
for (let i = 0; i < 500; i++) {
const mesh = new THREE.Mesh(geometry, material);
mesh.position.x = (Math.random() - 0.5) * 1000;
mesh.position.y = (Math.random() - 0.5) * 1000;
mesh.position.z = (Math.random() - 0.5) * 1000;
mesh.updateMatrix();
mesh.matrixAutoUpdate = false;
scene.add(mesh);
}
// 设置光源
const dirLight1 = new THREE.DirectionalLight(0xffffff, 3);
dirLight1.position.set(1, 1, 1);
scene.add(dirLight1);
const dirLight2 = new THREE.DirectionalLight(0x002288, 3);
dirLight2.position.set(-1, -1, -1);
scene.add(dirLight2);
const ambientLight = new THREE.AmbientLight(0x555555); // 环境光
scene.add(ambientLight);
// 设置渲染器
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio); // 设置像素比
renderer.setSize(window.innerWidth, window.innerHeight); // 设置渲染器大小
renderer.setAnimationLoop(animate); // 设置动画循环
DOMEl.appendChild(renderer.domElement); // 将渲染器的 DOM 元素添加到页面中
// 添加统计面板
stats = new Stats();
DOMEl.appendChild(stats.dom);
// GUI 控制界面,用于切换相机类型
const gui = new GUI();
gui.add(params, 'orthographicCamera').name('use orthographic').onChange(function (value) {
controls.dispose(); // 销毁现有的控制器
createControls(value ? orthographicCamera : perspectiveCamera); // 切换相机并创建相应的控制器
});
// 监听窗口大小变化
window.addEventListener('resize', onWindowResize);
// 初始时使用透视相机
createControls(perspectiveCamera);
}
// 创建控制器
function createControls(camera) {
controls = new TrackballControls(camera, renderer.domElement);
controls.rotateSpeed = 1.0; // 旋转速度
controls.zoomSpeed = 1.2; // 缩放速度
controls.panSpeed = 0.8; // 平移速度
controls.keys = ['KeyA', 'KeyS', 'KeyD']; // 设置控制器的按键(A、S、D)
}
// 处理窗口大小变化
function onWindowResize() {
const aspect = window.innerWidth / window.innerHeight;
// 更新透视相机的纵横比并重新计算投影矩阵
perspectiveCamera.aspect = aspect;
perspectiveCamera.updateProjectionMatrix();
// 更新正交相机的投影矩阵
orthographicCamera.left = -frustumSize * aspect / 2;
orthographicCamera.right = frustumSize * aspect / 2;
orthographicCamera.top = frustumSize / 2;
orthographicCamera.bottom = -frustumSize / 2;
orthographicCamera.updateProjectionMatrix();
// 更新渲染器的大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 更新控制器
controls.handleResize();
}
// 动画循环
function animate() {
controls.update(); // 更新控制器
render(); // 渲染场景
stats.update(); // 更新统计面板
}
// 渲染场景
function render() {
// 根据 params.orthographicCamera 的值选择相应的相机
const camera = (params.orthographicCamera) ? orthographicCamera : perspectiveCamera;
renderer.render(scene, camera); // 渲染场景
}
});
</script>
<style lang="scss" scoped="scoped">
#parkingLot {
width: 940px;
height: 940px;
border: 1px solid #ccc;
margin: 30px auto;
}
</style>
事件
- change 当摄像机被控制器变换后触发。
- start 当交互(例如触摸)被初始化后触发。
- end 当交互完成后触发。
属性
- dynamicDampingFactor : Number 设置阻尼的强度。仅在staticMoving设为false时考虑。默认为0.2。
- keys : Array 该数组包含用于控制交互的按键代码。 当定义的第一个按键按下后,所有的鼠标交互(左/中/右键)表现为环绕。 当定义的第二个按键按下后,所有的鼠标交互(左/中/右键)表现为缩放。 当定义的第三个按键按下后,所有的鼠标交互(左/中/右键)表现为平移。 默认为KeyA, KeyS, KeyD,分别表示A, S, D。
- maxDistance : Number 你能够将相机向外移动多少(仅适用于PerspectiveCamera),其默认值为Infinity。
- minDistance : Number 你能够将相机向内移动多少(仅适用于PerspectiveCamera),其默认值为0。
- maxZoom : Float 你能够将相机缩小多少(仅适用于OrthographicCamera),其默认值为Infinity。
- minZoom : Float 你能够将相机放大多少(仅适用于OrthographicCamera),其默认值为0。
- mouseButtons : Object 该对象包含由控件所使用的鼠标操作的引用。 .LEFT 指定给 THREE.MOUSE.ROTATE .MIDDLE 指定给 THREE.MOUSE.ZOOM .RIGHT 指定给 THREE.MOUSE.PAN
- noPan : Boolean 是否禁用平移,默认为false。
- noRotate : Boolean 是否禁用旋转,默认为false。
- noZoom : Boolean 是否禁用缩放,默认为false。
- panSpeed : Number 平移的速度,其默认值为0.3。
- rotateSpeed : Number 旋转的速度,其默认值为1.0。
- screen : Object 表示屏幕的属性。在handleResize()被调用时会自动设置。 left: 表示到屏幕左侧边界的偏移量(单位为像素)。 top: 表示到屏幕顶部边界的偏移量(单位为像素)。 width: 表示屏幕的宽度(单位为像素)。 height: 表示屏幕的高度(单位为像素)
- staticMoving : Boolean 阻尼是否被禁用。默认为false。
- target : Vector3 控件的焦点。
- zoomSpeed : Number 缩放的速度,其默认值为1.2。
方法
- handleResize () : undefined 若应用程序窗口大小发生改变,则应当调用此函数。
- reset () : undefined 重置控制器到初始状态。