Three.js 是什麼?從 WebGL 到瀏覽器裡的 3D 世界
第一次看到能旋轉的球鞋、跟著滑鼠移動的粒子,或捲動時慢慢展開的 3D 場景,很容易以為那是影片。很多時候,它其實是瀏覽器當場算出來的畫面。Three.js 就是目前最常見的入口之一。
如果瀏覽器只看得懂三角形,Three.js 在做什麼?
瀏覽器透過 WebGL 使用電腦的 GPU。WebGL 很強,但它的語言接近底層:你要自己準備頂點、三角形、著色器、矩陣與緩衝區。只是想把一個模型放到畫面上,也可能先寫一大段和內容無關的基礎程式。
Three.js 沒有取代 WebGL。它在 WebGL 上面整理出一套比較接近人類思考方式的工具:場景裡有物件,相機決定觀看位置,燈光和材質決定表面看起來如何,渲染器再把結果畫進 canvas。開發者仍在做即時 3D,只是不必每次都從三角形開始。
誰做的?從 mr.doob 的瀏覽器實驗開始
Three.js 的創作者是西班牙開發者 Ricardo Cabello,網路上更常看到他的名字是 mr.doob。第一個版本在 2010 年 4 月 24 日放上 GitHub。當時瀏覽器剛開始具備不用外掛也能畫即時 3D 的條件,他把自己做互動作品時累積的程式整理成開源函式庫。
後來加入的貢獻者不只補功能,也建立 loaders、controls、post-processing 和大量 examples。今天說 Three.js,已經不只是單一檔案,而是一個由核心引擎、附加模組、範例與社群組成的生態系。
先懂五個基本角色
Scene 是舞台,所有要被看到的物件都放在裡面。Camera 是觀眾站的位置;網站最常用 PerspectiveCamera,因為近大遠小比較像人的視覺。Renderer 把場景與相機交給 GPU,通常使用 WebGLRenderer。
Mesh 是看得見的物件,由 Geometry 和 Material 組合而成。Geometry 決定形狀,Material 決定表面如何反射光、顯示顏色或貼圖。Light 則負責照明;如果使用不受光影響的材質,也可以完全不放燈。理解這五個角色,就能讀懂大部分 Three.js 入門範例。

Three.js 能做什麼?
最直接的用途是把產品放進網站:家具、鞋子、機械零件或建築模型可以旋轉、換顏色、拆解,甚至放進 AR。第二類是資料視覺化,當資料具有地理、時間或空間關係時,3D 地球、網路拓樸和動態地圖能表達一般圖表不容易呈現的結構。
它也很適合互動敘事和輕量遊戲。GitHub Globe 用 Three.js 顯示全球開源活動;Google 的 Dreams in 3D 把使用者輸入的文字變成可探索的夢境;Bruno Simon 的作品集則把履歷變成一台能在 3D 場景裡駕駛的小車。這些作品都把 3D 直接變成操作方式或內容,不只是視覺裝飾。
Three.js 也能載入 glTF/GLB 模型、播放骨架動畫、做粒子、陰影、反射與後製特效。功能很多,但它仍是一套 JavaScript 函式庫,不會替你決定畫面、故事或互動節奏。
它不是 Blender,也不是完整遊戲引擎
Three.js 擅長在瀏覽器裡顯示和操作 3D;它不適合拿來精細建模、雕刻、綁骨架或製作複雜動畫。這些工作通常在 Blender 完成,再匯出成 GLB 給 Three.js 載入。兩者不是競爭關係,比較像攝影棚和播放器。
它也不像 Unity 或 Unreal 提供完整的編輯器、物理、關卡和資產管理。Three.js 給的是比較自由的網頁基礎元件。自由代表可以和 HTML、CSS、React 及網站路由緊密整合,也代表效能預算、載入狀態和互動規則要自己負責。
什麼時候不該用 Three.js?
如果內容用圖片、影片或 CSS 就能說清楚,3D 通常不是加分。模型會增加下載量,持續渲染會消耗電力,舊手機也可能掉幀。對搜尋引擎和螢幕閱讀器來說,canvas 裡的內容幾乎不存在,所以重要文字仍應保留在 HTML。
實作時我會先問三件事:3D 是否真的幫助理解?低效能裝置有沒有替代畫面?關閉動態效果的人能不能閱讀?答不出來時,先做平面版本往往更好。
本站案例:把捲動位置變成導演時間軸
KeepOnFirst 的 3D Studio 把 canvas 固定在背景,文章仍使用一般 HTML 往下排列。每個章節進入視窗時,程式切換焦點物件;章節內的捲動進度則控制相機位置、模型旋轉與燈光。即使 WebGL 載入失敗,文字仍然完整可讀。
先體驗本站的 3D 捲動文章Three.js 捲動文章 Starter
下面只留下最小核心:建立場景後,把頁面捲動進度正規化成 0 到 1,再用 lerp 平滑映射到相機與模型。正式網站還要補上 resize、載入狀態、requestAnimationFrame 節流、reduced motion 和 WebGL fallback。
import * as THREE from 'three';
const canvas = document.querySelector<HTMLCanvasElement>('#scene')!;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 0.1, 100);
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, alpha: true });
const model = new THREE.Mesh(
new THREE.BoxGeometry(1.8, 1.8, 1.8),
new THREE.MeshNormalMaterial(),
);
scene.add(model);
camera.position.z = 8;
renderer.setSize(innerWidth, innerHeight);
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
let frame = 0;
function render() {
const scrollMax = document.documentElement.scrollHeight - innerHeight;
const progress = THREE.MathUtils.clamp(scrollY / scrollMax, 0, 1);
camera.position.z = THREE.MathUtils.lerp(8, 3.5, progress);
model.rotation.y = progress * Math.PI * 2;
renderer.render(scene, camera);
}
function requestRender() {
if (frame) return;
frame = requestAnimationFrame(() => {
frame = 0;
render();
});
}
addEventListener('scroll', requestRender, { passive: true });
render();讓模型旋轉不難,難的是讓運動替文章服務。先寫出每一章讀者該看見什麼,再決定鏡頭怎麼移動,會比先堆特效更容易做出有意義的 3D 網站。
開啟完整 Demo,免費複製 Three.js 捲動文章 Starter上一篇:WebGL 是什麼?瀏覽器如何把資料交給 GPU下一篇:Blender 是什麼?以及如何 Headless 匯出 GLB