three TrackballControls 轨迹球控制器

641 阅读4分钟

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 重置控制器到初始状态。