前言html
随着数字化,工业互联网,物联网的发展,我国加油站正向有人值守,无人操做,远程控制的方向发展,传统的人工巡查方式逐渐转变为以自动化控制为主的在线监控方式,即采用数据采集与监控系统 SCADA。SCADA 系统的推广使用,大大提升了我国加油站的监控效率,本文所讲的则是经过对加油站的可视化建模,结合 HT 的 3D 可视化以及 2D 监控面板来实现对加油站的可视化监控。三维可视化监控系统是将三维的可视化技术和数据采集与监控技术融合,充分发挥了两种技术的核心优点,并经过数据库进行数据共享,共同构成一种全新的 SCADA 系统。该系统中也结合了海康的摄像头监控,经过调用海康提供的摄像头地址,实时的将视频流传输到前台,而且展现在 2d 页面上。在真实的系统中,每一个加油机以及加油罐都有本身对应须要展现的数据,这个能够根据本身须要展现的内容来设计 2d 面板,以后根据后台传来的数据进行展现。数据采集与监控系统经过各种的传感器实时采集监控对象的各种数据,上传数据库并实时共享给三维可视化技术搭建的监控对象的三维可视化模型及场景,最后经过监控系统直观的展现出来,极大的提升了监控对象数据的表达能力和工做人员的工做效率。node
该系统中实现了对加油机,油罐的监控,以及对加油站内的摄像头进行调取并显示,本文会讲解使用 HT 来搭建该系统的步骤,以及对场景中使用到的部分关键代码进行说明。ajax
预览地址:基于 HTML5 WebGL 的加油站 3D 可视化监控 www.hightopo.com/demo/gas-st…数据库
界面效果预览api
视频监控效果缓存
加油机监控效果bash
油罐监控效果app
加油站切换效果dom
由于系统中对许多的加油站进行建模,因此系统中能够根据 url 地址的 stationCode 来区分不一样的加油站,即 stationCode 为该加油站的惟一标识,固然该系统能够嵌入到任何第三方的系统中,HT 只须要第三方页面给一个 dom,就能够将该页面放到该 dom 中,例如上图 3d 场景,ht 能够经过 g3d.addToDOM(el) 来将 3d 场景的 dom append 到 el 这个 dom 下,g3d 为 ht 中 ht.graph3d.Graph3dView 的实例,具体可查看 3D 手册socket
HT 搭建系统步骤
1.制做模型
在 ht 的 3D 场景中部分简单的建模能够根据 ht 的 api 来进行搭建,例如墙面,管道,六面体,地板等等基本 3d 模型,例如若是想制做一个三维的球体模型,则能够经过如下代码:
1 var node = new ht.Node();
2 node.s({
3 "shape3d": "sphere" // 此处指定该 node style 的 shape3d 为 sphere 即球体的意思
4 });复制代码
若是须要使用代码来进行较为复杂些的建模,则能够经过指定模型的顶点信息来进行搭建,大致可理解为 3d 中的模型都是由三角面进行拼接而成的,因此指定该模型的全部三角面就能够构造出该模型,三角面又是由三个顶点信息构成,因此指定模型的顶点信息也能够构建模型,具体能够参考 建模手册
可是在咱们这个加油站可视化监控系统中,咱们的加油机模型以及油罐和加油站外景的模型都是十分复杂的模型,若是采用上述两种方法:
目前 ht 能够支持 obj 模型的导入,因此设计师能够根据加油站拍摄的外景图片对加油站场景以及加油机,油罐等的模型进行建模,obj 模型可使用主流的 3dMAX 等的建模工具进行搭建,以后导入到 ht 中进行显示。对于系统中须要交互的模型则要分开进行建模,例如加油机模型不可和加油站场景的 obj 模型在同一个 obj 中,例以下图分开方式:
2.搭建场景
上一步中咱们已经获得了场景所须要的全部模型,在 ht 中能够经过 ht.Default.loadObj(objUrl, mtlUrl, params) 来加载 obj 的模型,以后经过 ht.Default.setShape3dModel(name, model) 来注册模型,loadObj 用来读取模型的顶点信息以及贴图部分的信息,就是上一步中所指的第二点经过顶点信息来构造模型,此时顶点信息已经由 obj 模型提供,因此拿到顶点信息,贴图等信息以后,能够经过 setShape3dModel 来注册模型,具体使用方法请参考 OBJ 手册,以后能够经过 ht 的 node 图元来使用该模型,具体使用方法以下:
1 var node = new ht.Node();
2 node.s({
3 "shape3d": name
4 });复制代码
上面的 name 就是经过 ht.Default.setShape3dModel(name, model) 中的 name 获得的,表示此图元使用该模型来展现。
构成该监控系统的还有用来展现加油机,油罐模型的具体监控参数的面板,ht 中全部的 2d 都为矢量,因此放大不会失真,2d 面板也是经过一个个图元进行摆放展现,经过调整每一个图元的样式来美化图元,具体的样式可参考 风格手册。
油罐 2d 面板展现以下:
3.对接数据
上一步中咱们已经把须要展现的模型以及须要展现的监控数据进行了设计,而且在场景中进行了摆放,因此该步骤中则须要对数据进行对接,目前对接部分包括:
第一条的对接能够经过 socket 或者 ajax 来进行,将后台数据传输到前台以后动态绑定到界面上显示便可,ht 中经过数据绑定来驱动界面上内容的动态刷新,具体的绑定操做能够查看 数据绑定手册。
系统中摄像头监控部分主要是经过将第三方的视频 dom 嵌入到 ht 的图纸中,ht 中能够经过 renderHTML 来嵌入 dom,嵌入 dom 的原理其实也是在图纸的对应位置加入一个 node 图元,根据图纸的缩放值(zoom),以及横向偏移值(tx),纵向偏移值(ty) 的图纸信息以及该图元的 position, width, height 的图元信息来动态的计算 dom 的宽高和 dom 的位置,具体代码能够参考以下:
1 let rect = node.getRect(), // 获取该 node 的包围矩形信息
2 zoom = graphView.getZoom(), // 获取图纸的缩放值
3 tx = graphView.tx(), // 获取图纸的横向偏移值
4 ty = graphView.ty(); // 获取图纸的纵向偏移值
5 // 下面操做为对 node 的包围矩形进行缩放
6 rect.x *= zoom;
7 rect.y *= zoom;
8 rect.width *= zoom;
9 rect.height *= zoom;
10
11 // div 的 left 即为下面的 x 坐标, top 即为下面的 y 坐标
12 let x = tx + rect.x;
13 let y = ty + rect.y;
14
15 div.style.position = 'absolute';
16 div.style.width = rect.width + 'px';
17 div.style.height = rect.height + 'px';
18 div.style.left = x + 'px';
19 div.style.top = y + 'px';复制代码
上面代码展现了动态摆放 dom 到 ht 图纸的原理,因此用户能够根据本身的需求将 dom 元素放到 2d 图纸中去,该系统中的监控模块 dom 就是经过该方式的原理进行动态摆放,从下图能够看出 dom 叠加的效果。
4.制做动画效果
该系统中动画效果比较简单,主要就是点击加油机或者油罐时,将视角飞向该物体,而且二维面板上显示对应的监控数据,视角的切换主要是修改 3D 场景的 eye 以及 center 的数据,可是 ht 中提供了更为方便的操做函数 flyTo,因此主要代码即为下面一行:
1 // node 即为要飞向的节点 例如加油机
2 // 第二参数为配置参数
3 g3d.flyTo(node, { animation: true, direction: [-16, 6, 8], distance: 600 });复制代码
上述第二个参数具体可参考上述所提供的 3D 手册,direction:默认undefined,眼睛处于目标的方向(相对目标,受到目标自身旋转影响,distance :默认undefined(未定义的话则使用下面的ratio模式计算距离),浮点类型,表示眼睛跟中心的固定距离,上述所用到的两个参数解释即为此。
该函数还有一个使用方法为当第一参数传值为 null 空时,视角会调整看向场景内全部节点,因此利用此功能可能看到加油站的全景。
系统中还有一个效果是虚化背景,虚化背景的原理就是修改场景中全部模型的透明度,例如该系统中经过遍历全部节点,将当前节点的透明度设置为 0.1,则在视觉上咱们看到的场景即为虚化的场景,具体节点的样式属性能够参考上面已经给出的风格手册,关键代码以下:
1 // 遍历场景中全部图元
2 dataModel.each((d) = >{
3 // opacityMap 用来记录当前某个节点没有虚化以前的透明度值
4 if (!opacityMap[d.getId()]) {
5 opacityMap[d.getId()] = {
6 'shape3d.opacity': d.s('shape3d.opacity'),
7 'shape3d.transparent': d.s('shape3d.transparent'),
8 'all.opacity': d.s('all.opacity'),
9 'all.transparent': d.s('all.transparent'),
10 'left.opacity': d.s('left.opacity'),
11 'left.transparent': d.s('left.transparent'),
12 'right.opacity': d.s('right.opacity'),
13 'right.transparent': d.s('right.transparent'),
14 'front.opacity': d.s('front.opacity'),
15 'front.transparent': d.s('front.transparent'),
16 'back.opacity': d.s('back.opacity'),
17 'back.transparent': d.s('back.transparent'),
18 'top.opacity': d.s('top.opacity'),
19 'top.transparent': d.s('top.transparent'),
20 'bottom.opacity': d.s('bottom.opacity'),
21 'bottom.transparent': d.s('bottom.transparent'),
22 '3d.selectable': d.s('3d.selectable')
23 };
24 }
25 // 设置当前节点的透明度 opacity 为须要虚化至多大透明度 系统中为 0.1
26 d.s({
27 'shape3d.opacity': opacity,
28 'shape3d.transparent': true,
29 'all.opacity': opacity,
30 'all.transparent': true,
31 'left.opacity': opacity,
32 'left.transparent': true,
33 'right.opacity': opacity,
34 'right.transparent': true,
35 'front.opacity': opacity,
36 'front.transparent': true,
37 'back.opacity': opacity,
38 'back.transparent': true,
39 'top.opacity': opacity,
40 'top.transparent': true,
41 'bottom.opacity': opacity,
42 'bottom.transparent': true,
43 '3d.selectable': false
44 });
45 });复制代码
上面代码执行以后场景中全部的节点就被虚化,由于每一个节点虚化所须要设置的透明度属性不一样,因此一共有上面十几种样式属性须要判断设置,具体的样式名称能够参考上文提出的风格手册,如下为虚化效果:
场景中有双击便利店进入便利店内景的操做,具体交互以及效果以下图:
5.优化场景
当 3d 场景中点或者面的数量较多时,3d 面板,公告板部分较多时,ht 中有几种优化策略能够进行优化,咱们知道 3d 场景中的全部模型都是由三角面构成的,而三角面又是由三个顶点构成的,因此若是场景中的点或者面比较多的时候场景会出现必定的卡顿,GPU 渲染会比较费时,在 ht 中能够经过在控制台输入 g3d.showDebugTip() 来显示当前场景一共有多少面和顶点,具体效果以下:
其中 Vertices 为点的数量,Faces 为面的数量。
因此在 ht 中能够有如下 4 种直观优化策略能够优化:
第一种状况能够在设计建模时经过各类减面的手段来减小模型的面数,这一部分优化的空间是最大的,也是效果最明显的。
第二种状况可使用批量,批量能提升性能的原理在于,当图元一个个独立绘制模型时性能较差,而但一批图元聚合成一个大模型进行一次性的绘制时, 则会极大提升WebGL刷新性能,具体可参考 批量手册。
第三种状况使用 shape3d.image.cache 这个属性来开启面板的缓存,当咱们一个场景中若是须要使用大量的相似公告板的功能,咱们能够利用上面的属性对该节点设置缓存,具体使用方法能够参考 3D手册。
第四种状况咱们能够在眼睛距离场景很远的时候隐藏部分细节图元,相似地图缩放到很小的时候,具体的城市会隐藏掉,放大到具体模型细节时,其它看不见的图元能够相应设置隐藏,这样能够提升很多的性能。
手机端效果