使用three.js(webgl)搭建智慧楼宇、设备检测、数字孪生——第十三课
老子云:有道无术,术尚可求,有术无道,止于术。
咱开篇引用老子的话术,也没其它意思,只是最近学习中忽有感悟,索性就写了上来。
这句话用现代辩证思维理解,这里的”道“ 大抵是指方法论,解决大部分问题的一般发展规律,例如学习的方法,解决问题的方法,获取知识的方法。而这里的”术“就可以理解为解决具体问题的技术,例如,一门手艺,一项专业,一个技能等。老子的意思是要掌握一般事物的发展规律...
学习技术,也是一样,比如咱最近专注的3D技术,往行而上了说,道在于实践中求知的方法论,术在于熟练并应用技术的能力。而往行而下了讲,道在于3D具体执行的原理(了解掌握webgl),术则在于封装好的库的应用(了解掌握three.js)
不过现在静下心,看文字的很少了,上面说教了这么一堆废话,我也全当一说,你如读了,也权当一乐。要是有那么一点赞同,姑且也就这么滴吧。
序:
最近也很长时间没有记一些博文了,翻了一下之前的项目,重新以现在的角度审度之前的代码,看看有没有啥可以提炼,可以改进的点。温故而知新吗。
看自己之前写的代码,有些地方能发现一些惊喜,但大部分都是惊吓,都是写了啥啊,咋当时就这么写了,大多时候都是满脸的鄙夷。
这个项目还是好久前的项目,具体时候,不太记得了,是给杭州的一个泵业小镇做的智慧楼宇。当时说是智慧楼宇,但是监控的设备,并没有那么多。估计也是一个试点项目吧。
智慧楼宇的项目做过好多个,可以看看我之前的一些案例课程:
物联网3D,物业基础设施3D运维,使用webgl(three.js)与物联网设备结合案例。搭建智慧楼宇,智慧园区,3D园区、3D物业设施,3D楼宇管理系统——第八课
使用webgl(three.js)搭建3D智慧园区、3D大屏,3D楼宇,智慧灯杆三维展示,3D灯杆,web版3D,bim管理系统——第六课
闲话少序,咱么切入正题。
一、整体效果
首先我们先看一下整体的建模项目效果,如下:
二、功能展示
功能还是比较简单的,无非是一些多角度展示与简单几种设备检测
2.1、视角切换
视角切换比较再技术上实现比较简单,主要是改变主摄像机camera的属性
在场景中调整几个固定的角度,然后提取摄像机的属性值,再跟视角按钮做关联,这样就可以简单实现外场的视角切换了。
2.2、楼层切换
楼层切换稍微复杂一些,这里主要使用了按需加载,建模时也要考虑到具体场景的应用
楼层切换,首先考虑的是楼层再何时加载,如果一开始全部预加载好,这无疑是对性能与速度的浪费,其次是加载后是否需要销毁。
例如上图,场景复原后,内部楼层是否再可视范围内,对于webgl来说,在场景内的模型,都是需要进行计算绘制的,不管是否被遮挡。
再如上图,再次调用打开楼层时,如何处理动画,如何节约资源。这些都是主要的技术点。我们后面节点着重讲解方法。这里着重介绍功能
2.3、设备监控
智慧楼宇,数字孪生,主要核心在于采集端数据跟展示端数据的关联控制。
如上图 设备与楼层关联,定位某种类型设备时,自动展开楼层。
三、技术讲解
3.1、建模
建模除了固有的特效模型需要处理外,其它的就需要根据业务逻辑对模型进行分解,归类,本着不浪费新能,极致加载的原则。例如这个项目,我们模型分解如下:
3.1.1外立面模型框架
初见的场景,只做外立面模型,不做内部模型


