本文 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 / -2 與 aspect * 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.position 與 camera.lookAt。 |
| 多相機切換忘記更新投影矩陣 | 切換相機後未呼叫 updateProjectionMatrix(),會出現視野異常。 |
切換相機前,確保每個相機的投影矩陣已更新。 |
最佳實踐:
- 封裝相機建立:將相機設定寫成函式或類別,方便在不同場景重複使用。
- 使用
OrbitControls:開發階段加入軌道控制器,可即時觀察相機參數變化。 - 保持相機與光源同步:在需要陰影的情況下,將光源(如
DirectionalLight)的方向與相機視角保持一致,可避免陰影偏移。 - 利用
debugUI:結合dat.GUI或lil-gui,即時調整fov、near、far、zoom(正交相機)等參數,加速調校。
實際應用場景
| 場景 | 建議相機 | 為什麼選擇 |
|---|---|---|
| 角色扮演遊戲(RPG) | PerspectiveCamera |
需要逼真的深度感與視野寬度,營造沉浸感。 |
| 2.5D 平台遊戲 | OrthographicCamera |
角色與背景保持相同大小,避免遠近變形,易於製作像素風格。 |
| 建築模型檢視 | 可切換 Perspective ↔ Orthographic |
透視模式檢視真實感,正交模式作圖紙比例。 |
| 資料視覺化(條形圖、熱力圖) | OrthographicCamera |
保持圖形尺寸比例,避免視覺誤差。 |
| VR/AR 原型 | PerspectiveCamera + VRButton |
需要與使用者頭部追蹤同步的透視投影。 |
| 技術教學或 UI 渲染 | OrthographicCamera + zoom |
透過 zoom 可快速放大細節,適合 UI 元素定位。 |
總結
- 相機是 Three.js 中唯一決定畫面呈現方式的核心元件,選擇正確的相機類型與參數直接影響使用者體驗。
PerspectiveCamera提供自然的深度感,適合遊戲、虛擬實境等需要沉浸感的應用;OrthographicCamera則以平行投影保留比例,常用於 2.5D、工程圖與資料視覺化。- 永遠記得:
near不能為 0,far不宜過大。- 視窗變動時要即時更新
aspect(透視)或四邊界(正交)。 - 使用
lookAt或手動設定方向向量,確保相機指向正確目標。
- 透過 封裝、控制器、即時 UI 調校,可以讓相機的調整變得更直觀、開發效率更高。
掌握了相機的建立與調整之後,接下來就可以把重心放在 模型載入、光源配置、動畫控制 等更進階的 Three.js 主題上。祝你在 3D 網頁開發的旅程中,玩得開心、寫得順利! 🚀