Three.js 教學 – 基本材質 MeshBasicMaterial
簡介
在 3D 網頁開發中,材質 (Material) 扮演了「外觀」的角色,決定了模型在螢幕上如何呈現光影、顏色與紋理。MeshBasicMaterial 是 Three.js 最簡單、最常使用的材質之一,它不受任何光照影響,僅以固定的顏色或貼圖直接渲染網格。
對於需要 快速原型、UI 介面、或 不需要光照計算的物件(例如天空盒、2D 精靈、debug 圖形),MeshBasicMaterial 是最佳選擇。掌握它的使用方式,能讓你在開發初期就快速看到成果,並為後續進階材質(如 MeshStandardMaterial)奠定基礎。
核心概念
1. MeshBasicMaterial 是什麼?
MeshBasicMaterial 繼承自 Material,其特點如下:
- 不受光照影響:渲染時只依賴顏色 (
color) 或貼圖 (map)。 - 渲染速度快:省略光照計算,適合大量低多邊形物件或 UI 元素。
- 適用於 2D 風格或背景圖:如 HUD、精靈、天空盒等。
const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
2. 常用屬性概覽
| 屬性 | 型別 | 說明 |
|---|---|---|
color |
THREE.Color |
基本顏色,可使用十六進位、CSS 字串或 THREE.Color 物件 |
map |
THREE.Texture |
貼圖,支援 PNG、JPG、WebP 等格式 |
opacity |
Number (0~1) |
透明度,需同時設定 transparent:true 才會生效 |
transparent |
Boolean |
是否啟用透明度混合 |
side |
THREE.Side |
渲染哪一面:FrontSide、BackSide、DoubleSide |
wireframe |
Boolean |
是否以線框模式渲染 |
alphaTest |
Number |
Alpha 測試門檻,常用於裁切半透明貼圖的邊緣 |
depthWrite |
Boolean |
是否寫入深度緩衝區,調整渲染順序時會用到 |
小技巧:如果只需要 純色,可以省略
map,直接使用color;若同時使用貼圖與顏色,貼圖會 乘上color。
3. 建立 MeshBasicMaterial 的基本流程
- 載入貼圖(若需要)
使用THREE.TextureLoader,確保貼圖已完成載入再套用。 - 建立材質實例,設定所需屬性。
- 建立幾何體 (Geometry),如
BoxGeometry、SphereGeometry。 - 組合成 Mesh,加入場景。
// 1. 載入貼圖
const loader = new THREE.TextureLoader();
const texture = loader.load('textures/brick_diffuse.jpg');
// 2. 建立材質
const material = new THREE.MeshBasicMaterial({
map: texture,
color: 0xffffff, // 乘上白色不會改變貼圖顏色
side: THREE.DoubleSide
});
// 3. 建立幾何體
const geometry = new THREE.BoxGeometry(2, 2, 2);
// 4. 合成 Mesh 並加入場景
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
程式碼範例
以下提供 5 個實用範例,示範 MeshBasicMaterial 在不同情境下的用法。每段程式碼均附上說明註解,方便直接複製測試。
範例 1️⃣ 基本純色立方體
// 建立一個純紅色的立方體
const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshBasicMaterial({
color: 0xff0000 // 十六進位紅色
});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
說明:此材質完全不受光照影響,無論場景中有多少光源,立方體都會保持純紅色。
範例 2️⃣ 使用貼圖作為材質
const loader = new THREE.TextureLoader();
loader.load('textures/earth.jpg', (texture) => {
const geometry = new THREE.SphereGeometry(1, 32, 32);
const material = new THREE.MeshBasicMaterial({
map: texture,
// 若想讓貼圖顏色稍微暗一些,可加上 color
// color: new THREE.Color(0.9, 0.9, 0.9)
});
const earth = new THREE.Mesh(geometry, material);
scene.add(earth);
});
說明:
MeshBasicMaterial直接把貼圖貼在球體上,不會因光源而產生陰影或高光,適合作為 地球示意圖 或 背景圖。
範例 3️⃣ 半透明與混合模式
const geometry = new THREE.PlaneGeometry(3, 3);
const material = new THREE.MeshBasicMaterial({
color: 0x00ff00,
opacity: 0.5, // 50% 透明度
transparent: true, // 必須啟用才能生效
side: THREE.DoubleSide // 雙面可見
});
const plane = new THREE.Mesh(geometry, material);
plane.position.set(0, 1, -2);
scene.add(plane);
重點:若忘記把
transparent設為true,opacity會被忽略,物件仍會完整不透明。
範例 4️⃣ 雙面渲染與線框模式
// 雙面渲染 + 線框
const geometry = new THREE.TorusKnotGeometry(1, 0.3, 100, 16);
const material = new THREE.MeshBasicMaterial({
color: 0x0000ff,
side: THREE.DoubleSide, // 兩面都渲染,避免背面消失
wireframe: true // 只顯示線框
});
const knot = new THREE.Mesh(geometry, material);
scene.add(knot);
應用:在開發階段想快速檢視模型拓撲或作為 技術指示器(如軌道、路徑)時非常有用。
範例 5️⃣ 結合 alphaTest 裁切半透明貼圖
loader.load('textures/leaf.png', (texture) => {
const geometry = new THREE.PlaneGeometry(2, 2);
const material = new THREE.MeshBasicMaterial({
map: texture,
transparent: true,
alphaTest: 0.5 // 只保留 alpha > 0.5 的像素,避免半透明邊緣的混合
});
const leaf = new THREE.Mesh(geometry, material);
leaf.position.set(-2, 0, 0);
scene.add(leaf);
});
說明:
alphaTest可以在渲染前直接剔除低透明度的像素,提升效能,同時避免在多層半透明物件上出現 Z‑fight。
常見陷阱與最佳實踐
| 陷阱 | 可能的結果 | 解決方式 |
|---|---|---|
忘記設定 transparent:true |
opacity 無效,物件仍全不透明 |
設定 transparent:true,或直接使用 alphaTest |
| 貼圖未完成載入就使用 | 會得到 黑色或錯誤的紋理 | 使用 TextureLoader.load 的回呼或 Promise,確保貼圖載入完成 |
| 使用非 2 的次方尺寸貼圖 | 部分舊版瀏覽器會自動縮放,導致模糊或失真 | 盡量使用 256、512、1024、2048… 的尺寸;若無法避免,設定 texture.minFilter = THREE.LinearFilter |
| 大量重複建立相同材質 | 記憶體浪費、渲染效能下降 | 重用 Material 實例,或使用 material.clone() 只在需要微調時才複製 |
未呼叫 material.dispose() |
釋放不到 GPU 記憶體,長時間運行會記憶體泄漏 | 在物件不再需要時,手動呼叫 material.dispose()、texture.dispose() |
忘記設定 side: THREE.DoubleSide |
背面不渲染,導致模型在特定角度變透明 | 若模型會被從背面觀看,記得設定 DoubleSide,但注意渲染成本會稍增 |
最佳實踐小結
- 先載入貼圖再建立材質:使用
Promise或async/await確保貼圖已完成。 - 統一管理材質:建立一個
materials物件或Map,集中儲存與重用。 - 設定正確的色彩空間:在渲染器開啟
outputEncoding = THREE.sRGBEncoding,貼圖若為 sRGB,記得texture.encoding = THREE.sRGBEncoding。 - 適度使用
alphaTest:在大量半透明葉子、旗幟等貼圖時,使用alphaTest可大幅提升效能。 - 釋放資源:在場景切換或物件刪除時,務必呼叫
dispose(),保持記憶體乾淨。
實際應用場景
| 場景 | 為什麼選擇 MeshBasicMaterial |
|---|---|
| 2D UI/HUD(如血條、按鈕) | 不需要光照,渲染成本低,顏色與貼圖直接呈現 |
| 天空盒或背景平面 | 只需貼圖,不受光照影響,避免背景被光源改變顏色 |
| Debug 形狀(座標軸、邊框) | 直接使用純色或線框,快速辨識模型位置 |
| 簡易貼圖示意(例如地圖、概念圖) | 只要貼圖本身的色彩,無需光照計算 |
| 粒子系統的基礎點 | 使用 SpriteMaterial(基於 MeshBasicMaterial)渲染 2D 圖案,保持透明度與混合模式 |
總結
MeshBasicMaterial 是 Three.js 中最直接、最輕量的材質類別。它的 不受光照特性 讓開發者能在最短時間內得到可視化結果,特別適合:
- 快速原型與 UI 元件
- 背景圖、天空盒 以及 純色示意
- Debug 與 教學範例
掌握其屬性(color、map、opacity、transparent、side、wireframe 等)以及常見陷阱(透明度設定、貼圖載入、資源釋放),即可在日常開發中靈活運用,並為之後的 PBR、Shader 材質奠定堅實基礎。
實務建議:在專案中先建立一套 材質管理器(Material Registry),把所有
MeshBasicMaterial放入共用池子。這樣不僅能減少記憶體開銷,還能在需要調整全局顏色或亮度時,只需要改動一次即可。
祝你在 Three.js 的旅程中玩得開心,創造出豐富多彩的 3D 網頁體驗! 🚀