three.js使用的人太少了,一个博文就几百个人看,之前发js基础哪怕是d3都会有几千的阅读量,看看以后考虑说一说d3了,哈哈。吐槽完毕回归正题。前几天郭先生看到网上有人开发了3D机房,正愁博客没什么写的,于是昨天熬夜也做了一个,今天就把大体的流程告诉萌新们,先说说主要功能模块。

  1. 墙体、地面、窗户以及门的实现(双击门禁门可开关)。
  2. 机柜实现(机柜门的开关、机箱的推拉以及开关推拉的条件)。
  3. 机箱存储占用比率(用颜色表示占用率,并附颜色谱图)。
  4. 监控摄像视角(包括监控摄像机的模型导入,和四视角监控)。
  5. 红外防控报警。
  6. 强弱电线的铺设。
  7. 以及风向。

下面对应这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. 封装动画

这里面有很多动画,例如各种门的转动,服务器的平移,如果直接改变属性闲得很突兀,那么我们有几种选择,

  1. 关键帧动画
  2. Tween动画
  3. 自制动画

这里我们练习自己封装一个小动画,他虽然可能不够精确,但是十分实用。

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 制作机房(上)的更多相关文章

  1. three.js 制作机房(下)

    这一篇书接上文,说一说剩下的一些模块. 1. 机箱存储占用比率 机箱存储占用比其实很简单,就是在机箱上新加一个组即可,然后根据比率值来设置颜色,这个颜色我们去HSL(0.4,0.8,0.5) ~ HS ...

  2. js制作带有遮罩弹出层实现登录小窗口

    要实现的效果如下 点击“登录”按钮后,弹出登录小窗口,并且有遮罩层(这个名词还是百度知道的,以前只知道效果,却不知道名字) 在没有点击“登录”按钮之前登录小窗口不显示,点击“登录”按钮后小窗口显示,并 ...

  3. 用JS制作一个信息管理平台完整版

      前  言 JRedu 在之前的文章中,介绍了如何用JS制作一个实用的信息管理平台. 但是那样的平台功能过于简陋了,我们今天来继续完善一下. 首先我们回顾一下之前的内容.   1.JSON的基础知识 ...

  4. 利用css+原生js制作简易钟表

    利用css+原生js制作简单的钟表.效果如下所示 实现该效果,分三大块:html.javascript.css html部分html部分比较简单,定义一个clock的div,内部有原点.时分秒针.日期 ...

  5. JS制作图片切换

    <!DOCTYPE html> <html> <head> <title>纯JS制作简单的图片切换</title> <meta cha ...

  6. 使用Vue.js制作仿Metronic高级表格(一)静态设计

    Metronic高级表格是Metonic框架中自行实现的表格,其底层是Datatables.本教程将主要使用Vue实现交互部分,使用Bootstrap做样式库.jQuery做部分用户交互(弹窗). 使 ...

  7. D3.js 制作中国地图 .net 公共基础类

    D3.js 制作中国地图 from:  http://d3.decembercafe.org/pages/map/index.html GeoJSON is a format for encoding ...

  8. 使用WebGL + Three.js制作动画场景

    使用WebGL + Three.js制作动画场景 3D图像,技术,打造产品,还有互联网:这些只是我爱好的一小部分. 现在,感谢WebGL的出现-一个新的JavaScriptAPI,它可以在不依赖任何插 ...

  9. HTML5 file API加canvas实现图片前端JS压缩并上传

    一.图片上传前端压缩的现实意义 对于大尺寸图片的上传,在前端进行压缩除了省流量外,最大的意义是极大的提高了用户体验. 这种体验包括两方面: 由于上传图片尺寸比较小,因此上传速度会比较快,交互会更加流畅 ...

随机推荐

  1. 消除win10桌面图标的右下方小箭头

    很容易的小东西,在这里简单提一下 新建一个记事本,写下以下代码,改为.bat后缀,双击运行,然后箭头消失 reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Micro ...

  2. 【Nginx】图片显示过慢,文件下载不完全,竟然是Nginx的锅!!

    写在前面 最近,一名读者跟我说他通过浏览器访问自己的服务器时,图片显示的非常慢,以至于在浏览器中都无法完全加载出来,下载文件时,更是恼火,文件根本就无法完全下载下来.而且奇怪的是这位读者所在的网络是没 ...

  3. 小特跨境电商ERP桌面版 1.不止包括进销存 还能算毛利

    经过近几年跨境电商ERP的开发,加上对跨境电商行业的业务积累,开发出一套适合中小跨境电商公司使用的ERP软件.欢迎选购.支持目前流行的各大电商平台,如速卖通.敦煌网.亚马逊.Shopee.Wish等. ...

  4. SmartMS如何使用二次验证码/虚拟MFA/两步验证/谷歌身份验证器?

    一般点账户名——设置——安全设置中开通虚拟MFA两步验证 具体步骤见链接 SmartMS如何使用二次验证码/虚拟MFA/两步验证/谷歌身份验证器? 二次验证码小程序于谷歌身份验证器APP的优势 1.无 ...

  5. Markdown显示测试

    这是一个一级标题 文本1 文本2 这是一个二级标题 斜体 粗体 粗斜体 下面是分割线 上面是分割线 删除线 下划线 脚注[1] 这是一个三级标题 无序列表1 内容 无序列表2 内容 无序列表3 有序列 ...

  6. Oracle数据库出现[23000][2291] ORA-02291: integrity constraint (SIMTH.SYS_C005306) violated异常

    参考链接 这个异常发生在往中间表中插入数据时,这时出现异常是因为关联的某个表没有插入数据,所以给没有插入数据的关联表插入数据,再给中间表插入数据此时异常就会解决.

  7. Python按值传递参数和按引用传递参数

    Python按值传递参数和按引用传递参数: 按值传递参数: 使用一个变量的值(数字,字符串),放到实参的位置上 注:传递过去的是变量的副本,无论副本在函数中怎么变,变量的值都不变 传递常量: # 传递 ...

  8. Django学习路23_if else 语句,if elif else 语句 forloop.first第一个元素 .last最后一个元素,注释

    if else 格式 {% if 条件 %} <标签>语句</标签> {%else%} <标签>语句</标签> {%endif} 标签都可以添加样式 { ...

  9. pdb 进行调试

    import pdb a = 'aaa' pdb.set_trace( ) b = 'bbb' c = 'ccc' final = a+b+c print(final) import pdb a = ...

  10. 自述:转职IT ,痛苦一阵子;不转职IT,痛苦一辈子(第一章)

    作为一个从后期制作转职过来的Java工程师,我认为我是幸运的,虽然我的本科专业(影视后期)也是火爆行业,不愁工作,但我不后悔进入这个IT坑,毕竟转行,只痛苦一阵子,但是不转行,可能我会痛苦一辈子. 我 ...