基于 HTML5 WebGL 的加油站 3D 可视化监控

2024-08-30 11:08

本文主要是介绍基于 HTML5 WebGL 的加油站 3D 可视化监控,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

随着数字化,工业互联网,物联网的发展,我国加油站正向有人值守,无人操作,远程控制的方向发展,传统的人工巡查方式逐渐转变为以自动化控制为主的在线监控方式,即采用数据采集与监控系统 SCADA。SCADA 系统的推广使用,大大提高了我国加油站的监控效率,本文所讲的则是通过对加油站的可视化建模,结合 HT 的 3D 可视化以及 2D 监控面板来实现对加油站的可视化监控。三维可视化监控系统是将三维的可视化技术和数据采集与监控技术融合,充分发挥了两种技术的核心优势,并通过数据库进行数据共享,共同构成一种全新的 SCADA 系统。该系统中也结合了海康的摄像头监控,通过调用海康提供的摄像头地址,实时的将视频流传输到前台,并且展示在 2d 页面上。在真实的系统中,每个加油机以及加油罐都有自己对应需要展示的数据,这个可以根据自己需要展示的内容来设计 2d 面板,之后根据后台传来的数据进行展示。数据采集与监控系统通过各类的传感器实时采集监控对象的各类数据,上传数据库并实时共享给三维可视化技术搭建的监控对象的三维可视化模型及场景,最后通过监控系统直观的展示出来,极大的提高了监控对象数据的表达能力和工作人员的工作效率。

该系统中实现了对加油机,油罐的监控,以及对加油站内的摄像头进行调取并显示,本文会讲解使用 HT 来搭建该系统的步骤,以及对场景中使用到的部分关键代码进行说明。

预览地址:基于 HTML5 WebGL 的加油站 3D 可视化监控 http://www.hightopo.com/demo/gas-station-demo/

界面效果预览

视频监控效果

加油机监控效果

油罐监控效果

加油站切换效果

因为系统中对许多的加油站进行建模,所以系统中可以根据 url 地址的 stationCode 来区分不同的加油站,即 stationCode 为该加油站的唯一标识,当然该系统可以嵌入到任何第三方的系统中,HT 只需要第三方页面给一个 dom,就可以将该页面放到该 dom 中,例如上图 3d 场景,ht 可以通过 g3d.addToDOM(el) 来将 3d 场景的 dom append 到 el 这个 dom 下,g3d 为 ht 中 ht.graph3d.Graph3dView 的实例,具体可查看 3D 手册

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 中的模型都是由三角面进行拼接而成的,所以指定该模型的所有三角面就可以构造出该模型,三角面又是由三个顶点信息构成,所以指定模型的顶点信息也可以构建模型,具体可以参考 建模手册

但是在我们这个加油站可视化监控系统中,我们的加油机模型以及油罐和加油站外景的模型都是十分复杂的模型,如果采用上述两种方法:

  1. 通过第一种简单的墙面,球体,六面体等模型拼接出加油站是不现实的,因为模型没有那么全面,而且贴图部分也不好分开贴,所以不可行。
  2. 通过指定顶点信息来构造加油站的所有模型,这部分虽然在理论上是可行的,但是计算顶点信息需要大量的工作,可想而知代码部分的工作量是不小的,所以不可行。

目前 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.对接数据

上一步中我们已经把需要展示的模型以及需要展示的监控数据进行了设计,并且在场景中进行了摆放,所以该步骤中则需要对数据进行对接,目前对接部分包括:

  1. 2d 面板两侧的数据对接
  2. 视频监控的对接

第一条的对接可以通过 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 种直观优化策略可以优化:

  1. 减少模型的面数
  2. 使用批量处理场景中大量的相同图元
  3. 对 3d 面板使用缓存
  4. 当场景视角距离较远时隐藏部分细节图元,或者当场景视角距离某个模型很近时,隐藏看不见的图元以提高性能

第一种情况可以在设计建模时通过各种减面的手段来减少模型的面数,这一部分优化的空间是最大的,也是效果最明显的。

第二种情况可以使用批量,批量能提高性能的原理在于,当图元一个个独立绘制模型时性能较差,而但一批图元聚合成一个大模型进行一次性的绘制时, 则会极大提高WebGL刷新性能,具体可参考 批量手册。

第三种情况使用 shape3d.image.cache 这个属性来开启面板的缓存,当我们一个场景中如果需要使用大量的类似公告板的功能,我们可以利用上面的属性对该节点设置缓存,具体使用方法可以参考 3D手册。

