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压缩并上传
一.图片上传前端压缩的现实意义 对于大尺寸图片的上传,在前端进行压缩除了省流量外,最大的意义是极大的提高了用户体验. 这种体验包括两方面: 由于上传图片尺寸比较小,因此上传速度会比较快,交互会更加流畅 ...
随机推荐
- Ethical Hacking - POST EXPLOITATION(1)
METERPRETER BASICS >help - shows help >background - backgrounds current session >sessions - ...
- awesome : vue-awesome 按需引入
其实挺简单的,被文档带到沟里去了. main.js: 首先讲一下全部引入,很简单. import 'vue-awesome/icons' import Icon from 'vue-awesome/c ...
- three.js 数学方法之Vector3
今天郭先生来说一说three.js的Vector3,该类表示的是一个三维向量(3D vector). 一个三维向量表示的是一个有顺序的.三个为一组的数字组合(标记为x.y和z),可被用来表示很多事物, ...
- springboot文件上传 流的方式 后台计算上传进度
//代码 public static void main(String[] args) throws Exception { String path = "f:/svn/t_dictiona ...
- Elasticsearch及相关插件的安装
Elasticsearch及相关插件的安装 1.安装Elasticsearch并启动服务 2.安装第三方插件 2.1.Head插件 是Elasticsearch的一个集群管理工具,可以通过它来查看和搜 ...
- 两数相加(B站看视频总结)
''' 两数相加: 给出两个 非空 的链表用来表示两个非负的整数 各自的位数是按照逆序的方式存储的 每一个节点只能保存 一位数 示例: 输入:(2->4->3) + (5->6-&g ...
- JavaScript Set对象
JavaScript Set对象 Set 用于存储任何类型的唯一值,无论是基本类型还是引用类型. 只有值没有键 严格类型检测存储,字符串数字不等同于数值型数字 存储的值具有唯一性 遍历顺序是添加的顺序 ...
- 6-Pandas之缺失值处理
一.了解缺失值 通常使用 NA('not available')来代指缺失值 在Pandas的数据结构中,缺失值使用 NaN('Not a Number')进行标识 除了汇总统计方法,还可以使用isn ...
- Python os.fpathconf() 方法
概述 os.fpathconf() 方法用于返回一个打开的文件的系统配置信息.高佣联盟 www.cgewang.com Unix上可用. 语法 fpathconf()方法语法格式如下: os.fpat ...
- PHP xml_error_string() 函数
定义和用法 xml_error_string() 函数获取 XML 解析器的错误描述.高佣联盟 www.cgewang.com 如果成功,该函数则返回错误描述.如果失败,则返回 FALSE. 语法 x ...