Three.js 开发机房(三)
之前三节都没涉及到机房,只是一些零零散散的知识点,这一节我们就开始正式画外墙。
首先我了明显理解以下啥是墙?其实说白了就是一个长方体,长不确定,宽一般也就是40cm,高也就是两米,这就是一个简单的墙,当然很多墙上都有窗户、门啥的,其实也就是在长方体的固定的位置掏个洞,然后放上我们需要方的东西,比如门,窗户。
在画墙之前我们需要对一个机房的俯视图进行分析,就比如下面这张机房的图片

(图片来自网络)
就像图片中显示的一样,这个机房非常标准,是个很标准的长方形机房,长900cm, 宽600cm,左侧的墙体是玻璃隔断,还有一扇门,
那好,我们就可以开干了,首先我们要初始化一个机房的结构布局的Json,注意门不能和窗户重合,有门的地方窗户需要分成门左边和门右边两个数组(当然你也可以写多个判断进行操作,但是比较麻烦)。
{
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}]}}
]
},
接下来我们开始画地板,我们目前就将地板和机房大小做一样:
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);
})
}
执行效果如下图:

紫色是我加给整个Html的颜色,主要是方便观看地板,接下来我们就开始画墙了,在画墙之前我们先初始化一个画长方体(窗宽高均默认为1)的函数:
initLambert() {
var cubeGeometry = new THREE.BoxGeometry(1, 1, 1);
this.initLambertMod = new THREE.Mesh(cubeGeometry, this.wallMatArray);
};
封装好之后我们在画墙的时候就不用每画一道墙就新建一个几何体和材质,我们只需要克隆我们刚才初始化的墙体就好了
之后我们正式封装具有具体长度、角度和位置在的墙
/**
* 画长方体
* @param { 长方体的长度 } width
* @param { 长方体的高度 } height
* @param { 长方体的厚度 } depth
* @param { 长方体旋转的角度 } angle
* @param { 长方体的材质 } material
* @param { 长方体的X轴坐标 } x
* @param { 长方体的Y轴坐标 } y
* @param { 长方体的Z轴坐标 } 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); //-逆时针旋转,+顺时针
return code;
};
这样我们就将一个具有长宽高、方向、位置的长方体就画出来了,
只是画出来还不行,我们需要将数据和模型关联起来,我们先对 this.data.wall 进行遍历得到这道墙的具体信息,是否有门窗,墙的起始点和结束点,知道了起始点和结束点,我们就能算出这道墙具体有多长,还有这道墙的角度

如上图,有以上两个点我们能得出该条线的信息
长度: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);
}
});
};
执行完我们就能看到如下图这样的结果了

还差一面墙,上面既有门又有窗户,那我们就先作既有门又有窗户的,献上一张图爽一下

要实现这样,那我们首先要封装一个几何ti裁切函数:
/**
* 几何体裁切函数
* @param { 被采裁切的集合体 } bsp
* @param { 要裁掉的集合体 } less_bsp
* @param { 区分是机房的墙还是机柜裁切的 } 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(); //重新计算几何体侧面法向量
result.geometry.computeVertexNormals();
result.material.needsUpdate = true; //更新纹理
result.geometry.buffersNeedUpdate = true;
result.geometry.uvsNeedUpdate = true;
if (mat == 2) {
result.nature = "Cabinet";
}
return result;
};
之后我们就开始对有门或者有窗户的墙面开始处理,先整理数据,将数据整理成我么能够最简单就能处理的
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) {
// 有窗户或有门或都有
// 当然判断里面还是分开成有门或者有窗户,但互不干涉
var window__List = []; // 盛放窗户的数组
var door__List = []; // 盛放门的数组
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);
}
});
};
整理完成之后我们就要开始对以上数据进行操作了,此时我们就需要创建函数cerateWallHadDoorOrGlass来开始画有玻璃和门的墙了
//画有门和有窗子的墙(工具函数)
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);
};
如此,大功告成,我们在放一面没有门但有玻璃的墙看看

画墙这块就到这儿,这篇文章整整花费了我一下午的时间,项目是直接从vue init webpack dome 开始的,各位看客如果觉得还行,麻烦给个“推荐”,哈哈哈,全当我一下午的辛苦没白费! * _ *
Three.js 开发机房(三)的更多相关文章
- Three.js 开发机房(四)
这一节我们讲讲怎么画机柜,其实机柜如果作的复杂一点.逼真一点可以用3D建模工具,不过一般的项目中也不用做的那么麻烦,那我们就可以将机柜抽象以下,首先它是一块具有长宽高的立方体铁块,然后我们从中间在掏掉 ...
- JS开发HTML5游戏《神奇的六边形》(三)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
- Node.js学习笔记——Node.js开发Web后台服务
一.简介 Node.js 是一个基于Google Chrome V8 引擎的 JavaScript 运行环境.Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效.Node.j ...
- JS开发HTML5游戏《神奇的六边形》(一)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
- heX——基于 HTML5 和 Node.JS 开发桌面应用
heX 是网易有道团队的一个开源项目,允许你采用前端技术(HTML,CSS,JavaScript)开发桌面应用软件的跨平台解决方案.heX 是你开发桌面应用的一种新的选择,意在解决传统桌面应用开发中繁 ...
- JS开发HTML5游戏《神奇的六边形》(二)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
- atitit js 开发工具 ide的代码结构显示(func list) outline总结
atitit js 开发工具 ide的代码结构显示(func list) outline总结 eclips环境::4.3.1 #-------需要一个js开发工具,可以显示outline或者代码结构显 ...
- JS开发HTML5游戏《神奇的六边形》(四)
近期出现一款魔性的消除类HTML5游戏<神奇的六边形>,今天我们一起来看看如何通过开源免费的青瓷引擎(www.zuoyouxi.com)来实现这款游戏. (点击图片可进入游戏体验) 因内容 ...
- EXT.NET高效开发(三)——使用Chrome浏览器的开发人员工具
这篇帖子老少皆宜,不分男女,不分种族,不分职业.俗话说:“磨刀不误砍柴工”.掌握一些开发工具的使用,对自己帮助是很大的(无论是用于分析问题,还是提高生产力).本篇就讲述如何利用Chrome浏览器(这里 ...
随机推荐
- 使用Minifly打造基于视觉感知的跟踪无人机
前言:无人机和人工智能现在是非常热门的话题,将两者结合起来是一个比较好的创意,本文介绍一种可行的解决方案来实现基于视觉感知的跟踪无人机.从零开始搭建无人机系统工作量和难度(以及钱)都是非常大的,所以在 ...
- 1.Go语言copy函数、sort排序、双向链表、list操作和双向循环链表
1.1.copy函数 通过copy函数可以把一个切片内容复制到另一个切片中 (1)把长切片拷贝到短切片中 package main import "fmt" func main() ...
- 深入理解JVM-java字节码文件结构剖析(练习解读字节码)
public class MyTest2 { String str = "Welcome"; private int x = 5; public static Integer in ...
- luogu2279_[HNOI2003]消防局的设立 贪心
传送门 不需要树形dp 关于深度排序 当前节点到最近的消防局(f[u])>2时要建新的与u的上面(v)的上面(w) 同时w的上面和上面的上面也要更新f值 #include <bits/st ...
- 使用JMS接口接入WebSphere MQ消息
在你的应用程序中利用IBM WebSphere MQ消息中间件提供Java消息服务开放接口. IBM WebSphere MQ(WMQ)是一套面向消息的中间件(message-oriented mid ...
- Mock Server的搭建
一.概述 我们系统与第三方开票系统有交互,场景是我们系统请求第三方开票系统,第三方开票系统根据我们的请求数据,生成开票信息然后返回发票号或异常信息,我们根据返回的信息做对应的处理.因为配合上存在一些障 ...
- while 的循环遍历 分享心得
while 基本循环体 1.while while 条件: 循环体 2.while else while 条件: 循环体 else:#如果while条件结果为假 不执行循环体 直接执行else 代码块 ...
- SpringBoot内置tomcat启动原理
前言 不得不说SpringBoot的开发者是在为大众程序猿谋福利,把大家都惯成了懒汉,xml不配置了,连tomcat也懒的配置了,典型的一键启动系统,那么tomcat在springb ...
- EVE-NG入门篇
目录 一.EVE-NG配置要求 二.EVE-NG 安装 三.基于OVA的安装步骤 四.导入设备介绍 五.启动设备 六.与secure CRT关联 七.常见问题 一.EVE-NG配置要求 1.最低配置 ...
- ASP.NET Core on K8S深入学习(7)Dashboard知多少
本篇已加入<.NET Core on K8S学习实践系列文章索引>,可以点击查看更多容器化技术相关系列文章. 在第二篇<部署过程解析与Dashboard>中介绍了如何部署Das ...