本文 AI 產出,尚未審核

Three.js 課程 – Camera 與 Controls

主題:OrbitControls 基礎


簡介

在 3D 網頁應用中,**相機(Camera)**是使用者觀察場景的「眼睛」,而 **控制器(Controls)**則是讓相機能夠以直覺的方式移動、旋轉、縮放。
OrbitControls 是 Three.js 官方提供的最常用控制器之一,它模擬「環繞」相機的操作:使用者可以拖曳滑鼠或手指,讓相機圍繞目標點(target)旋轉,亦能透過滾輪或捏合手勢實作縮放(dolly)功能。

掌握 OrbitControls 的基本用法,能讓你在短時間內為 3D 場景加入 交互式觀察,提升使用者體驗,尤其適合模型展示、資料視覺化、遊戲原型等各種應用。


核心概念

1. 為什麼使用 OrbitControls?

功能 手動實作難度 OrbitControls 提供的好處
繞目標旋轉 需要自行計算球面坐標、四元數 已封裝好,支援平滑阻尼
平移(Pan) 需要把相機與目標平行移動 可直接開關,支援螢幕座標轉換
縮放(Zoom/Dolly) 需要根據相機型別調整距離或視角 自動辨識 PerspectiveCameraOrthographicCamera
滑鼠/觸控手勢 需自行監聽多種事件 支援滑鼠、觸控、滾輪、鍵盤等多種輸入

結論:若只是想要快速得到「可拖曳、可縮放」的相機交互,OrbitControls 是最省時的選擇。


2. 基本安裝與引用

OrbitControls 並非 Three.js 核心模組,而是位於 examples/jsm/controls/OrbitControls.js。在使用 ES6 模組時,只要透過 import 載入即可:

// main.js
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

小技巧:若使用 bundler(如 Vite、Webpack)或 CDN(如 unpkg)皆可直接引用,請確認版本號與 Three.js 本體保持一致。


3. 建立基本場景與 OrbitControls

以下是一個最小化範例,展示如何在 PerspectiveCamera 上套用 OrbitControls

import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js';

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

  // 2. Scene
  const scene = new THREE.Scene();
  scene.background = new THREE.Color(0x202020);

  // 3. Camera
  const camera = new THREE.PerspectiveCamera(
    60,                                 // fov
    window.innerWidth / window.innerHeight,
    0.1, 1000                           // near, far
  );
  camera.position.set(5, 5, 5);        // 初始位置

  // 4. OrbitControls
  const controls = new OrbitControls(camera, renderer.domElement);
  controls.target.set(0, 0, 0);        // 環繞的目標點
  controls.update();                  // 必須在第一次渲染前呼叫

  // 5. 加入簡單幾何體作為參考
  const geometry = new THREE.BoxGeometry(1, 1, 1);
  const material = new THREE.MeshNormalMaterial();
  const cube = new THREE.Mesh(geometry, material);
  scene.add(cube);

  // 6. 監聽視窗變動
  window.addEventListener('resize', () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  });

  // 7. 動畫迴圈
  function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
  }
  animate();
}
init();

說明

  • controls.target 定義相機繞旋的中心點。預設為 (0,0,0),若想觀察其他模型,只要把它移到模型的中心即可。
  • controls.update() 在第一次渲染前必須呼叫,否則相機位置不會根據 target 立即同步。
  • renderer.domElement 為事件監聽的目標,確保滑鼠/觸控操作只在畫布上觸發。

4. 常用屬性與方法

屬性 / 方法 類型 功能說明
controls.enableDamping Boolean 開啟阻尼(慣性)效果,需在 animate 內呼叫 controls.update()
controls.dampingFactor Number 阻尼係數,建議 0.05~0.1
controls.enableZoom Boolean 允許縮放(滾輪或捏合)
controls.minDistance / maxDistance Number 限制相機與目標的最遠/最近距離(Perspective)
controls.minZoom / maxZoom Number 限制正交相機的縮放倍率
controls.enablePan Boolean 允許平移(按住滑鼠右鍵或中鍵)
controls.panSpeed Number 平移速度係數
controls.autoRotate Boolean 自動繞目標旋轉(常用於展示模型)
controls.autoRotateSpeed Number 自動旋轉速度(度/秒)
controls.maxPolarAngle / minPolarAngle Number 限制垂直旋轉角度(弧度),防止相機翻到地面以下
controls.saveState() / reset() 方法 儲存當前狀態、或回到最初狀態

5. 進階範例:自訂限制與自動旋轉

以下範例示範 限制垂直俯仰角度(只允許在 30°~150° 之間)以及 自動旋轉(適合商品模型展示):

// ... 先前的 init 基礎設定同上

// 1. 限制垂直俯仰角度(以弧度計算)
controls.minPolarAngle = THREE.MathUtils.degToRad(30);   // 30°
controls.maxPolarAngle = THREE.MathUtils.degToRad(150);  // 150°

 // 2. 開啟阻尼與自動旋轉
controls.enableDamping = true;
controls.dampingFactor = 0.08;
controls.autoRotate = true;
controls.autoRotateSpeed = 2.0; // 每秒 2 度

