之前三節(jié)都沒涉及到機(jī)房,只是一些零零散散的知識(shí)點(diǎn),這一節(jié)我們就開始正式畫外墻。
首先我了明顯理解以下啥是墻?其實(shí)說白了就是一個(gè)長方體,長不確定,寬一般也就是40cm,高也就是兩米,這就是一個(gè)簡單的墻,當(dāng)然很多墻上都有窗戶、門啥的,其實(shí)也就是在長方體的固定的位置掏個(gè)洞,然后放上我們需要方的東西,比如門,窗戶。
在畫墻之前我們需要對(duì)一個(gè)機(jī)房的俯視圖進(jìn)行分析,就比如下面這張機(jī)房的圖片
(圖片來自網(wǎng)絡(luò))
就像圖片中顯示的一樣,這個(gè)機(jī)房非常標(biāo)準(zhǔn),是個(gè)很標(biāo)準(zhǔn)的長方形機(jī)房,長900cm, 寬600cm,左側(cè)的墻體是玻璃隔斷,還有一扇門,
那好,我們就可以開干了,首先我們要初始化一個(gè)機(jī)房的結(jié)構(gòu)布局的Json,注意門不能和窗戶重合,有門的地方窗戶需要分成門左邊和門右邊兩個(gè)數(shù)組(當(dāng)然你也可以寫多個(gè)判斷進(jìn)行操作,但是比較麻煩)。
{ houseWidth: 900, // 房間長度 houseHeight: 600, // 房間寬 angle: 45, // 房間朝向
wall: [ {position:{x: 0, y: 0, endX: 900, endY: 0}, door: {isDoor:
false}, windows: {isWindows:false}}, {position:{x: 900, y: 0, endX: 900,
endY: 600}, door: {isDoor: false}, windows: {isWindows: false}},
{position:{x: 0, y: 600, endX: 900, endY: 600}, door: {isDoor: false},
windows: {isWindows:false}}, {position:{x: 0, y: 0, endX: 0, endY: 600},
door: {isDoor: true, doorNum: 2, door_PointL [{x: 0, y: 200, endX: 0, endY:
400, doorDirection: 2}]}, windows: {isWindows: true, windows__Point: [{x: 0, y:
0, endX: 0, endY: 150}, {x: 0, y: 450, endX: 0, endY: 600}]}} ] },
接下來我們開始畫地板,我們目前就將地板和機(jī)房大小做一樣:
createFloor() { let _self = this; this.imgRendering.load("地板的圖片", texture =>
{ texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.repeat.set(8,
8); var floorGeometry = new THREE.BoxGeometry(this.houseWidth,
this.houseHeight, 1); var floorMaterial = new THREE.MeshBasicMaterial({ map:
texture, side: THREE.DoubleSide }); floorMaterial.opacity = 1;
floorMaterial.transparent = true; var floor = new THREE.Mesh(floorGeometry,
floorMaterial); floor.position.y = 0; floor.rotation.x = Math.PI / 2;
_self.scene.add(floor); }) }
執(zhí)行效果如下圖:
紫色是我加給整個(gè)Html的顏色,主要是方便觀看地板,接下來我們就開始畫墻了,在畫墻之前我們先初始化一個(gè)畫長方體(窗寬高均默認(rèn)為1)的函數(shù):
initLambert() { var cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
this.initLambertMod = new THREE.Mesh(cubeGeometry, this.wallMatArray); };
封裝好之后我們在畫墻的時(shí)候就不用每畫一道墻就新建一個(gè)幾何體和材質(zhì),我們只需要克隆我們剛才初始化的墻體就好了
之后我們正式封裝具有具體長度、角度和位置在的墻
/** * 畫長方體 * @param { 長方體的長度 } width * @param { 長方體的高度 } height * @param {
長方體的厚度 } depth * @param { 長方體旋轉(zhuǎn)的角度 } angle * @param { 長方體的材質(zhì) } material *
@param { 長方體的X軸坐標(biāo) } x * @param { 長方體的Y軸坐標(biāo) } y * @param { 長方體的Z軸坐標(biāo) } z */
createLambert(width, height, depth, angle, material, x, y, z) { var code =
this.initLambertMod.clone(); code.scale.set(width, height, depth)
code.position.set(x, y, z); code.rotation.set(0, angle * Math.PI, 0);
//-逆時(shí)針旋轉(zhuǎn),+順時(shí)針 return code; };
這樣我們就將一個(gè)具有長寬高、方向、位置的長方體就畫出來了,
只是畫出來還不行,我們需要將數(shù)據(jù)和模型關(guān)聯(lián)起來,我們先對(duì)?this.data.wall
進(jìn)行遍歷得到這道墻的具體信息,是否有門窗,墻的起始點(diǎn)和結(jié)束點(diǎn),知道了起始點(diǎn)和結(jié)束點(diǎn),我們就能算出這道墻具體有多長,還有這道墻的角度
如上圖,有以上兩個(gè)點(diǎn)我們能得出該條線的信息
長度:Math.sqrt(Math.pow(Math.abs(300 -0), 2) +Math.pow(Math.abs(0 -300), 2));
角度:Math.asin((300- 0) / (0 - 300)) / Math.PI
這樣我們就知道了該條線的具體信息,下面我們就能畫墻了:
createHouseWall() { this.data.wall.map((item) => { var position =
item.position; var w = position.endX - position.x; var h =
position.endY - position.y; var x = (position.x + w / 2) - (this.houseWidth
/ 2); var z = (position.y + h / 2) - (this.houseHeight / 2); var width
= Math.sqrt(Math.pow(w, 2) + Math.pow(h, 2)); var angle = Math.asin(h /
width) / Math.PI; if (item.windows.isWindows || item.door.isDoor) {
// 有窗戶或有門或都有 } else { // 沒門、沒窗戶 let code =
this.createLambert(width, 200, 10, angle, this.matArrayB, x, 100, z);
this.scene.add(code); } }); };
執(zhí)行完我們就能看到如下圖這樣的結(jié)果了
還差一面墻,上面既有門又有窗戶,那我們就先作既有門又有窗戶的,獻(xiàn)上一張圖爽一下
要實(shí)現(xiàn)這樣,那我們首先要封裝一個(gè)幾何ti裁切函數(shù):
/** * 幾何體裁切函數(shù) * @param { 被采裁切的集合體 } bsp * @param { 要裁掉的集合體 } less_bsp * @param
{ 區(qū)分是機(jī)房的墻還是機(jī)柜裁切的 } mat */ returnResultBsp(bsp, less_bsp, mat) { switch (mat) {
case 1: var material = new THREE.MeshPhongMaterial({ color: 0x9cb2d1, specular:
0x9cb2d1, shininess: 30, transparent: true, opacity: 1 }); break; case 2: var
material = new THREE.MeshPhongMaterial({ color: 0x42474c, specular: 0xafc0ca,
shininess: 30, transparent: true, opacity: 1 }); break; default: } var
sphere1BSP = new ThreeBSP(bsp); var cube2BSP = new ThreeBSP(less_bsp);
//0x9cb2d1 淡紫,0xC3C3C3 白灰 , 0xafc0ca灰 var resultBSP =
sphere1BSP.subtract(cube2BSP); var result = resultBSP.toMesh(material);
result.material.flatshading = THREE.FlatShading;
result.geometry.computeFaceNormals(); //重新計(jì)算幾何體側(cè)面法向量
result.geometry.computeVertexNormals(); result.material.needsUpdate = true;
//更新紋理 result.geometry.buffersNeedUpdate = true; result.geometry.uvsNeedUpdate
= true; if (mat == 2) { result.nature = "Cabinet"; } return result; };
之后我們就開始對(duì)有門或者有窗戶的墻面開始處理,先整理數(shù)據(jù),將數(shù)據(jù)整理成我么能夠最簡單就能處理的
createHouseWall() { this.data.wall.map((item) => { var position =
item.position; var w = position.endX - position.x; var h =
position.endY - position.y; var x = (position.x + w / 2) - (this.houseWidth
/ 2); var z = (position.y + h / 2) - (this.houseHeight / 2); var width
= Math.sqrt(Math.pow(w, 2) + Math.pow(h, 2)); var angle = Math.asin(h /
width) / Math.PI; if (item.windows.isWindows || item.door.isDoor) {
// 有窗戶或有門或都有 // 當(dāng)然判斷里面還是分開成有門或者有窗戶,但互不干涉 var window__List = []; //
盛放窗戶的數(shù)組 var door__List = []; // 盛放門的數(shù)組 if (item.windows.isWindows) {
item.windows.windows__Point.map((windows__Point, window__index) => { let
window__Json = {}; let windows__w = windows__Point.endX - windows__Point.x;
let windows__h = windows__Point.endY - windows__Point.y;
window__Json.window__x = (windows__Point.x + windows__w / 2) - (this.houseWidth
/ 2); window__Json.window__z = (windows__Point.y + windows__h / 2) -
(this.houseHeight / 2); window__Json.window__width =
Math.sqrt(Math.pow(windows__w, 2) + Math.pow(windows__h, 2));
window__Json.w_Height = 120; window__Json.window__y = 100;
window__List.push(window__Json); }); } if (item.door.isDoor) { var
door__num = item.door.doorNum || 1; item.door.door_Point.map((door__Point,
door__index) => { var door__Json = {}; var windows__w = door__Point.endX -
door__Point.x; var windows__h = door__Point.endY - door__Point.y; if (door__num
== 2) { let doubleDoorList = []; for (var i = 0; i < 2; i++) { door__Json = {};
door__Json.door__x = (door__Point.x + windows__w / 2) - (this.houseWidth / 2) +
(door__Point.endX - door__Point.x) / 2 * i; door__Json.door__z = (door__Point.y
+ windows__h / 2) - (this.houseHeight / 2) + (door__Point.endY - door__Point.y)
/ 2 * i; door__Json.door__width = (Math.sqrt(Math.pow(windows__w, 2) +
Math.pow(windows__h, 2))) / 2; door__Json.door__height = 180;
door__Json.door__y = 100; door__Json.doorDirection = door__Point.doorDirection;
if (door__Point.doorDirection < 2) { doubleDoorList.unshift(door__Json); } else
{ doubleDoorList.push(door__Json); } } door__List.push(doubleDoorList); } else
{ door__Json.door__x = (door__Point.x + windows__w / 2) - (this.houseWidth /
2); door__Json.door__z = (door__Point.y + windows__h / 2) - (this.houseHeight /
2); door__Json.door__width = Math.sqrt(Math.pow(windows__w, 2) +
Math.pow(windows__h, 2)); door__Json.door__height = 180; door__Json.door__y =
100; door__Json.doorDirection = door__Point.doorDirection;
door__List.push(door__Json); } }); } } else { // 沒門、沒窗戶 let
code = this.createLambert(width, 200, 10, angle, this.matArrayB, x, 100, z);
this.scene.add(code); } }); };
整理完成之后我們就要開始對(duì)以上數(shù)據(jù)進(jìn)行操作了,此時(shí)我們就需要?jiǎng)?chuàng)建函數(shù)cerateWallHadDoorOrGlass來開始畫有玻璃和門的墻了
//畫有門和有窗子的墻(工具函數(shù)) cerateWallHadDoorOrGlass(width, height, depth, angle,
material, x, y, z, door__list, windows__List) { //茶色:0x58ACFA 透明玻璃色:0XECF1F3
var glass_material = new THREE.MeshBasicMaterial({ color: 0XECF1F3 });
glass_material.opacity = 0.5; glass_material.transparent = true; var wall =
this.returnLambertObject(width, height, depth, angle, material, x, y, z);
windows__List.map((item, index) => { var window_cube =
this.returnLambertObject(item.window__width, item.w_Height, depth, angle,
material, item.window__x, item.window__y, item.window__z); wall =
this.returnResultBsp(wall, window_cube, 1); let code =
this.returnLambertObject(item.window__width, item.w_Height, 2, angle,
glass_material, item.window__x, item.window__y, item.window__z);
this.scene.add(code); }); var status__result = [0.5, 0.5, 0, 0, ]
door__list.map((item, index) => { if (item.length == 2) { item.map((c_item,
c_index) => { let door_cube = this.returnLambertObject(c_item.door__width,
c_item.door__height, 10, angle, this.matArrayB, c_item.door__x, c_item.door__y,
c_item.door__z); wall = this.returnResultBsp(wall, door_cube, 1); let
doorgeometry = new THREE.BoxGeometry(100, 180, 2); let door = ""; if (c_index
== 0) { door = new THREE.Mesh(doorgeometry, this.LeftDoorRenderingList); } else
{ door = new THREE.Mesh(doorgeometry, this.DoorRenderingList); }
door.position.set(c_item.door__x, c_item.door__y, c_item.door__z);
door.rotation.y = status__result[c_item.doorDirection] * Math.PI; door.nature =
"door"; door.direction = c_item.doorDirection; door.isClose = 1; door.doorIndex
= c_index; this.scene.add(door); }); } else { let door_cube =
this.returnLambertObject(item.door__width, item.door__height, 10, angle,
this.matArrayB, item.door__x, item.door__y, item.door__z); wall =
this.returnResultBsp(wall, door_cube, 1); let doorgeometry = new
THREE.BoxGeometry(100, 180, 2); let door = new THREE.Mesh(doorgeometry,
this.DoorRenderingList); door.position.set(item.door__x, item.door__y,
item.door__z); door.rotation.y = status__result[item.doorDirection] * Math.PI;
door.nature = "door"; door.direction = item.doorDirection; door.isClose = 1;
this.scene.add(door); } }); this.scene.add(wall); };
如此,大功告成,我們在放一面沒有門但有玻璃的墻看看
畫墻這塊就到這兒,這篇文章整整花費(fèi)了我一下午的時(shí)間,項(xiàng)目是直接從vue init webpack dome
開始的,各位看客如果覺得還行,麻煩給個(gè)“推薦”,哈哈哈,全當(dāng)我一下午的辛苦沒白費(fèi)! * _ *
?
熱門工具 換一換