three.js UV對映簡述

郭先生的部落格發表於2020-08-17

今天郭先生來說一說uv對映,什麼是uv對映?uv對映就是將二維的貼圖對映到物件的一個面(或者多個面)上。說到這個問題,我們就不得不瞭解一下Geometry的點、面和uv的結構。我們以BoxGeometry為例。

new THREE.BoxGeometry(20, 20, 20); //建立一個邊長為20的正方體。

我們可以發現一個長方體由八個點和12個三角面組成,就拿0-1-2-3這個面來看,兩個面的face3分別是:

也就是faces[0]對應頂點0-2-1,faces[1]對應頂點2-3-1,這個順序可以記一下。
Face3裡面有一個很重要的屬性materialIndex,這個索引是當使用陣列材質的時候指定使用哪個材質作為當前Face3的材質,對於BoxGeometry來說,前面的兩個三角面的materialIndex為0,後面的兩個為1,上面兩個為2,下面的兩個為3,左面兩個為4,右面的兩個為5,即使陣列中只有兩個材質,那麼也是按照這個順序(既只顯示前後兩個面)。

再說說uv對映,一個紋理圖的原點在其左下方,座標為(0,0),右下方為(1,0),左上方為(0,1),右上方為(1,1)

在Geometry中,faceVertexUvs決定了uv對映的關係,如下如就是uv對映關係

我們可以看出第一個三角面對應一個二維點陣列[new THREE.Vector2(0,1), new THREE.Vector2(0,0), new THREE.Vector2(1, 1)],他預設將face3[0]的第一個點對應紋理的第一個點,face3[0]的第二個點對應紋理的第二個點,,face3[0]的第三個點對應紋理的第三個點,最後的到的如下圖,

 

我們稍微改變一下[new THREE.Vector2(0.25,0.75), new THREE.Vector2(0.25,0.25), new THREE.Vector2(0.75, 0.75)],看看會發生什麼,

就變成這個樣子了,原因看下圖

接下來我們以陣列材質的方式和單張紋理圖的方式說一下如何將6個面賦予不同的貼圖(預設六個面是相同的貼圖)。

1. 陣列材質的方式

這種方法十分簡單,只需要建立6個貼圖材質即可

var geom = new THREE.BoxGeometry(20, 20, 20);
var mate1 = new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('/static/images/animal/kaola.png')});
var mate2 = new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('/static/images/animal/mao.png')});
var mate3 = new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('/static/images/animal/quan.png')});
var mate4 = new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('/static/images/animal/shi.png')});
var mate5 = new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('/static/images/animal/tuboshu.png')});
var mate6 = new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('/static/images/animal/xiongmao.png')});

var mesh = new THREE.Mesh(geom, [mate1, mate2, mate3, mate4, mate5, mate6]);
scene.add(mesh);

2. 單張紋理圖

如下圖所示,將六個面的紋理貼圖繪製到一張

var geom = new THREE.BoxGeometry(20, 20, 20);
var mate = new THREE.MeshBasicMaterial({map: new THREE.TextureLoader().load('/static/images/animal/an-uv.png')});
var mesh = new THREE.Mesh(geom, mate);
geom.faceVertexUvs[0][0] = [new THREE.Vector2(0,1), new THREE.Vector2(0,0.66), new THREE.Vector2(0.5, 1)];
geom.faceVertexUvs[0][1] = [new THREE.Vector2(0,0.66), new THREE.Vector2(0.5,0.66), new THREE.Vector2(0.5, 1)];
geom.faceVertexUvs[0][2] = [new THREE.Vector2(0.5,1), new THREE.Vector2(0.5,0.66), new THREE.Vector2(1, 1)];
geom.faceVertexUvs[0][3] = [new THREE.Vector2(0.5,0.66), new THREE.Vector2(1,0.66), new THREE.Vector2(1, 1)];
geom.faceVertexUvs[0][4] = [new THREE.Vector2(0,0.66), new THREE.Vector2(0,0.33), new THREE.Vector2(0.5, 0.66)];
geom.faceVertexUvs[0][5] = [new THREE.Vector2(0,0.33), new THREE.Vector2(0.5,0.33), new THREE.Vector2(0.5, 0.66)];
geom.faceVertexUvs[0][6] = [new THREE.Vector2(0.5,0.66), new THREE.Vector2(0.5,0.33), new THREE.Vector2(1, 0.66)];
geom.faceVertexUvs[0][7] = [new THREE.Vector2(0.5,0.33), new THREE.Vector2(1,0.33), new THREE.Vector2(1, 0.66)];
geom.faceVertexUvs[0][8] = [new THREE.Vector2(0,0.33), new THREE.Vector2(0,0), new THREE.Vector2(0.5, 0.33)];
geom.faceVertexUvs[0][9] = [new THREE.Vector2(0,0), new THREE.Vector2(0.5,0), new THREE.Vector2(0.5, 0.33)];
geom.faceVertexUvs[0][10] = [new THREE.Vector2(0.5,0.33), new THREE.Vector2(0.5,0), new THREE.Vector2(1, 0.33)];
geom.faceVertexUvs[0][11] = [new THREE.Vector2(0.5,0), new THREE.Vector2(1,0), new THREE.Vector2(1, 0.33)];

scene.add(mesh);

他們的結果同下圖。這裡faceVertexUvs陣列的第一維度是材質的索引,第二維度才是面的uv貼圖對映關係,由於只有一個材質,所以這裡的索引都是0。

這節說了一下uv的使用,下一節說一說關於它的小應用。

 

轉載請註明地址:郭先生的部落格

相關文章