// 3. 在 animate 中持續更新
function animate() {
  requestAnimationFrame(animate);
  controls.update(); // 必須放在此,才能讓阻尼與自動旋轉生效
  renderer.render(scene, camera);
}
animate();

重點

  • THREE.MathUtils.degToRad() 讓角度轉成弧度,避免手動計算錯誤。
  • 開啟阻尼後,即使使用者停止拖曳,相機仍會「滑行」到停止點,感覺更自然。
  • autoRotate 只在使用者未互動時才會啟動,若使用者手動旋轉,會暫時停下。

6. 多相機切換與 OrbitControls

在同一個場景中,有時會需要 切換不同類型的相機(例如從 PerspectiveCamera 切到 OrthographicCamera),只要保留同一個 OrbitControls 實例,並在切換後重新指派相機即可:

let currentCamera = perspectiveCamera; // 預設相機
const controls = new OrbitControls(currentCamera, renderer.domElement);
controls.enableDamping = true;

// 切換相機的函式
function switchCamera() {
  // 先保存目前的控制狀態
  const target = controls.target.clone();
  const position = currentCamera.position.clone();

  // 刪除舊的控制器(或直接改變相機屬性)
  controls.dispose();

  // 切換相機
  currentCamera = (currentCamera.isPerspectiveCamera) ? orthographicCamera : perspectiveCamera;

  // 重新建立控制器
  const newControls = new OrbitControls(currentCamera, renderer.domElement);
  newControls.target.copy(target);
  currentCamera.position.copy(position);
  newControls.enableDamping = true;
  newControls.update();

  // 替換全局變數
  controls = newControls;
}

此方式確保 使用者的視角與目標點不會因切換相機而重置,提升使用者體驗。


常見陷阱與最佳實踐

陷阱 可能的症狀 解決方案
忘記呼叫 controls.update() 相機不會跟隨阻尼或自動旋轉 在每個動畫迴圈(requestAnimationFrame)內呼叫
相機與目標距離過遠或過近 滾輪縮放失效、或控制器卡住 設定 minDistance / maxDistance(透視)或 minZoom / maxZoom(正交)
視窗大小改變後未更新相機比例 畫面變形、比例失真 resize 事件中呼叫 camera.updateProjectionMatrix()
使用 OrbitControls 時與其他控制器衝突 滑鼠事件被覆寫、控制失效 確保同一時間只掛載一個控制器,或使用 controls.enabled = false 暫時關閉
無意間把 OrbitControls 加到錯誤的 DOM 元素 滑鼠事件無反應 應傳入渲染器的 domElementrenderer.domElement

最佳實踐

  1. 阻尼(Damping):對於大多數 UI,開啟 enableDamping 並設定 dampingFactor 0.05~0.1,能讓操作更順滑。
  2. 限制角度:使用 minPolarAngle / maxPolarAngle 防止相機翻到地面以下,尤其在地形或模型展示時。
  3. 自動旋轉作為預設姿態:在模型載入完成前,可設定 autoRotate,提供「自動播放」的預覽效果。
  4. 儲存與還原狀態:在需要「重設視角」的 UI(如「回到初始視角」按鈕),呼叫 controls.saveState()controls.reset()
  5. 適當的事件節流:若在 resizepointermove 中做大量計算,建議使用 requestAnimationFramethrottle 以降低效能衝擊。

實際應用場景

場景 為何選擇 OrbitControls 具體實作要點
產品 3D 展示(商品輪播) 需要使用者自由旋轉、縮放,同時提供自動旋轉預覽 開啟 autoRotate、設定 maxDistance 限制過遠視角、加入 UI 按鈕切換 enableZoom
資料視覺化(3D 圖表) 使用者要檢視不同角度的圖表,同時避免相機穿透圖形 設定 minPolarAngle / maxPolarAngle、使用 pan 只在 X‑Y 平面移動
建築模型導覽 大型模型需要平滑的相機移動與限制俯仰角,以免「掉下去」 minDistancemaxDistance 依模型大小調整、配合 OrbitControlstarget 設為建築中心
VR/AR 前端預覽 在 WebXR 中仍可使用 OrbitControls 作為非沉浸式的預覽模式 controls.enabled 設為 !renderer.xr.isPresenting,在 XR 進入時自動關閉
多相機切換(俯視、透視) 同一場景需要切換不同視角以提供不同資訊 參考上方「多相機切換」範例,保持 controls.target 不變,僅改變相機參數

總結

OrbitControls 是 Three.js 中最實用且易上手的相機控制器之一。透過 簡單的匯入、初始化與屬性調整,開發者即可為 3D 場景加入自然的旋轉、平移與縮放交互。

  • 核心概念target 為環繞中心、enableDamping 提升流暢度、min/maxPolarAngle 控制垂直限制。
  • 常見陷阱:忘記 update()、未設定距離限制、視窗變更未同步相機。
  • 最佳實踐:適度使用阻尼、限制角度、保存/還原狀態、在需要時關閉控制器。

掌握這些要點後,你就能在 商品展示、資料視覺化、建築導覽 等多種實務情境中,快速打造出 直觀、流暢且可客製化 的 3D 互動體驗。祝你玩得開心,創作出更多令人驚艷的 Three.js 作品!