本文 AI 產出,尚未審核

Three.js – 開發環境與基本設置

主題:建立相機(PerspectiveCamera / OrthographicCamera)


簡介

在 3D 场景中,相機是唯一決定使用者最終看到畫面的「眼睛」。無論是製作交互式模型檢視、遊戲視角切換,或是資料視覺化的投影,都必須先正確建立相機,才能讓三維物件正確呈現在螢幕上。Three.js 提供了兩種最常用的相機類型:

  • PerspectiveCamera(透視相機)—— 模擬人眼或相機鏡頭的視角,遠近物件會因距離不同而產生大小變化。
  • OrthographicCamera(正交相機)—— 以平行投影方式呈現,遠近物件大小相同,常用於 2.5D、等比例圖或技術圖表。

本篇文章將從 概念、語法、實作範例 三個層面,帶領讀者一步步完成相機的建立與調校,並說明在實務開發中應如何選擇與最佳化。


核心概念

1. PerspectiveCamera(透視相機)

透視相機的建構子為:

new THREE.PerspectiveCamera( fov, aspect, near, far );
參數 說明
fov 視野角度(Field‑of‑View),單位是度(°),通常設定在 45~75° 之間。
aspect 畫布寬高比 canvas.width / canvas.height,在視窗調整時需同步更新。
near 近裁剪平面,距離相機最近能被渲染的距離,不能為 0,常設 0.1。
far 遠裁剪平面,最遠能被渲染的距離,過大會降低深度緩衝精度,常設 1000~5000。

1.1 範例:基本透視相機

// 建立渲染器與畫布
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

// 建立場景
const scene = new THREE.Scene();

// 建立透視相機
const fov = 60;                     // 60°視野
const aspect = window.innerWidth / window.innerHeight;
const near = 0.1;
const far = 2000;
const camera = new THREE.PerspectiveCamera( fov, aspect, near, far );

// 設定相機位置與目標
camera.position.set( 0, 2, 5 );    // x, y, z
camera.lookAt( 0, 0, 0 );          // 看向原點

// 簡單立方體示範
const geometry = new THREE.BoxGeometry( 1, 1, 1 );
const material = new THREE.MeshNormalMaterial();
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );

// 渲染迴圈
function animate() {
    requestAnimationFrame( animate );
    cube.rotation.y += 0.01;
    renderer.render( scene, camera );
}
animate();

重點lookAt 會自動調整相機的方向向量,讓相機指向指定座標。


2. OrthographicCamera(正交相機)

正交相機的建構子為:

new THREE.OrthographicCamera( left, right, top, bottom, near, far );
參數 說明
left / right 觀察體的左、右邊界,通常以 aspect * viewSize / -2aspect * viewSize / 2 計算。
top / bottom 觀察體的上、下邊界,常以 viewSize / 2-viewSize / 2 計算。
near / far 與透視相機相同,控制裁剪平面。

2.1 範例:基本正交相機

// 設定畫布與渲染器(同上)
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );

const scene = new THREE.Scene();

// 正交相機參數
const viewSize = 10;                         // 觀察體高度
const aspect = window.innerWidth / window.innerHeight;
const left   = -aspect * viewSize / 2;
const right  =  aspect * viewSize / 2;
const top    =  viewSize / 2;
const bottom = -viewSize / 2;
const near = 0.1;
const far = 100;

// 建立正交相機
const camera = new THREE.OrthographicCamera( left, right, top, bottom, near, far );
camera.position.set( 5, 5, 5 );
camera.lookAt( 0, 0, 0 );

// 加入格線輔助
const gridHelper = new THREE.GridHelper( 20, 20 );
scene.add( gridHelper );

// 加入一個平面作為示例
const planeGeo = new THREE.PlaneGeometry( 8, 8 );
const planeMat = new THREE.MeshBasicMaterial({ color: 0x66ccff, side: THREE.DoubleSide });
const plane = new THREE.Mesh( planeGeo, planeMat );
plane.rotation.x = -Math.PI / 2;
scene.add( plane );

function animate() {
    requestAnimationFrame( animate );
    renderer.render( scene, camera );
}
animate();

小提醒:正交相機的 left/right/top/bottom 必須隨視窗大小變化而重新計算,否則畫面會出現拉伸。


3. 動態調整相機參數(視窗縮放)

無論是透視或正交相機,都需要在 resize 事件中同步更新 aspect(透視)或 left/right/top/bottom(正交),否則畫面比例會失真。

window.addEventListener( 'resize', onWindowResize, false );

