在WebGL和Three.js的3D圖形渲染中,著色器(Shader) 是實現復雜視覺效果的核心工具。通過編寫自定義的著色器代碼,開發者可以直接操作GPU,實現從基礎顏色渲染到動態光照、粒子效果等高級圖形技術。本文將深入解析Three.js中著色器的核心概念、實現原理及實戰應用,并結合代碼示例幫助讀者全面掌握這一關鍵技術。
核心特點??:
一、著色器基礎與分類
1.1 頂點著色器(Vertex Shader)
頂點著色器負責處理幾何體的每個頂點,主要功能包括:
- 頂點位置變換:將模型空間坐標轉換為屏幕空間坐標(通過
gl_Position
輸出) - 頂點屬性計算:如法線變換、紋理坐標傳遞等
void main() {gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
說明:projectionMatrix
(投影矩陣)、modelViewMatrix
(模型視圖矩陣)由Three.js自動注入,position
是頂點的原始坐標。
1.2 片元著色器(Fragment Shader)
片元著色器決定每個像素的最終顏色,通過 gl_FragColor
輸出:
void main() {gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 紅色
}
特性:顏色支持動態計算,如基于光照模型、紋理采樣等。
1.3 著色器材質類型
Three.js提供兩種自定義著色器材質:
-
??
ShaderMaterial
??:簡化版材質,內置常用變量(如modelViewMatrix
、projectionMatrix
),適合快速開發。 -
??
RawShaderMaterial
??:需手動聲明所有變量(如attribute
、uniform
),靈活性更高,適合深度優化。
??示例代碼:創建基礎著色器材質??
const material = new THREE.ShaderMaterial({ vertexShader: vertexShaderCode, fragmentShader: fragmentShaderCode, uniforms: { time: { value: 0 }, color: { value: new THREE.Color(0xff0000) } }
});
二、著色器變量類型
2.1 Uniforms
- 全局常量:所有頂點/片元共享同一值(如時間、光源位置)
- 傳遞方式:通過
ShaderMaterial
的uniforms
屬性設置
const material = new THREE.ShaderMaterial({uniforms: {uTime: { value: 0 },uTexture: { value: new THREE.TextureLoader().load("texture.png") }}
});
在著色器中聲明:uniform float uTime;
2.2 Attributes
- 頂點屬性:每個頂點獨有的數據(如位置、顏色、法線)
- 典型應用:動態頂點動畫(如波浪效果)
geometry.setAttribute('displacement', new THREE.BufferAttribute(displacementArray, 1));
在頂點著色器中訪問:attribute float displacement;
2.3 Varyings
- 插值變量:從頂點著色器向片元著色器傳遞數據(如UV坐標、顏色插值)
// 頂點著色器
varying vec2 vUv;
void main() {vUv = uv;// ...
}// 片元著色器
varying vec2 vUv;
void main() {vec4 color = texture2D(uTexture, vUv);
}
注意:變量名需在兩者中保持一致。
三、矩陣變換與坐標系統
3.1 核心矩陣解析
- 模型矩陣(modelMatrix) :幾何體的旋轉、平移、縮放變換
- 視圖矩陣(viewMatrix) :相機的觀察變換(等同于相機世界矩陣的逆矩陣)
- 投影矩陣(projectionMatrix) :3D到2D的投影(如透視投影)
3.2 矩陣乘法順序
頂點變換遵循 “右乘”順序,確保坐標正確轉換:
gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position, 1.0);
原理:從模型空間→世界空間→相機空間→裁剪空間逐步變換。
四、實戰案例:動態波紋效果
4.1 著色器代碼實現
頂點著色器(傳遞UV坐標):
varying vec2 vUv;
void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
片元著色器(動態波紋計算):
uniform float uTime;
varying vec2 vUv;void main() {float ripple = sin(length(vUv - 0.5) * 10.0 - uTime * 2.0);float opacity = smoothstep(0.0, 0.2, abs(ripple));gl_FragColor = vec4(0.2, 0.5, 1.0, opacity);
}
4.2 JavaScript端配置
const material = new THREE.ShaderMaterial({uniforms: {uTime: { value: 0 }},vertexShader: vertexShaderCode,fragmentShader: fragmentShaderCode,transparent: true
});// 動畫循環中更新Uniform
function animate() {material.uniforms.uTime.value += 0.01;requestAnimationFrame(animate);
}
效果:實現以中心向外擴散的藍色波紋。
五、高級技巧與優化
5.1 性能優化策略
- 減少分支語句:GPU不擅長動態分支,可用
mix()
或step()
替代if-else
- 向量化運算:優先使用
vec3
/vec4
代替多個float
計算 - 紋理壓縮:使用Mipmap和紋理圖集減少采樣開銷
5.2 常見問題排查
- 變量未聲明:檢查Three.js版本是否支持特定語法(如
#version 300 es
) - 精度問題:在移動端明確指定精度(
precision mediump float;
) - 矩陣順序錯誤:確保模型→視圖→投影的乘法順序正確
六、擴展應用:后期處理通道
通過 EffectComposer
和 ShaderPass
實現屏幕后處理:
import { EffectComposer, ShaderPass } from 'three/examples/jsm/postprocessing';const composer = new EffectComposer(renderer);
composer.addPass(new RenderPass(scene, camera));const customPass = new ShaderPass(customShaderMaterial);
composer.addPass(customPass);
典型效果:模糊、Bloom光效、顏色校正等。
結語
Three.js著色器為開發者打開了高性能圖形編程的大門。通過深入理解GLSL語法、矩陣變換和變量傳遞機制,可以創造出從基礎顏色變化到復雜物理模擬的全方位視覺效果。建議通過Shadertoy平臺進行實時演練,結合Three.js文檔探索更多可能性。