three.js 制作机房(上)
three.js使用的人太少了,一个博文就几百个人看,之前发js基础哪怕是d3都会有几千的阅读量,看看以后考虑说一说d3了,哈哈。吐槽完毕回归正题。前几天郭先生看到网上有人开发了3D机房,正愁博客没什么写的,于是昨天熬夜也做了一个,今天就把大体的流程告诉萌新们,先说说主要功能模块。
- 墙体、地面、窗户以及门的实现(双击门禁门可开关)。
- 机柜实现(机柜门的开关、机箱的推拉以及开关推拉的条件)。
- 机箱存储占用比率(用颜色表示占用率,并附颜色谱图)。
- 监控摄像视角(包括监控摄像机的模型导入,和四视角监控)。
- 红外防控报警。
- 强弱电线的铺设。
- 以及风向。
下面对应这7个功能模块附图。







看图是不是感觉很好呢?不过细分下来每个点都是十分简单的。那么我们就按照模块分析一下。
1. 墙体、地面、窗户以及门的实现
这一块主要就是对于3d空间位置的理解,旋转的使用以及uv的使用。考虑到墙面和窗户代码的重复使用,这里封装一下。封装完以后,改变更加灵活方便,门的旋转参见之前发的博客模拟门转动。
1. 墙的实现
这里我们看下墙的数据,数组的每一项就是一面墙(这里我要求每一面墙最多只能有一个门位和窗户位,如果想两个窗户,那么就在原本的一面墙上设置两个数组),s表示墙的size,p表示墙的position(这里用不到选不考虑旋转),hasDoor表示有门,ds表示门的size,dp表示门的position,hasWindow表示是否有窗,ws表示窗的size,wp表示窗的position,是不是挺简单的(当然每个人设计的都不相同)。这样绘制出来的图,就如我上面发的图。下面上代码
var wallArr = [
{s: [1, 20, 61], p: [45, 10, 0], dir: 'z', hasDoor: true, ds: [1, 18, 18], dp: [45, 9, 15], hasWindow: true, ws: [1, 10, 24], wp: [45, 10, -13]},
{s: [1, 20, 61], p: [-45, 10, 0], dir: 'z', hasDoor: false, hasWindow: true, ws: [1.2, 10, 50], wp: [-45, 10, 0]},
// {s: [46, 20, 1], p: [22.5, 10, 30], dir: 'x', hasDoor: false, hasWindow: true, ws: [30, 10, 1], wp: [22.5, 10, 30]},
// {s: [46, 20, 1], p: [-22.5, 10, 30], dir: 'x', hasDoor: false, hasWindow: true, ws: [30, 10, 1], wp: [-22.5, 10, 30]},
// {s: [46, 20, 1], p: [22.5, 10, -30], dir: 'x', hasDoor: false, hasWindow: true, ws: [30, 10, 1], wp: [22.5, 10, -30]},
// {s: [46, 20, 1], p: [-22.5, 10, -30], dir: 'x', hasDoor: false, hasWindow: true, ws: [30, 10, 1], wp: [-22.5, 10, -30]},
{s: [91, 20, 1], p: [0, 10, 30], dir: 'x', hasDoor: false, hasWindow: true, ws: [80, 10, 1], wp: [0, 10, 30]},
{s: [91, 20, 1], p: [0, 10, -30], dir: 'x', hasDoor: false, hasWindow: true, ws: [80, 10, 1], wp: [0, 10, -30]}
];
就是一个这样的数组。我们将注释打开,并注释掉后两行,得到如图效果。