function onWindowResize() {
    const width = window.innerWidth;
    const height = window.innerHeight;

    // 透視相機
    camera.aspect = width / height;
    camera.updateProjectionMatrix();

    // 正交相機(若使用正交相機則改寫下列程式碼)
    // const viewSize = 10;
    // const aspect = width / height;
    // camera.left   = -aspect * viewSize / 2;
    // camera.right  =  aspect * viewSize / 2;
    // camera.top    =  viewSize / 2;
    // camera.bottom = -viewSize / 2;
    // camera.updateProjectionMatrix();

    renderer.setSize( width, height );
}

4. 多相機切換與渲染

在同一個場景中常會需要 切換相機(例如:第一人稱、鳥瞰圖、等角投影)。只要保持同一個 renderer,在渲染迴圈中改變傳入的相機即可。

let activeCamera = perspectiveCamera;   // 初始使用透視相機

function switchCamera() {
    activeCamera = ( activeCamera === perspectiveCamera )
        ? orthographicCamera
        : perspectiveCamera;
}

// 監聽鍵盤切換(按下 C 鍵)
window.addEventListener( 'keydown', ( e ) => {
    if ( e.key === 'c' || e.key === 'C' ) switchCamera();
});

function animate() {
    requestAnimationFrame( animate );
    renderer.render( scene, activeCamera );
}
animate();

常見陷阱與最佳實踐

陷阱 說明 解決方案
near = 0 設為 0 會導致深度緩衝區無法正確分割,產生 Z‑fighting。 永遠設定大於 0(如 0.1)。
far 設太大 過大的遠裁剪平面會降低深度精度,遠近物件會出現鋸齒或穿插。 設定 合理的 far,只要能涵蓋場景即可。
未更新 aspect 視窗大小改變後未更新相機的 aspect,畫面會被拉伸。 resize 事件中呼叫 camera.updateProjectionMatrix()
正交相機邊界寫死 直接硬寫 left/right/top/bottom,在不同螢幕比例下會變形。 使用 視窗比例 重新計算邊界。
相機位置與目標不一致 把相機放在遠離目標的位置卻未調整 lookAt,導致場景看不到。 明確設定 camera.positioncamera.lookAt
多相機切換忘記更新投影矩陣 切換相機後未呼叫 updateProjectionMatrix(),會出現視野異常。 切換相機前,確保每個相機的投影矩陣已更新。

最佳實踐

  1. 封裝相機建立:將相機設定寫成函式或類別,方便在不同場景重複使用。
  2. 使用 OrbitControls:開發階段加入軌道控制器,可即時觀察相機參數變化。
  3. 保持相機與光源同步:在需要陰影的情況下,將光源(如 DirectionalLight)的方向與相機視角保持一致,可避免陰影偏移。
  4. 利用 debug UI:結合 dat.GUIlil-gui,即時調整 fovnearfarzoom(正交相機)等參數,加速調校。

實際應用場景

場景 建議相機 為什麼選擇
角色扮演遊戲(RPG) PerspectiveCamera 需要逼真的深度感與視野寬度,營造沉浸感。
2.5D 平台遊戲 OrthographicCamera 角色與背景保持相同大小,避免遠近變形,易於製作像素風格。
建築模型檢視 可切換 Perspective ↔ Orthographic 透視模式檢視真實感,正交模式作圖紙比例。
資料視覺化(條形圖、熱力圖) OrthographicCamera 保持圖形尺寸比例,避免視覺誤差。
VR/AR 原型 PerspectiveCamera + VRButton 需要與使用者頭部追蹤同步的透視投影。
技術教學或 UI 渲染 OrthographicCamera + zoom 透過 zoom 可快速放大細節,適合 UI 元素定位。

總結

  • 相機是 Three.js 中唯一決定畫面呈現方式的核心元件,選擇正確的相機類型與參數直接影響使用者體驗。
  • PerspectiveCamera 提供自然的深度感,適合遊戲、虛擬實境等需要沉浸感的應用;
  • OrthographicCamera 則以平行投影保留比例,常用於 2.5D、工程圖與資料視覺化。
  • 永遠記得
    1. near 不能為 0,far 不宜過大。
    2. 視窗變動時要即時更新 aspect(透視)或四邊界(正交)。
    3. 使用 lookAt 或手動設定方向向量,確保相機指向正確目標。
  • 透過 封裝、控制器、即時 UI 調校,可以讓相機的調整變得更直觀、開發效率更高。

掌握了相機的建立與調整之後,接下來就可以把重心放在 模型載入、光源配置、動畫控制 等更進階的 Three.js 主題上。祝你在 3D 網頁開發的旅程中,玩得開心、寫得順利! 🚀