You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Three.js的TrackballControls编程实现CAD式缩放、旋转、平移按钮触发操作?

实现Three.js TrackballControls的缩放、旋转、平移及按钮触发功能

Hey there, let's build this out step by step. I've worked on similar CAD-style view controls with TrackballControls before, so I'll walk you through setting up both native mouse interactions and button-triggered actions that fit perfectly for CAD workflows.

1. 基础环境搭建

First, let's set up the core Three.js components, add TrackballControls, and include a test CAD model (we'll use a cube for simplicity):

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>CAD View Controls</title>
  <style>
    body { margin: 0; }
    canvas { display: block; }
    .control-buttons { position: fixed; top: 15px; left: 15px; z-index: 100; }
    button { padding: 10px 16px; margin: 0 6px; border: none; border-radius: 4px; background: #2194ce; color: white; cursor: pointer; font-size: 14px; }
    button:hover { background: #1a7cb8; }
  </style>
</head>
<body>
  <div class="control-buttons">
    <button id="zoomBtn">缩放视图</button>
    <button id="rotateBtn">旋转视图</button>
    <button id="panBtn">平移视图</button>
  </div>
  <script type="module">
    import * as THREE from 'three';
    import { TrackballControls } from 'three/addons/controls/TrackballControls.js';

    // 初始化场景、相机、渲染器
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0xf5f5f5);

    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(6, 6, 6);
    camera.lookAt(scene.position);

    const renderer = new THREE.WebGLRenderer({ antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    // 添加测试CAD模型
    const geometry = new THREE.BoxGeometry(3, 3, 3);
    const material = new THREE.MeshStandardMaterial({ color: 0x1e88e5, roughness: 0.3, metalness: 0.2 });
    const cadModel = new THREE.Mesh(geometry, material);
    scene.add(cadModel);

    // 添加光源(让CAD模型细节更清晰)
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
    scene.add(ambientLight);
    const directionalLight = new THREE.DirectionalLight(0xffffff, 0.9);
    directionalLight.position.set(8, 12, 10);
    scene.add(directionalLight);

2. 配置TrackballControls

TrackballControls is perfect for CAD-style free-form navigation. Let's enable all required features and tweak settings for smooth interactions:

// 初始化并配置TrackballControls
    const controls = new TrackballControls(camera, renderer.domElement);
    controls.enableZoom = true;       // 开启缩放功能
    controls.enableRotate = true;     // 开启旋转功能
    controls.enablePan = true;        // 开启平移功能
    controls.dampingFactor = 0.06;    // 操作阻尼,让视图过渡更自然
    controls.minDistance = 2;         // 最小缩放距离(防止镜头贴太近)
    controls.maxDistance = 25;        // 最大缩放距离(防止镜头拉太远)
    controls.update();                // 首次更新控件状态

3. 实现按钮触发的操作逻辑

Now we'll add event listeners to the buttons to manually control the camera and keep the controls state in sync with button actions:

3.1 缩放按钮(点击切换放大/缩小)

// 缩放按钮逻辑
    const zoomBtn = document.getElementById('zoomBtn');
    let zoomDirection = 1; // 1 = 放大,-1 = 缩小
    const zoomStep = 0.6;  // 每次缩放的步长

    zoomBtn.addEventListener('click', () => {
      const currentDistance = camera.position.distanceTo(scene.position);
      // 确保新距离在允许范围内
      const newDistance = Math.max(controls.minDistance, Math.min(controls.maxDistance, currentDistance - zoomStep * zoomDirection));
      // 按比例调整相机位置,保持朝向模型中心
      camera.position.lerp(scene.position, (currentDistance - newDistance) / currentDistance);
      camera.lookAt(scene.position);
      controls.update(); // 更新控件状态
      zoomDirection *= -1; // 下次点击切换缩放方向
    });

3.2 旋转按钮(绕Y轴旋转固定角度)

// 旋转按钮逻辑
    const rotateBtn = document.getElementById('rotateBtn');
    const rotateAngle = Math.PI / 8; // 每次旋转22.5度(可按需调整)

    rotateBtn.addEventListener('click', () => {
      // 绕Y轴旋转相机位置
      camera.position.applyAxisAngle(new THREE.Vector3(0, 1, 0), rotateAngle);
      camera.lookAt(scene.position);
      controls.update();
    });

3.3 平移按钮(沿相机水平方向平移)

// 平移按钮逻辑
    const panBtn = document.getElementById('panBtn');
    let panDirection = 1; // 1 = 向右,-1 = 向左
    const panStep = 0.6;  // 每次平移的步长

    panBtn.addEventListener('click', () => {
      // 获取相机的右方向向量
      const right = new THREE.Vector3();
      camera.getWorldDirection(right).cross(camera.up).normalize();
      // 平移相机和控件目标点(保持跟踪一致性)
      camera.position.add(right.multiplyScalar(panStep * panDirection));
      controls.target.add(right.multiplyScalar(panStep * panDirection));
      controls.update();
      panDirection *= -1; // 下次点击切换平移方向
    });

4. 动画循环与窗口适配

Finally, add the animation loop to keep the controls and view updated, plus handle window resizing:

// 动画循环
    function animate() {
      requestAnimationFrame(animate);
      controls.update(); // 必须持续更新控件
      renderer.render(scene, camera);
    }
    animate();

    // 窗口大小适配
    window.addEventListener('resize', () => {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
      controls.handleResize();
    });
  </script>
</body>
</html>

额外优化建议

  • If you want continuous action on hold (e.g., hold the zoom button to keep scaling), use setInterval and clearInterval like this:
    let zoomInterval;
    zoomBtn.addEventListener('mousedown', () => {
      zoomInterval = setInterval(() => {
        const currentDistance = camera.position.distanceTo(scene.position);
        const newDistance = Math.max(controls.minDistance, Math.min(controls.maxDistance, currentDistance - 0.15 * zoomDirection));
        camera.position.lerp(scene.position, (currentDistance - newDistance) / currentDistance);
        camera.lookAt(scene.position);
        controls.update();
      }, 16); // ~60fps
    });
    zoomBtn.addEventListener('mouseup', () => clearInterval(zoomInterval));
    zoomBtn.addEventListener('mouseleave', () => clearInterval(zoomInterval));
    
  • Adjust rotation axes (e.g., rotate around X-axis) or pan directions (vertical) to match your CAD workflow needs.

内容的提问来源于stack exchange,提问作者sathish94us

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:10:28