1. 程式人生 > 程式設計 >three.js 利用uv和ThreeBSP製作一個快遞櫃功能

three.js 利用uv和ThreeBSP製作一個快遞櫃功能

最近有three網友,問我要不要學習blender,其實我感覺學習一下也無妨,不過花大量時間精通,尚可不必,術業有專攻給別人留一條路吧,哈哈。那我我們就是用ThreeBSP和uv貼圖的知識來製作一個定製化的快遞櫃,先上圖,線上案例請點選部落格原文。

three.js 利用uv和ThreeBSP製作一個快遞櫃功能

下面我們來講解一下這樣一個櫃子的製作。

1. 主角是一個JSON

這樣一個快遞櫃的核心是JSON資料的建立,有了jSON資料,我們就可以通過迴圈遍歷出櫃子,櫃門和uv對映關係。那面下面來看看我們的JSON資料(部分程式碼)。

var doorArray = [
  [94,10,-176,196,false],[94,-76,76,176,[46,15,186,60,147,21,105.5,true],89,78,20,62,41,true]
]

他是以一個數組的形式表現的,每一個數組代表一個櫃子資料,每一個數組中的第一項為當前櫃子寬度,第二項為高度,第三項為中心x位置,第四項而中心y位置,第五項為櫃子是否能開啟(因為有的地方為操作面板等)。

2. ThreeBSP繪製櫃子的整體架構。

說完核心,我們在看看櫃子的整體框架。下面是櫃子的側面圖,通過側面圖我們可以很清晰的看出我們做了什麼

three.js 利用uv和ThreeBSP製作一個快遞櫃功能

其實加的不多,就是在上面加了一個簷,下面加了兩個底座,還有就是在每個小快遞櫃中掏出一個洞。
我們看程式碼

var texture = new THREE.TextureLoader().load('/static/images/base/cabinet.jpg')
let pubMate = new THREE.MeshNormalMaterial();
let frameGeom = new THREE.BoxGeometry(450,200,50);
let frameMesh = new THREE.Mesh(frameGeom,pubMate);
frameMesh.position.y = 106;

let footShape = new THREE.Shape();
footShape.moveTo(0,2);
footShape.lineTo(8,-2);
footShape.lineTo(8,-4);
footShape.lineTo(0,0);
footShape.lineTo(-12,2);
footShape.lineTo(0,2);

let footExtrudeSettings = {
  steps: 5,depth: 450,bevelEnabled: false
};
let footGeom = new THREE.ExtrudeGeometry(footShape,footExtrudeSettings);
let footMesh = new THREE.Mesh(footGeom,pubMate);
let footMesh1 = footMesh.clone();
footMesh1.rotation.y = -Math.PI / 2;
footMesh1.position.x = 225;
footMesh1.position.y = 4;
footMesh1.position.z = 25;
let footMesh2 = footMesh.clone();
footMesh2.rotation.y = Math.PI / 2;
footMesh2.position.x = -225;
footMesh2.position.y = 4;
footMesh2.position.z = -25;

let headGeom = new THREE.BoxGeometry(450,5,20);
let headMesh = new THREE.Mesh(headGeom,pubMate);
headMesh.position.z = 23;
headMesh.position.y = 206 - 2.5;

let framebsp = new ThreeBSP(frameMesh);
let foot1bsp = new ThreeBSP(footMesh1);
let foot2bsp = new ThreeBSP(footMesh2);
let headbsp = new ThreeBSP(headMesh);

res = framebsp.union(foot1bsp).union(foot2bsp).union(headbsp);

for(var i=0; i<doorArray.length; i++) {
  let geom = new THREE.BoxGeometry(doorArray[i][0]-1,doorArray[i][1]-1,50);
  let mesh = new THREE.Mesh(geom,pubMate);
  mesh.position.set(doorArray[i][2],doorArray[i][3],4)
  let meshbsp = new ThreeBSP(mesh);
  res = res.subtract(meshbsp);
}

let cabinetGeom = res.toGeometry();
let cabinetMate = new THREE.MeshPhongMaterial({color: 0xD8C513,specular: 0xD8C513,shininess: 10});
let cabinetMesh = new THREE.Mesh(cabinetGeom,cabinetMate);
cabinetMesh.position.y = 106;

scene.add(cabinetMesh);

這裡就是在框架BoxGeometry的基礎上加了兩個底座ExtrudeGeometry,和一個簷BoxGeometry,然後遍歷減去小櫃子。掌握好各自的空間位置,製作其實並不難。

3. 櫃子的統一貼圖

將一張圖作為貼圖,貼到所有的mesh上,如最上面圖的效果,因為上節課已經大致的說了關於uv的一點知識。

for(var i=0; i<doorArray.length; i++) {
    let a0 = doorArray[i][0];
  let a1 = doorArray[i][1];
  let a2 = doorArray[i][2];
  let a3 = doorArray[i][3];

  let x1 = ((a2 - a0 / 2) + 223) / 446;
  let x2 = ((a2 + a0 / 2) + 223) / 446;
  let y1 = ((a3 - a1 / 2) - 10) / 191;
  let y2 = ((a3 + a1 / 2) - 10) / 191;

  doorMesh.geometry.faceVertexUvs[0][8] = [new THREE.Vector2(x1,y2),new THREE.Vector2(x1,y1),new THREE.Vector2(x2,y2)];
  doorMesh.geometry.faceVertexUvs[0][9] = [new THREE.Vector2(x1,y2)];
}

上面已經說過,這裡的a0是櫃子的寬,a1是櫃子的高,a2是櫃子中心x的座標值,a3是櫃子中心y的座標值。因為櫃子整體x的範圍是[-223,223],y的範圍的[10,201]。經過換算x1是紋理x座標的最小值,x2是紋理x座標的最大值,y1是紋理y座標的最小值,y2是紋理y座標的最大值,最後設定陣列索引為8和9小三角面的uv對映(因為我們要設定的面為長方體的左面,就是8和9控制的面)。

最後加上一點點開櫃子的動畫就大功告成了。

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

到此這篇關於three.js 利用uv和ThreeBSP製作一個快遞櫃功能的文章就介紹到這了,更多相關three.js 製作快遞櫃內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!