{ "show": true, "uuid": "", "name": "bout_f13_0", "objType": "ExtrudeGeometry", "position": { "x": 2117.824, "y": 5950.545, "z": 2309.159 }, "style": { "skinColor": 16711680, "skin": { "skin_up": { "skinColor": 3911420, "materialType": "lambert", "side": 1, "opacity": 1, "imgurl": "../img/3dImg/floor.jpg", "repeatx": true, "width": 0.005, "repeaty": true, "height": 0.005, "envMap": { "name": "skybox", "reflectivity": 0.4, "refractionRatio": 0.4, "combine": "" } }, "skin_down": { "skinColor": 16711680, "side": 1, "opacity": 1 }, "skin_side": { "skinColor": 846790, "side": 2, "opacity": 1 } } }, "scale": { "x": 1, "y": 1, "z": 1 }, "shapeParm": { "points": [{ "x": 0, "y": 0, "type": "nomal" }, { "x": 0, "y": 100, "type": "nomal" }, { "x": 100, "y": 100, "type": "nomal" }, { "x": 100, "y": 2300, "type": "nomal" }, { "x": -50, "y": 2300, "type": "nomal" }, { "x": -50, "y": 2450, "type": "nomal" }, { "x": -2500, "y": 2450, "type": "nomal" }, { "x": -2500, "y": 2300, "type": "nomal" }, { "x": -2650, "y": 2300, "type": "nomal" }, { "x": -2650, "y": 100, "type": "nomal" }, { "x": -2500, "y": 100, "type": "nomal" }, { "x": -2500, "y": 0, "type": "nomal" }], "holes": [] }, "extrudeSettings": { "amount": 1, "curveSegments": 6, "steps": 1, "bevelEnabled": false, "bevelThickness": 1, "bevelSize": 1, "bevelSegments": 1, "extrudePathPoints": [] }, "showSortNub": 5, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "rotation": [{ "direction": "x", "degree": -1.5707963267948966 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }
3.1.2、独立楼层模型
楼层模型按需加载,即用到时再加载,看不到时直接不加载或者隐藏,模型代码如下:


[{"show":true,"uuid":"","name":"build_f2_4","objType":"ExtrudeGeometry","position":{"x":-994.227,"y":810,"z":-54.692},"style":{"skinColor":16711680,"skin":{"skin_up":{"skinColor":3911935,"side":0,"opacity":0},"skin_down":{"skinColor":16711680,"side":1,"opacity":1},"skin_side":{"skinColor":2279636,"side":2,"opacity":0.8,"imgurl":"../img/3dImg/dl01.png","repeatx":true,"width":0.0001,"repeaty":true,"height":0.003}}},"scale":{"x":0.35,"y":0.35,"z":1},"shapeParm":{"points":[{"x":-11200,"y":4620,"type":"nomal"},{"x":-11580,"y":4620,"type":"absarc","radius":400,"startAngle":0,"endAngle":1.3962634015954636,"Clockwise":false},{"x":-13000,"y":5380,"type":"nomal"},{"x":-13300,"y":4600,"type":"absarc","radius":810,"startAngle":1.5707963267948966,"endAngle":2.2689280275926285,"Clockwise":false},{"x":-15400,"y":3780,"type":"nomal"},{"x":-15000,"y":3260,"type":"absarc","radius":620,"startAngle":2.6179938779914944,"endAngle":3.9269908169872414,"Clockwise":false},{"x":-13700,"y":1200,"type":"nomal"},{"x":-13150,"y":1710,"type":"absarc","radius":700,"startAngle":4.363323129985823,"endAngle":5.93411945678072,"Clockwise":false},{"x":-12170,"y":2240,"type":"nomal"}],"holes":[]},"extrudeSettings":{"amount":400,"curveSegments":6,"steps":1,"bevelEnabled":false,"bevelThickness":1,"bevelSize":1,"bevelSegments":1,"extrudePathPoints":[]},"showSortNub":6,"customType1":"","customType2":"","animation":null,"dbclickEvents":null,"rotation":[{"direction":"x","degree":-1.5707963267948963},{"direction":"y","degree":0},{"direction":"z","degree":0}],"BindDevId":null,"BindDevName":null,"devInfo":null,"BindMeteId":null,"BindMeteName":null},{"show":true,"uuid":"","name":"build_f1","objType":"ExtrudeGeometry","position":{"x":7715.604,"y":30,"z":2309.159},"style":{"skinColor":16711680,"skin":{"skin_up":{"skinColor":1129349,"side":0,"opacity":0.8,"imgurl":"../img/3dImg/floor1.jpg","repeatx":true,"width":0.001,"repeaty":true,"height":0.001},"skin_down":{"skinColor":16711680,"side":1,"opacity":1},"skin_side":{"skinColor":16777215,"side":2,"opacity":0.8,"imgurl":"../img/3dImg/dl01.png","repeatx":true,"width":0.0001,"repeaty":true,"height":0.003}}},"scale":{"x":1,"y":1,"z":1},"shapeParm":{"points":[{"x":0,"y":0,"type":"nomal"},{"x":0,"y":5000,"type":"nomal"},{"x":-7500,"y":5000,"type":"nomal"},{"x":-7500,"y":4600,"type":"nomal"},peParm":{"points":[{"x":0,"y":0,"type":"nomal"},{"x":0,"y":100,"type":"nomal"},{"x":100,"y":100,"type":"nomal"},{"x":100,"y":2300,"type":"nomal"},{"x":-50,"y":2300,"type":"nomal"},{"x":-50,"y":2450,"type":"nomal"},{"x":-2500,"y":2450,"type":"nomal"},{"x":-2500,"y":2300,"type":"nomal"},{"x":-2650,"y":2300,"type":"nomal"},{"x":-2650,"y":100,"type":"nomal"},{"x":-2500,"y":100,"type":"nomal"},{"x":-2500,"y":0,"type":"nomal"}],"holes":[]},"extrudeSettings":{"amount":300,"curveSegments":6,"steps":1,"bevelEnabled":false,"bevelThickness":1,"bevelSize":1,"bevelSegments":1,"extrudePathPoints":[]},"showSortNub":5,"customType1":"","customType2":"","animation":null,"dbclickEvents":null,"rotation":[{"direction":"x","degree":-1.5707963267948963},{"direction":"y","degree":0},{"direction":"z","degree":0}],"BindDevId":null,"BindDevName":null,"devInfo":null,"BindMeteId":null,"BindMeteName":null},{"show":true,"uuid":"","name":"build_f5","objType":"ExtrudeGeometry","position":{"x":2117.824,"y":2080,"z":2309lickEvents":null,"rotation":[{"direction":"x","degree":-1.5707963267948963},{"direction":"y","degree":0},{"direction":"z","degree":0}],"BindDevId":null,"BindDevName":null,"devInfo":null,"BindMeteId":null,"BindMeteName":null},{"show":true,"uuid":"","name":"build_f13","objType":"ExtrudeGeometry","position":{"x":1557.594,"y":6080,"z":1780.258},"style":{"skinColor":16711680,"skin":{"skin_up":{"skinColor":1129349,"side":0,"opacity":0.8,"imgurl":"../img/3dImg/floor1.jpg","repeatx":true,"width":0.001,"repeaty":true,"height":0.001},"skin_down":{"skinColor":16711680,"side":1,"opacity":1},"skin_side":{"skinColor":16777215,"side":2,"opacity":0.8,"imgurl":"../img/3dImg/dl01.png","repeatx":true,"width":0.0001,"repeaty":true,"height":0.003}}},"scale":{"x":1,"y":1,"z":1},"shapeParm":{"points":[{"x":0,"y":1500,"type":"nomal"},{"x":-1500,"y":1500,"type":"nomal"},{"x":-1500,"y":0,"type":"nomal"},{"x":0,"y":0,"type":"nomal"}],"holes":[]},"extrudeSettings":{"amount":300,"curveSegments":6,"steps":1,"bevelEnabled":false,"bevelThickness":1,"bevelSize":1,"bevelSegments":1,"extrudePathPoints":[]},"showSortNub":5,"customType1":"","customType2":"","animation":null,"dbclickEvents":null,"rotation":[{"direction":"x","degree":-1.5707963267948963},{"direction":"y","degree":0},{"direction":"z","degree":0}],"BindDevId":null,"BindDevName":null,"devInfo":null,"BindMeteId":null,"BindMeteName":null}]
3.1.3、具体楼层房间模型
这部分模型主要是对楼层模型进行分隔,楼层外围可以复制,内部不同,这样我们既可以通过分开建模的方式,实现控制
模型代码如下:


[ { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_left": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_right": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" } } }, "showSortNub": 19, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "rotation": [{ "direction": "x", "degree": 0 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "thick": null, "scale": { "x": 1, "y": 1, "z": 1 }, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }, { "show": true, "uuid": "", "name": "br_f1_w_17", "objType": "cube2", "length": 900, "width": 15, "height": 300, "x": 889.653, "y": 136.966, "z": -315.791, "style": { "skinColor": 16777215, "skin": { "skin_up": { "skinColor": 50175, "side": 1, "opacity": 1 }, "skin_down": { "skinColor": 50175, "side": 1, "opacity": 1 }, "skin_fore": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_behind": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_left": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_right": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" } } }, "showSortNub": 19, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "rotation": [{ "direction": "x", "degree": 0 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "thick": null, "scale": { "x": 1, "y": 1, "z": 1 }, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteNa 1 }, " mgurl": "../img/3dImg/inside_lightmap.jpg" } } }, "showSortNub": 19, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "rotation": [{ "direction": "x", "degree": 0 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "thick": null, "scale": { "x": 1, "y": 1, "z": 1 }, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }, { "show": true, "uuid": "", "name": "br_f1_w_36", "objType": "cube2", "length": 700, "width": 15, "height": 300, "x": 5979.223, "y": 136.966, "z": -2274.46, "style": { "skinColor": 16777215, "skin": { "skin_up": { "skinColor": 50175, "side": 1, "opacity": 1 }, "skin_down": { "skinColor": 50175, "side": 1, "opacity": 1 }, "skin_fore": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_behind": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_left": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_right": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" } } }, "showSortNub": 19, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "rotation": [{ "direction": "x", "degree": 0 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "thick": null, "scale": { "x": 1, "y": 1, "z": 1 }, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }, { "show": true, "uuid": "", "name": "br_f1_w_37", "objType": "cube2", "length": 15, "width": 400, "height": 300, "x": 6328.26, "y": 136.966, "z": -2469.455, "style": { "skinColor": 16777215, "skin": { "skin_up": { "skinColor": 50175, "side": 1, "opacity": 1 }, "skin_down": { "skinColor": 50175, "side": 1, "opacity": 1 }, "skin_fore": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_behind": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_left": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.j egree": 0 }], "thick": null, "scale": { "x": 1, "y": 1, "z": 1 }, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }, { "name": "dev_f1_wsd_2OBJCREN1", "objType": "cylinder", "radiusTop": 16, "radiusBottom": 20, "height": 100, "segmentsX": 24, "segmentsY": 0, "openEnded": false, "position": { "x": -61.251, "y": 120.45, "z": 5.971 }, "scale": { "x": 1, "y": 1, "z": 1 }, "rotation": [{ "direction": "x", "degree": 0 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "style": { "skinColor": 16776960, "skin": { "skin_up": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_3.jpg" }, "skin_down": { "skinColor": 16777215, "side": 1, "opacity": 1 }, "skin_side": { "skinColor": 16777215, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_4.jpg", "repeatx": true, "width": 3, "repeaty": true, "height": 1 } } }, "showSortNub": 7, "show": true, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }, { "show": true, "uuid": "", "name": "dev_f1_wsd_2OBJCREN2", "objType": "cube2", "length": 210, "width": 20, "height": 160, "x": 0, "y": 0, "z": -61.333, "style": { "skinColor": 16777215, "skin": { "skin_up": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_3.jpg" }, "skin_down": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_3.jpg" }, "skin_fore": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_1.jpg" }, "skin_behind": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_1.jpg" }, "skin_left": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_1.jpg" }, "skin_right": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_1.jpg" } } }, "showSortNub": 6, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "rotation": [{ "direction": "x", "degree": 0 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "thick": null, "scale": { "x": 1, "y": 1, "z": 1 }, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }], "showSortNub": 43, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }]
3.2、逻辑代码
上面讲过模型建模时的注意事项,下面就是对分解好的模型进行应用。
3.2.1、视角切换
主要调用切换视角得方法WT3DObj.commonFunc.changeCameraPosition
$(".floorNub").click(function () {//2D页面按钮事件绑定
$(".floorNub").attr("class", "floorNub")
$(this).attr("class", "floorNub action");
var id= $(this).attr("id");
if(indexpage.btn_action){
layer.msg("动画执行中...");
return;
}
indexpage.btn_action = true;
switch (id) {
case "Btn_1"://视角一
{
WT3DObj.commonFunc.changeCameraPosition( {x: 9487.603167348385, y: 8719.775524425808, z: 10591.130126266144},{x: 4356.640551613654, y: 4840.572823023986, z: 3600.0637528600773}, 1000,
function () {
indexpage.btn_action = false;
});
}
break;}}
});
3.2.2、楼层分解
//出发切换楼层方法
case "Btn_5"://楼层一
{ modelBussiness.backToAllBuild(function () {
modelBussiness.showFloor(1);
setTimeout(function () {
indexpage.btn_action = false;
}, 1000);
});
}
break;
调用showFloor方法,方法具体如下
ModelBussiness.prototype.showFloor = function (floornub) { modelBussiness.currentState = "rooms";
WT3DObj.IsStepFirstBackSide = true;
//显示楼层
modelBussiness.clickFloorAnimation(floornub);
layer.closeAll();
}
这里主要调用clickFloorAnimation方法,并且记录当前状态
ModelBussiness.prototype.clickFloorAnimation = function (_floorNub) {
modelBussiness.loadFloorRooms(_floorNub);//加载楼层
modelBussiness.showFloorAnimation(_floorNub);//显示楼层
var floors = modelBussiness.InfloorBuildCache; var position = { y: 1}
new showSlowly(position).to({
y: 500,
}, 500).onUpdate(function () {
var _this = this;
$.each(floors, function (_i, _o) {
var _fnub = parseInt(_o.name.replace("build_f", ""));
if (_fnub > _floorNub) {
_o.position.y = _o.oldPositiony + (_fnub - _floorNub) * _this.y;
}
})
}).onComplete(function () {
var oobjs = [];
$.each(floors, function (_i, _o) {
var _fnub = parseInt(_o.name.replace("build_f", ""));
if (_fnub > _floorNub) {
oobjs.push(_o);
}
});
WT3DObj.commonFunc.changeObjsOpacity(oobjs, 1, 0.01, 1000, function () {
$.each(oobjs, function (_i, _o) {
_o.visible = false;
_o.position.y = 100000;
});
});
if(_floorNub<=3){
WT3DObj.commonFunc.changeCameraPosition({ x: 3873, y: 8547 + (_floorNub - 1) * 400, z: 5275 },
{ x: 3639, y: 3780 + (_floorNub - 1) * 400, z: 2556 }, 1000, function () { });
} else {
WT3DObj.commonFunc.changeCameraPosition({ x: 756.8552720903069, y: 4080 + (_floorNub - 1) * 400, z: 3005.0971402300224 }, { x: 778.609209478186, y: (_floorNub - 1) * 400, z: 1208.2712831508117 }, 1000,
function () {
});
}
var position = { y: 500 }
new showShowly(position).to({
y: 2000,
}, 1000).onUpdate(function () {
var _this = this;
$.each(floors, function (_i, _o) {
var _fnub = parseInt(_o.name.replace("build_f", ""));
if (_fnub > _floorNub) {
_o.position.y = _o.oldPositiony + (_fnub - _floorNub) * _this.y;
_o.step2Positiony = _o.oldPositiony + (_fnub - _floorNub) * _this.y;
}
});
}).onComplete(function () { }).start();
}).start();
}
按需加载得方法,对不同楼层 按需加载对应得模型
ModelBussiness.prototype.loadFloorRooms = function (nub, floor) {
var floorname = "build_f" + nub;
if (nub == 2) {
floorname += "_1";
}
var floor = WT3DObj.commonFunc.findObject(floorname);
if (modelBussiness.RoomModels["f" + nub]){
$.each(modelBussiness.RoomModels["f" + nub], function (_index, _obj) {
_obj.visible = true;
_obj.position.y = _obj.oldPositiony;
});
return;
}
if (nub >= 5) {
var models = getF5Rooms();
$.each(models, function (_index, _obj) {
_obj.name = _obj.name.replace("br_f4_", "br_f" + nub+"_");
if (_obj.name.indexOf("text") >= 0) {
_obj.position.y = floor.position.y + 550;
} else {
if (_obj.position) {
_obj.position.y = floor.position.y+500;
} else {
_obj.y = floor.position.y+150;
}
}
});
WT3DObj.commonFunc.loadModelsByJsons(models, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0 }, true, function () {
modelBussiness.RoomModels["f" + nub] = [];
$.each(WT3DObj.scene.children, function (_index, _obj) {
if (_obj.name.indexOf("br_f" + nub + "_w_") == 0 || _obj.name.indexOf("br_f" + nub + "_r_") == 0) {
_obj.oldPositiony = _obj.position.y;
modelBussiness.RoomModels["f" + nub].push(_obj);
};
});
});
} else {
var models = window["getF"+nub+"Rooms"]();
WT3DObj.commonFunc.loadModelsByJsons(models, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0 }, true, function () {
modelBussiness.RoomModels["f" + nub] = [];
$.each(WT3DObj.scene.children, function (_index, _obj) {
if (_obj.name.indexOf("br_f" + nub + "_w_") == 0 || _obj.name.indexOf("br_f" + nub + "_r_") == 0) {
_obj.oldPositiony = _obj.position.y;
modelBussiness.RoomModels["f" + nub].push(_obj);
}
});
});
}
}
楼层展开,虚化等动画统一展示方法:
ModelBussiness.prototype.showFloorAnimation = function (floornub) {
modelBussiness.hidemodelsCache = null;
modelBussiness.scaleModels = null;
var hidemodeNames = ["bout_f13_2", "bout_f13_1", "bout_f13_1", "bout_f13_0", "bout_flow2_1", "bout_flow2_2", "bout_flow2_3"];
for (var i = 1; i <= 12; i++) { hidemodeNames.push("build_out"+i);
}
var hidemodeModels = WT3DObj.commonFunc.findObjectsByNames(hidemodeNames);
$.each(hidemodeModels, function (_index, _obj) {
_obj.oldPositiony = _obj.position.y;
_obj.visible = false;
_obj.position.y = 200000;
});
var scaleModelNames = ["bout_39", "bout0_11", "bout_42", "bout_38", "bout_45", "bout_40", "bout_44", "bout_41", "bout_43"];
var scaleModels = WT3DObj.commonFunc.findObjectsByNames(scaleModelNames);
WT3DObj.commonFunc.changeObjsOpacity(scaleModels, 1, 0.01, 1000, function () {
$.each(scaleModels, function (_index, _obj) {
_obj.oldScaleX = _obj.scale.x;
_obj.oldScaleY = _obj.scale.y;
_obj.oldScaleZ = _obj.scale.z;
if (["bout_39", "bout_38", "bout_40", "bout_41"].indexOf(_obj.name) >= 0) {
_obj.scale.y = floornub / 14
}
if (["bout_42", "bout_45", "bout_44", "bout_43", "bout0_11"].indexOf(_obj.name) >= 0) {
_obj.scale.z = floornub / 14
}
if ("bout0_11" == _obj.name) {
_obj.scale.z = (floornub - 3) / 11
}
});
WT3DObj.commonFunc.changeObjsOpacity(scaleModels, 0.01, 1, 10, function () {
});
});
modelBussiness.hidemodelsCache = hidemodeModels;
modelBussiness.scaleModels = scaleModels; }
3.2.3、设备定位
定位具体设备,将楼层展开与主摄像机位置调整并用起来调用
modelBussiness.backToAllBuild(function () {
modelBussiness.showFloor(4);//展开楼层4
setTimeout(function () {
//调整摄像机位置
WT3DObj.commonFunc.changeCameraPosition({x: 853.7726152337735, y: 3002.9928530489865, z: 2579.4120334043137},{x: 1732.9469861751966, y: 1855.692424929085, z: 1402.3507946674324}, 1000,
function () {
indexpage.btn_action = false; });
}, 1000);
});
3.3、数据对接、展示
数据对接,主要是讲模型与设备数据id进行绑定,并且根据api进行调用
function W3DShowApi() { } //显示设备自定义框
W3DShowApi.prototype.showDevWin = function (modelname) {
console.log("显示楼层数字的自定义框");
//这里的showHtml可以自定义 var showHtml = "<div style='font-size:32px;color:white;text-align:center;line-height:90px;'>自定义内容:" + modelname + "</div > ";
//这里的显示框大小可以自定义
var area = ['auto', "100px"];//宽 高
return {
html: showHtml,
area: area
}
}
W3DShowApi.prototype.dbclickDevWin = function (modelname) {
console.log("显示楼层数字的自定义框");
//这里的showHtml可以自定义
layer.msg("显示双击设备自定义框:" + modelname);
} var w3DShowApi = new W3DShowApi();
我们这里弹窗使用了layerui的插件
ModelBussiness.prototype.showRoomMsg = function (_obj) {
var showWindow = false;
var showHtml = "<div></div>";
var area = ["350px", "200px"];
if (w3DShowApi) {
var wparam = w3DShowApi.showDevWin(_obj.name);
if (wparam) {
showHtml = wparam.html;
area = wparam.area;
showWindow = true;
}
}
if (!showWindow) {
return;
}
modelBussiness.hasshowRoomMessage = false;
modelBussiness.currentShowRoomText = _obj;
//获取位置
var position = {
x: _obj.position.x,
y: _obj.position.y,
z: _obj.position.z,
};
//position.y += 150;
var screenPostion = WT3DObj.transToScreenCoord(position);
$("#MarkMessageHelper").remove();
$("body").append("<div id='MarkMessageHelper' style='position:absolute;left:" + (screenPostion.x) + "px;top:" + screenPostion.y + "px;height:2px;width:2px;z-index:1000;'></div>");
layer.closeAll(); modelBussiness.currentShowRoomTipIndex = layer.tips(showHtml, '#MarkMessageHelper', {
closeBtn: 1,
shade: false,
shadeClose: true,
skin:"customskin",
area: area,
time: 0,//是否定时关闭,0表示不关闭
cancel: function (index, layero) {
modelBussiness.hasshowRoomMessage = false;
layer.close(index);
if (closeFunc) {
closeFunc();
}
},
success: function () {
setTimeout(function () {
modelBussiness.hasshowRoomMessage = true;
}, 150);
},
tips: [1, "rgba(0,0,0,0.1)"] //还可配置颜色
});
}
由于篇幅原因,这一课先介绍到这里
后面我将继续讲解用webgl 建立 3D隧道、3D桥梁、webgl实现三维隧道桥梁、three.js实现三维隧道桥梁、桥梁隧道三维应用炫酷效果等等
技术交流 1203193731@qq.com
交流微信:
如果你有什么要交流的心得 可邮件我或者微我
其它相关文章:
如何用three.js(webgl)搭建3D粮仓、3D仓库、3D物联网设备监控-第十二课
如何用webgl(three.js)搭建处理3D隧道、3D桥梁、3D物联网设备、3D高速公路、三维隧道桥梁设备监控-第十一课
如何用three.js实现数字孪生、3D工厂、3D工业园区、智慧制造、智慧工业、智慧工厂-第十课
使用webgl(three.js)创建3D机房,3D机房微模块详细介绍(升级版二)
如何用webgl(three.js)搭建一个3D库房-第一课
如何用webgl(three.js)搭建一个3D库房,3D密集架,3D档案室,-第二课
使用webgl(three.js)搭建一个3D建筑,3D消防模拟——第三课
使用webgl(three.js)搭建一个3D智慧园区、3D建筑,3D消防模拟,web版3D,bim管理系统——第四课
如何用webgl(three.js)搭建不规则建筑模型,客流量热力图模拟
使用webgl(three.js)搭建一个3D智慧园区、3D建筑,3D消防模拟,web版3D,bim管理系统——第四课(炫酷版一)
使用webgl(three.js)搭建3D智慧园区、3D大屏,3D楼宇,智慧灯杆三维展示,3D灯杆,web版3D,bim管理系统——第六课
如何用webgl(three.js)搭建处理3D园区、3D楼层、3D机房管线问题(机房升级版)-第九课(一)
使用three.js(webgl)搭建智慧楼宇、设备检测、数字孪生——第十三课的更多相关文章
- 基于 HTML5 WebGL 的智慧楼宇可视化系统
前言 可视化的智慧楼宇在 21 世纪是有急迫需求的,中国被世界称为"基建狂魔",全球高层建筑数量位居首位,所以对于楼宇的监控是必不可少.智慧楼宇可视化系统更多突出的是管理方面的功能 ...
- 基于 HTML5 WebGL 的智慧楼宇三维可视化监控
前言 可视化的智慧楼宇在 21 世纪是有急迫需求的,中国被世界称为"基建狂魔",全球高层建筑数量位居首位,所以对于楼宇的监控是必不可少.智慧楼宇可视化系统更多突出的是管理方面的功能 ...
- 物联网3D,物业基础设施3D运维,使用webgl(three.js)与物联网设备结合案例。搭建智慧楼宇,智慧园区,3D园区、3D物业设施,3D楼宇管理系统——第八课
写在前面的废话: 很久没有更新文章了,这段时间一直忙于项目落地,虽然很忙,但是感觉没有总结,没有提炼的日子,总是让人感觉飘飘忽忽的. 所幸放下一些事,抽出一些时间,把近期的项目做一些整理与记录.也算是 ...
- 如何用three.js(webgl)搭建3D粮仓、3D仓库、3D物联网设备监控-第十二课
序: 最近因为疫情,居家办公,索性翻翻之前的项目案例,总结总结. 这次疫情,深圳停摆,群众也挺恐慌的,封闭前一天,超市被抢购一空,虽然官方媒体一再强调,材米油盐蔬菜肉类管够,但是任然挡不住群众们的抢购 ...
- 基于 HTML5 WebGL 的 智慧楼宇能源监控系统
前言 21世纪,在能源危机和全球气候变暖的压力下,太阳能等可再生能源越来越受到关注,其中光伏建筑一体化逐渐成为绿色发展方式和生活方式,加强节能降耗,支持低碳产业和新能源.可再生能源发展,也已经成为国家 ...
- webgl智慧楼宇发光效果算法系列之高斯模糊
webgl智慧楼宇发光效果算法系列之高斯模糊 如果使用过PS之类的图像处理软件,相信对于模糊滤镜不会陌生,图像处理软件提供了众多的模糊算法.高斯模糊是其中的一种. 在我们的智慧楼宇的项目中,要求对楼宇 ...
- 基于 WebGL 的 HTML5 楼宇自控 3D 可视化监控
前言 智慧楼宇和人们的生活息息相关,楼宇智能化程度的提高,会极大程度的改善人们的生活品质,在当前工业互联网大背景下受到很大关注.目前智慧楼宇可视化监控的主要优点包括: 智慧化 -- 智慧楼宇是一个生态 ...
- H5 + WebGL 实现的楼宇自控 3D 可视化监控
前言 智慧楼宇和人们的生活息息相关,楼宇智能化程度的提高,会极大程度的改善人们的生活品质,在当前工业互联网大背景下受到很大关注.目前智慧楼宇可视化监控的主要优点包括: 智慧化 -- 智慧楼宇是一个生态 ...
- 如何用three.js实现数字孪生、3D工厂、3D工业园区、智慧制造、智慧工业、智慧工厂-第十课
文章前,先聊点啥吧. 最近元宇宙炒的挺火热,在所有人都争相定义元宇宙的时候,资本就开始着手入场了.当定义明确,全民皆懂之后,风口也就过去了. 前两天看到新闻,新世界CEO宣布购入最大的数字地块,这块虚 ...
随机推荐
- 白嫖Azure与体验GoLand远程开发
前言 近期因为有本地开发远程使用Linux编译部署的需求,而虚拟机的性能实在是不敢恭维,WSL的坑之前也踩过(没有systemd等),故考虑使用SSH连接云服务器开发. 目前VSCode提出了Remo ...
- 解决WIN7无法安装高版本Node.js问题
网上很多文章都让去安装低版本node 由于业务需求,低版本node npm 有一些包支持的不好 npm出cb() never call 本着更新npm 顺带弄个高版本的node 单独更新npm npm ...
- JAVA - 缓冲和缓存
JAVA - 缓冲和缓存 缓冲 Buffer 功能:协调上下层应用之间的性能差异.通过缓冲区的缓冲,当上层组件性能优于下层组件的时候,缓冲可以有效减少上层组件对下层组件的等待时间. 使用场景:IO流中 ...
- 【clickhouse专栏】clickhouse性能为何如此卓越
在<clickhouse专栏>上一篇文章中<数据库.数据仓库之间的区别与联系>,我们介绍了什么是数据库,什么是数据仓库,二者的区别联系.clickhouse的定位是" ...
- 16.Nginx优化与防盗链
Nginx优化与防盗链 目录 Nginx优化与防盗链 隐藏版本号 修改用户与组 缓存时间 日志切割 小知识 连接超时 更改进程数 配置网页压缩 配置防盗链 配置防盗链 隐藏版本号 可以使用 Fiddl ...
- 记一次ms17-010复现过程
最近碰到业务需要使用msf,以前了解过,后面都忘记了.这次干脆写下来,省的每次去找别人写的. 首先是使用nmap探测端口 nmap -O -sV 192.168.153.130 --script=vu ...
- MySQL-4-DDL
DDL:数据定义语言 创建create 创建库 语法:create database [if not exists]库名 # 创建库 CREATE DATABASE IF NOT EXISTS boo ...
- RPA 微信财务报销机器人 竹间智能
1.首先通过微信对话机器人收集报销信息及内容 2.上传发票并进行OCR识别 3.收集相关的出差信息,支持对话中修改内容 4.完成信息收集后,后台RPA机器人执行报销操作,并发送确认邮件 5.收到邮件后 ...
- CesiumJS 2022^ 源码解读[6] - 三维模型(ModelExperimental)新架构
目录 1. ModelExperimental 的缓存机制 1.1. 缓存池 ResourceCache 1.2. 缓存对象的键设计 ResourceCacheKey 2. 三维模型的加载与解析 2. ...
- 【Nim 游戏】 学习笔记
前言 没脑子选手随便一道博弈论都不会 -- 正文 Nim 游戏引入 这里给出最简单的 \(Nim\) 游戏的题目描述: \(Nim\) 游戏 有两个顶尖聪明的人在玩游戏,游戏规则是这样的: 有\(n\ ...