ok测试没有问题。
再说说墙的实现,这里使用了ThreeBSP,之前我也说过这个东西,它可以实现几何体的二元操作(A与B的和、A与B的差,A与B的交集)。这个东西我们用来在墙体中扣出窗户和门的位置。
2. 门的实现
接下来说一说门的纹理,ps一张门的图,记得将底图加上颜色和透明度,门把手不加透明,导出png,然后制作材质记得加上transparent。这里会有一个问题,那就是uv,因为boxGeometry各个面的uv都是[0,1],[1,1],[0,0],[1,0](如果没记错的话),多以这个门的反正面的把手肯定是不一样的方向,这样我们就改变一下uv
doorGeom1.faceVertexUvs[0][2] = [new THREE.Vector2(1,1), new THREE.Vector2(1,0), new THREE.Vector2(0,1)];
doorGeom1.faceVertexUvs[0][3] = [new THREE.Vector2(1,0), new THREE.Vector2(0,0), new THREE.Vector2(0,1)];
doorGeom2.faceVertexUvs[0][0] = [new THREE.Vector2(1,1), new THREE.Vector2(1,0), new THREE.Vector2(0,1)];
doorGeom2.faceVertexUvs[0][1] = [new THREE.Vector2(1,0), new THREE.Vector2(0,0), new THREE.Vector2(0,1)];
具体的旋转,之前博客有实现过。
3. 地面的实现
地面相信大家都会弄,主要是调整一个repeat和wrap,不多说。
floorT.wrapS = floorT.wrapT = THREE.RepeatWrapping;
floorT.repeat.x = floorT.repeat.y = 12;
2. 机柜的实现
这是里面对相对复杂的模块,不过里面还是用到了ThreeBSP,平移旋转、uv以及射线方面的知识,对于单个绘制来说,相信大家都能后信手拈来,不多对于大数量的机柜实现开关门、推拉服务器的点击操作逻辑(机柜关门是不允许推拉服务器操作,机柜中有服务器来出来是,不允许开关门操作),和机柜的隐藏显示。
1. 机柜架子的实现
机柜框架使用了ThreeBSP,将两个BoxGeometry相减既会出现一个没有门的框架,我们在加上门即可,门的旋转之前讲过了,
2. 服务器的实现
服务器的uv贴图只需要正面的即可,所以除了前两个三角形,其他的设置成这样就可以了。
for(let i=2; i<serGeom.faceVertexUvs[0].length; i++) {
serGeom.faceVertexUvs[0][i] = [new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2()];
}
3.服务器和柜门的点击事件
这里面我们考虑使用THREE.Raycaster类。
这是一个射线类,原理是鼠标在屏幕上点击的时候,得到二维坐标p(x, y),再加上深度坐标的范围(0, 1), 就可以形成两个三位坐标A(x1, y1, 0), B(x2, y, 1),这两个点的线穿过的Object3D由近及远返回一个数组,第一个便是我们点击到的对象。我们给之前的服务器机柜和服务器都加上名字方便我们知道点到的是哪一个。
let intersectFrameDoor = raycaster.intersectObjects(motorGroup.children, true);
let tempArr = intersectFrameDoor[0].object.name.split('-');//得到[机柜门/服务器名字,机柜编号,服务器编号[
if(tempArr[0] == 'mdoor') {
if(!this.motorServerFlag[tempArr[1]]) {
if(this.motorDoorFlag[tempArr[1]]) {
this.doAnimate(Math.PI * 3 / 5, 0, 500, intersectFrameDoor[0].object.parent, ['rotation', 'y'])
this.motorDoorFlag[tempArr[1]] = false;
} else {
this.doAnimate(0, Math.PI * 3 / 5, 500, intersectFrameDoor[0].object.parent, ['rotation', 'y'])
this.motorDoorFlag[tempArr[1]] = true;
}
}
} else if(tempArr[0] == 'mserver') {
if(this.motorDoorFlag[tempArr[1]]) {
let posx = intersectFrameDoor[0].object.position.x;
if(posx == 0) {
this.doAnimate(0, 2, 500, intersectFrameDoor[0].object, ['position', 'x']);
this.motorServerFlag[tempArr[1]] += 1;
} else {
this.doAnimate(2, 0, 500, intersectFrameDoor[0].object, ['position', 'x']);
this.motorServerFlag[tempArr[1]] -= 1;
}
}
}
4. 封装动画
这里面有很多动画,例如各种门的转动,服务器的平移,如果直接改变属性闲得很突兀,那么我们有几种选择,
- 关键帧动画
- Tween动画
- 自制动画
这里我们练习自己封装一个小动画,他虽然可能不够精确,但是十分实用。
doAnimate(s, e, t, o, a) { //开始的属性值、结束的属性值 时间 对象 属性
let temp = s;
let step = t / 20;
let stepLen = (e - s) / step;
let animationObj = setInterval(() => {
temp += stepLen;
if(stepLen > 0 && temp >= e) {
o[a[0]][a[1]] = e;
clearInterval(animationObj);
} else if(stepLen < 0 && temp <= e) {
o[a[0]][a[1]] = e;
clearInterval(animationObj);
} else {
o[a[0]][a[1]] = temp;
}
}, 20)
}
在fpx大于50的情况下,基本准确。
今天就先讲这两个模块,下一篇继续,觉得可以的话,点个赞吧。
转载请注明地址:郭先生的博客
three.js 制作机房(上)的更多相关文章
- three.js 制作机房(下)
这一篇书接上文,说一说剩下的一些模块. 1. 机箱存储占用比率 机箱存储占用比其实很简单,就是在机箱上新加一个组即可,然后根据比率值来设置颜色,这个颜色我们去HSL(0.4,0.8,0.5) ~ HS ...
- js制作带有遮罩弹出层实现登录小窗口
要实现的效果如下 点击“登录”按钮后,弹出登录小窗口,并且有遮罩层(这个名词还是百度知道的,以前只知道效果,却不知道名字) 在没有点击“登录”按钮之前登录小窗口不显示,点击“登录”按钮后小窗口显示,并 ...
- 用JS制作一个信息管理平台完整版
前 言 JRedu 在之前的文章中,介绍了如何用JS制作一个实用的信息管理平台. 但是那样的平台功能过于简陋了,我们今天来继续完善一下. 首先我们回顾一下之前的内容. 1.JSON的基础知识 ...
- 利用css+原生js制作简易钟表
利用css+原生js制作简单的钟表.效果如下所示 实现该效果,分三大块:html.javascript.css html部分html部分比较简单,定义一个clock的div,内部有原点.时分秒针.日期 ...
- JS制作图片切换
<!DOCTYPE html> <html> <head> <title>纯JS制作简单的图片切换</title> <meta cha ...
- 使用Vue.js制作仿Metronic高级表格(一)静态设计
Metronic高级表格是Metonic框架中自行实现的表格,其底层是Datatables.本教程将主要使用Vue实现交互部分,使用Bootstrap做样式库.jQuery做部分用户交互(弹窗). 使 ...
- D3.js 制作中国地图 .net 公共基础类
D3.js 制作中国地图 from: http://d3.decembercafe.org/pages/map/index.html GeoJSON is a format for encoding ...
- 使用WebGL + Three.js制作动画场景
使用WebGL + Three.js制作动画场景 3D图像,技术,打造产品,还有互联网:这些只是我爱好的一小部分. 现在,感谢WebGL的出现-一个新的JavaScriptAPI,它可以在不依赖任何插 ...
- HTML5 file API加canvas实现图片前端JS压缩并上传
一.图片上传前端压缩的现实意义 对于大尺寸图片的上传,在前端进行压缩除了省流量外,最大的意义是极大的提高了用户体验. 这种体验包括两方面: 由于上传图片尺寸比较小,因此上传速度会比较快,交互会更加流畅 ...
随机推荐
- Java数组倒置
Java数组之 -- 数组倒置 方法一 : package mytest; public class test2 { public static void main(String[] args ...
- NCRE-Python考点
NCRE-Python考点 作者:封亚飞本文不含 文件处理.面向对象程序设计.公共基础.计算生态希望各位可以批评指正Qq 64761294 由于图片上传不方便,需要真题的朋友可以加我的qq找我要pdf ...
- Java 并发队列 BlockingQueue
BlockingQueue 开篇先介绍下 BlockingQueue 这个接口的规则,后面再看其实现. 首先,最基本的来说, BlockingQueue 是一个先进先出的队列(Queue),为什么说是 ...
- CMD运行JAVA出现“错误:编码GBK的不可映射字符”
问题: 原因: 字符编码问题.由于java文件中有中文字符,而cmd在编译时解码默认使用GBK,所以导致无法解码出正确的中文字符. 解决办法: 使用-encoding指令指定运行编码为UTF-8.
- phpcms视频模块实现列表页打开内容页直接播放视频
摘自phpcms论坛 原链接地址:http://bbs.phpcms.cn/thread-557691-1-1.html 之前下载研究过“化蝶自在飞”开发的视频模型,发现功能不错,但唯一的缺憾是,我想 ...
- 如何部署redis服务
使用工具 redis-64-3.2.100 部署系统 windows server 2012R2 1.下载安装redis-64-3.2.100安装包,下载地址:https://github.com/m ...
- try{}catch的隐藏(如何优雅的实现异常块)
在项目中,我们会遇到异常处理,对于运行时异常,需要我们自己判断处理.对于受检异常,需要我们主动处理. 但是繁琐的try{}caht嵌套在代码里,看着很不舒服,这里我们不讨论性能,就代码来讲,来看看如何 ...
- PHP stristr() 函数
实例 查找 "world" 在 "Hello world!" 中的第一次出现,并返回字符串的剩余部分: <?php高佣联盟 www.cgewang.com ...
- MediaDevices对象
mediaDevices 是 Navigator对象的一个 只读属性,返回一个 MediaDevices 对象,该对象可提供对相机和麦克风等媒体输入设备的连接访问,也包括屏幕共享. 语法 const ...
- C/C++编程笔记:C语言实现连连看游戏,小白练手项目(源码分享)
本篇文章分享看题目就知道是写给初学者的,学的比较好的小伙伴也可以将自动算法等一些知识给加进去,希望对大家有帮助! 好了,当我们所有的准备工作做好之后,我们就可以来编写我们的C语言连连看游戏了! 其实这 ...