1. UV 映射基礎概念
1.1 什么是 UV 坐標?
在三維計算機圖形學中,UV 坐標是將二維紋理映射到三維模型表面的坐標系統。UV 中的 U 和 V 分別代表2D紋理空間的水平(X)和垂直(Y)坐標軸,與三維空間中的 XYZ 坐標形成區分。
- UV 坐標系范圍:[0,0] 到 [1,1]
- 每個頂點對應一個UV坐標
- 紋理采樣器通過UV值獲取紋理顏色
1.2 坐標系差異
// Three.js 中的坐標系對比
三維模型坐標:(x, y, z) ∈ [-∞, +∞]
紋理UV坐標:(u, v) ∈ [0, 1]
屏幕像素坐標:(x, y) ∈ [0, viewportSize]
2. Three.js 中的 UV 實現
2.1 Geometry 與 BufferGeometry
// 經典 Geometry 的UV設置
const geometry = new THREE.Geometry();
geometry.faceVertexUvs[0].push([new THREE.Vector2(0, 0),new THREE.Vector2(1, 0),new THREE.Vector2(0.5, 1)
]);// BufferGeometry 的UV設置
// 自定義平面幾何體
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([...]); // 頂點坐標
const uv = new Float32Array([0, 0, // 頂點0的UV1, 0, // 頂點1的UV1, 1, // 頂點2的UV0, 1 // 頂點3的UV
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
geometry.setAttribute('uv', new THREE.BufferAttribute(uv, 2)); // 關鍵UV設置[1,5](@ref)
2.2 內置幾何體的UV映射
映射類型 | 特點 | 適用場景 | Three.js實現 |
---|---|---|---|
??平面映射?? | 正交投影,無透視變形 | 墻面、地面 | PlaneGeometry 默認UV2 |
??立方體映射?? | 6面獨立展開 | 盒子、建筑 | BoxGeometry 自動生成4 |
??球形映射?? | 極坐標展開 | 行星、球體 | SphereGeometry 經線展開6 |
??圓柱映射?? | 環形展開 | 管道、柱體 | 需手動設置UV3 |
2.2.1 BoxGeometry
- 6個立方體面共享同一張紋理
- 每個面UV范圍:[ (0,0), (1,1) ]
- 默認沿表面均勻展開,,但可能存在接縫
2.2.2 SphereGeometry
- 經線方向:U坐標(0到1)
- 緯線方向:V坐標(0到1)
- 極點處UV密度較高
- 采用球形投影,UV 在兩極可能出現拉伸。
2.2.3 CylinderGeometry
- 側面:U環繞圓柱,V沿高度
- 頂部/底面:圓形UV展開
3. UV 操作實戰技巧
3.1 動態修改UV坐標
// 獲取UV屬性數組
const uvAttribute = geometry.getAttribute('uv');
const uvs = uvAttribute.array;// 修改第三個頂點的U坐標
uvs[2 * 2] = 0.75; // 索引計算:頂點索引 * 分量數 + 偏移// 必須標記更新
uvAttribute.needsUpdate = true;
3.2 紋理重復與偏移
const texture = new THREE.TextureLoader().load('tile.jpg');
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.MirroredRepeatWrapping;
texture.repeat.set(2, 3);
texture.offset.set(0.5, 0.25);
4. 高級 UV 應用
4.1 多重紋理混合
// 著色器代碼示例
varying vec2 vUv;
uniform sampler2D texture1;
uniform sampler2D texture2;void main() {vec4 texColor1 = texture2D(texture1, vUv);vec4 texColor2 = texture2D(texture2, vUv * 2.0);gl_FragColor = mix(texColor1, texColor2, 0.5);
}
4.2 UV 動畫
function animate() {requestAnimationFrame(animate);// 水平滾動紋理texture.offset.x += 0.01;// 動態修改UV坐標const uvs = geometry.attributes.uv.array;for(let i=0; i<uvs.length; i+=2){uvs[i] += Math.sin(Date.now() * 0.001) * 0.01;}geometry.attributes.uv.needsUpdate = true;
}
4.3 頂點著色器中的 UV 控制
通過自定義著色器實現復雜效果:
// 頂點著色器
varying vec2 vUv;
uniform float time;void main() {vUv = uv + vec2(time * 0.1, 0.0);gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
4.4 法線映射與 UV 的關系
法線貼圖依賴 UV 坐標確定法線方向:
const material = new THREE.MeshStandardMaterial({normalMap: normalTexture,normalScale: new THREE.Vector2(0.5, 0.5) // 控制法線強度
});
4.5 光照烘焙與 UV
在 Blender 中烘焙光照后導出帶有uv2
的模型:
// 在Three.js中啟用第二組UV
geometry.setAttribute('uv2', new THREE.BufferAttribute(uv2Array, 2));
material.aoMap = aoTexture;
material.aoMap.uvTransform = new THREE.Matrix3().fromArray(uvTransform);
5. 常見問題解決方案
5.1 紋理拉伸問題
-
成因:UV分布不均勻
-
解決方案:
- 使用更密集的幾何細分
- 制作UDIM紋理集
- 應用三平面投影
5.2 接縫處理技巧
-
原因:UV 坐標不連續或導出時頂點 UV 重復。
-
解決方案:
-
在 Blender 中使用
Smart UV Project
重新展開。 -
導出時勾選
Merge by Distance
選項。 -
在 Three.js 中調整 UV 坐標:
const uvArray = geometry.attributes.uv.array; for (let i = 0; i < uvArray.length; i += 2) {uvArray[i] = uvArray[i] % 1;uvArray[i + 1] = uvArray[i + 1] % 1; } geometry.attributes.uv.needsUpdate = true;
6. 性能優化建議
- 合并UV集:將多個材質的UV合并到同一紋理圖集
- 使用壓縮紋理格式:推薦 KTX2或者Basis Universal 格式
- 避免動態UV更新:靜態幾何體應凍結UV緩沖區
- LOD策略:根據距離切換UV細節層級
7. 調試工具推薦
- UV檢查材質:
const debugMaterial = new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('uv-grid.png')
});
- Three.js編輯器:可視化UV展開
- Blender + Three.js導出:專業級UV編輯流程
結語
UV映射是連接3D模型與2D紋理的核心橋梁。通過深入理解Three.js的UV實現機制,開發者可以創建更復雜的材質效果、優化渲染性能,并解決實際項目中的各種紋理映射難題。實際開發中需注意:紋理尺寸需為2的冪、不同材質類型對UV的支持差異、移動端性能優化等。建議結合WebGL著色器編程,進一步挖掘UV系統的潛力。