第四种情况我们可以在眼睛距离场景很远的时候隐藏部分细节图元,类似地图缩放到很小的时候,具体的城市会隐藏掉,放大到具体模型细节时,其它看不见的图元可以相应设置隐藏,这样可以提高不少的性能。

手机端效果

 

这篇关于基于 HTML5 WebGL 的加油站 3D 可视化监控的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1120644

相关文章

Python Dash框架在数据可视化仪表板中的应用与实践记录

《PythonDash框架在数据可视化仪表板中的应用与实践记录》Python的PlotlyDash库提供了一种简便且强大的方式来构建和展示互动式数据仪表板,本篇文章将深入探讨如何使用Dash设计一... 目录python Dash框架在数据可视化仪表板中的应用与实践1. 什么是Plotly Dash?1.1

Vue中组件之间传值的六种方式(完整版)

《Vue中组件之间传值的六种方式(完整版)》组件是vue.js最强大的功能之一,而组件实例的作用域是相互独立的,这就意味着不同组件之间的数据无法相互引用,针对不同的使用场景,如何选择行之有效的通信方式... 目录前言方法一、props/$emit1.父组件向子组件传值2.子组件向父组件传值(通过事件形式)方

css中的 vertical-align与line-height作用详解

《css中的vertical-align与line-height作用详解》:本文主要介绍了CSS中的`vertical-align`和`line-height`属性,包括它们的作用、适用元素、属性值、常见使用场景、常见问题及解决方案,详细内容请阅读本文,希望能对你有所帮助... 目录vertical-ali

浅析CSS 中z - index属性的作用及在什么情况下会失效

《浅析CSS中z-index属性的作用及在什么情况下会失效》z-index属性用于控制元素的堆叠顺序,值越大,元素越显示在上层,它需要元素具有定位属性(如relative、absolute、fi... 目录1. z-index 属性的作用2. z-index 失效的情况2.1 元素没有定位属性2.2 元素处

Python实现html转png的完美方案介绍

《Python实现html转png的完美方案介绍》这篇文章主要为大家详细介绍了如何使用Python实现html转png功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 1.增强稳定性与错误处理建议使用三层异常捕获结构:try: with sync_playwright(

Vue 调用摄像头扫描条码功能实现代码

《Vue调用摄像头扫描条码功能实现代码》本文介绍了如何使用Vue.js和jsQR库来实现调用摄像头并扫描条码的功能,通过安装依赖、获取摄像头视频流、解析条码等步骤,实现了从开始扫描到停止扫描的完整流... 目录实现步骤:代码实现1. 安装依赖2. vue 页面代码功能说明注意事项以下是一个基于 Vue.js

CSS @media print 使用详解

《CSS@mediaprint使用详解》:本文主要介绍了CSS中的打印媒体查询@mediaprint包括基本语法、常见使用场景和代码示例,如隐藏非必要元素、调整字体和颜色、处理链接的URL显示、分页控制、调整边距和背景等,还提供了测试方法和关键注意事项,并分享了进阶技巧,详细内容请阅读本文,希望能对你有所帮助...

使用Folium在Python中进行地图可视化的操作指南

《使用Folium在Python中进行地图可视化的操作指南》在数据分析和可视化领域,地图可视化是一项非常重要的技能,它能够帮助我们更直观地理解和展示地理空间数据,Folium是一个基于Python的地... 目录引言一、Folium简介与安装1. Folium简介2. 安装Folium二、基础使用1. 创建

基于Python开发PDF转PNG的可视化工具

《基于Python开发PDF转PNG的可视化工具》在数字文档处理领域,PDF到图像格式的转换是常见需求,本文介绍如何利用Python的PyMuPDF库和Tkinter框架开发一个带图形界面的PDF转P... 目录一、引言二、功能特性三、技术架构1. 技术栈组成2. 系统架构javascript设计3.效果图

Nginx实现前端灰度发布

《Nginx实现前端灰度发布》灰度发布是一种重要的策略,它允许我们在不影响所有用户的情况下,逐步推出新功能或更新,通过灰度发布,我们可以测试新版本的稳定性和性能,下面就来介绍一下前端灰度发布的使用,感... 目录前言一、基于权重的流量分配二、基于 Cookie 的分流三、基于请求头的分流四、基于请求参数的分