基于 HTML5 的 WebGL 3D 地铁站可视化系统

2024-08-30 11:18

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

前言

工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCADA 的前端技术来实现 2D 可视化监控,本系统采用 Hightopo 的 HT for Web 产品来构造轻量化的 3D 可视化场景,该 3D 场景从正面展示了一个地铁站的现实场景,包括地铁的实时运行情况,地铁上下行情况,视频监控,烟雾报警,电梯运行情况等等,帮助我们直观的了解当前的地铁站。

系统中为了帮助用户更直观友好的浏览当前地铁站,提供了三种交互模式:

  • 第一人称模式 – 操作就类似行人或车在行进的效果,可以通过键盘鼠标控制前进后退。
  • 自动巡检模式 – 该模式下用户不需要任何操作,场景自动前进后退来巡查当前地铁站的场景。
  • 鼠标操作模式 – 左键旋转场景,右键平移场景。

本篇文章通过对地铁站可视化场景的搭建,动画代码的实现,交互模式的原理解析,以及主要功能点的实现进行阐述,帮助我们了解如何使用 HT 实现一个简单的地铁站可视化。

预览地址:基于 HTML5 WebGL 的地铁站 3D 可视化系统 http://www.hightopo.com/demo/ht-subway/

界面简介及效果预览

地铁运行效果

在这里插入图片描述
地铁从站外开到站内的效果为透明度逐渐增加,速度逐渐降低。

漫游效果

在这里插入图片描述
上述为自动巡检的漫游效果,场景自动进行前进旋转。

监控设备交互效果

在这里插入图片描述
当我们点击场景中的监控设备时可以查看当前设备的运行情况,运行数据等信息。

场景搭建

该系统中的大部分模型都是通过 3dMax 建模生成的,该建模工具可以导出 obj 与 mtl 文件,在 HT 中可以通过解析 obj 与 mtl 文件来生成 3d 场景中的所有复杂模型,当然如果是某些简单的模型可以直接使用 HT 来绘制,这样会比 obj 模型更轻量化,所以大部分简单的模型都是采用 HT for Web 产品轻量化 HTML5/WebGL 建模的方案,具体的解析代码如下:

// 分别为 obj 文件地址,mtl 文件地址
ht.Default.loadObj('obj/metro.obj', 'obj/metro.mtl', {center: true,// 模型是否居中,默认为 false,设置为 true 则会移动模型位置使其内容居中r3: [0, -Math.PI / 2, 0],// 旋转变化参数,格式为 [rx, ry, rz]s3: [0.15, 0.15, 0.15],// 大小变化参数,格式为 [sx, sy, sz]finishFunc: function(modelMap, array, rawS3) {if (modelMap) {ht.Default.setShape3dModel('metro', array); // 注册一个名字为 metro 的模型}}
});

上面通过加载 obj 模型之后注册了一个名字为 metro 的模型,之后如果要使用该模型可以通过以下代码来实现:

var node = new ht.Node();
node.s({'shape3d': 'metro'
});

上面代码新建了一个 node 对象,通过设置 style 对象的 shape3d 属性可以把模型名称为 metro 用到该 node 对象上去,之后便是我们场景中看到的地铁列车模型。

动画代码分析

地铁动画代码的实现分析

场景中地铁的运行是通过 HT 提供的调度插件来实现,调度的具体用法可以参考 HT for Web 的调度手册,该调度主要用于在指定的时间间隔进行函数回调处理,回调函数的第一个参数为 data 图元,也就是 3D 场景中的模型节点,我们可以判断当前 data 是否为我们刚才创建的 metro 那个节点来进行后续的操作,场景中模拟了一个左开的地铁和一个右开的地铁,两辆地铁会交替出现。在 3D 场景中肯定会有坐标系,HT 中是用 x, y, z 来分别表示三个轴,所以地铁的运动肯定是改变地铁在坐标系中的位置来实现地铁的运行,地铁坐标如下图所示:
在这里插入图片描述
通过上图可以知道地铁在 3D 场景中的坐标系,如果要实现地铁的移动则只需要将地铁往图中所示红色箭头的方向进行移动,即 x 轴的方向,通过 setX 这个方法不断的修改地铁的位置达到地铁行进的目的,代码中通过 getSpeedByX 以及 getOpacityByX 两个方法来不断获取此时的列车速度以及列车透明度,以下为关键代码实现:

let metroTask = {interval: 50,// 每五十秒执行一次action: (data) = >{ // 即上文所提回调函数// 判断当时传进来的节点是否为地铁列车节点if (data === currentMetro) {// 获取地铁此时的 X 轴位置以及行进的方向let currentX = data.getX(),direction = data.a('direction');// 根据当前的 X 轴位置获取当前的列车速度let speed = this.getSpeedByX(currentX);// 根据当前的 X 轴位置获取当前的列车透明度let opacity = this.getOpacityByX(currentX);// 判断此时 X 轴位置是否超过某个值 即地铁是在某个范围内移动if (Math.abs(currentX) <= 5000) {// 设置当前的透明度opacity !== 1 ? currentMetro.s({'shape3d.transparent': true,'shape3d.opacity': opacity}) : currentMetro.s({'shape3d.transparent': false});// 设置当前的 X 轴位置data.setX(currentX + direction * speed);// 判断此时地铁的速度为 0,所以此时应该执行开门的动画if (speed === 0) this.doorAnimation(currentMetro, direction);}// 右方向地铁开到头,进行复位if (currentX > 5000 && direction === 1) {currentMetro = leftMetro;currentMetro.setX(5000);}// 左方向地铁开到头,进行复位if (currentX < -5000 && direction === -1) {currentMetro = rightMetro;currentMetro.setX( - 5000);}}}
};
dm3d.addScheduleTask(metroTask);

通过以上代码可以知道地铁在运行的过程中,主要通过修改地铁的 x 轴位置来产生前进的动画,并且需要让地铁在某个区间内进行运动,需要判断边界,而且为了模拟出真实的效果需要根据地铁当前的位置不断获取当前的列车速度以及列车透明度,以下为流程图:
在这里插入图片描述
上图所示的为地铁进站时候的流程,当地铁停靠完毕关门后需要进行出站,此时我们只需要把地铁位置重新设置一下不为 0 即可,以下为部分代码实现:

currentMetro.setX(direction * 10); // 设置出站列车的位置

当执行上面那句代码之后上方的 metroTask 调度任务执行到 getSpeedByX 这个方法之后获取到的 speed 速度不为 0,因此此时会继续执行地铁行进的动画,此时的速度就是由慢至快,透明度由深至浅。以下为开门动画执行流程:
在这里插入图片描述

自动巡检代码的实现分析

系统中自动巡检的实现主要是通过修改 3D 场景中的 eye 以及 center 的值,HT 中提供了 rotatewalk 两个方法来控制视角的旋转以及视角的行进,rotate 方法在非第一人称模式时,旋转是以 center 为中心进行旋转,也就是围绕中心物体旋转,当为第一人称时旋转以 eye 为中心进行旋转,也就是旋转眼睛朝向方向。walk 函数同时改变 eyecenter 的位置,也就是 eyecenter 在两点建立的矢量方向上同时移动相同的偏移量。该系统中我没有采用 rotate 函数而是自己实现了视角的旋转,因为原本的 rotate 函数旋转某个角度会马上旋转过去而不会有一个旋转的过程,所以我重新实现了旋转的方法,该系统中视角旋转是通过不断修改 center 的数值来实现,具体实现过程原理如下图所示:
在这里插入图片描述
部分实现代码如下:

rotateStep() {// 即上图辅助点 Clet fromCenter = this.fromCenter;// 即上图 B 点let toCenter = this.toCenter;// 每帧转一度let rotateValue = this.rotateFrame || Math.PI / 180;// 辅助点 C 与 B 点之间建立一个方向向量let centerVector = new ht.Math.Vector2(toCenter.x - fromCenter.x, toCenter.y - fromCenter.y);let centerVectorLength = centerVector.length();// 此时旋转百分比let rotatePercent = rotateValue * this.stepNum / this.curRotateVal;if (rotatePercent >= 1) {rotatePercent = 1;this.stepNum = -2;}let newLength = rotatePercent * centerVectorLength;centerVector.setLength(newLength);let newCenterVector = centerVector.add(fromCenter);// 获取旋转过程中 center 的点信息let newCenterPosition = [newCenterVector.x, this.personHeight, newCenterVector.y];// 设置当前 center 的大小this.g3d.setCenter(newCenterPosition);
}

通过上述代码就实现了场景中的视角旋转,并且可以通过修改 rotateValue 的值控制旋转的速度。

电梯动画代码的实现分析

场景中电梯是一个 obj 模型,3D 模型是由最基础的三角形面拼接合成,例如 1 个矩形可以由 2 个三角形构成,1 个立方体由 6 个面即 12 个三角形构成,以此类推更复杂的模型可以由许多的小三角形组合合成。因此 3D 模型定义即为对构造模型的所有三角形的描述,而每个三角形由三个顶点 vertex 构成,每个顶点 vertex 由 x, y, z 三维空间坐标决定,HT 中使用 vs 数组记录构成三角面的所有顶点坐标,所以如果想要让电梯运行起来,只需要把所有的顶点坐标往电梯运行的方向进行平移,以下为部分关键伪代码:

// vs 指的是构成电梯模型所有的三角面顶点坐标数组
// 由于场景中电梯的运行方向为往对角线右上方运动,所以只需要修改 x 轴以及 y 轴坐标值
// xStep yStep 为每次电梯运动的距离
setInterval(() = >{// i+3 是因为 vs 数组的顺序为 x, y, z 轴 所以每次 i 偏移三个单位大小for (let i = 0, l = vs.length; i < l; i = i + 3) {// 该顶点坐标下一个 x 轴坐标的值let nextX = vs[i] - xStep;// 该顶点坐标下一个 y 轴坐标的值let nextY = vs[i + 1] + yStep;vs[i] = nextX < -0.5 ? 0.5 - (Math.abs(nextX) - 0.5) : nextX;vs[i + 1] = nextY > 0.5 ? -0.5 + (Math.abs(nextY) - 0.5) : nextY;}
},
200);

电梯运动动画如下图所示:
在这里插入图片描述

监控功能展示及介绍

视频监控

当点击场景中的摄像头之后右侧顶部会显示出当前摄像头的监控画面,以下为实现效果图:在这里插入图片描述

烟雾报警监控

烟雾报警会根据后台实时传递过来的状态值来变换当前烟雾报警模型的颜色,红色为报警状态,以下为实现效果图:
在这里插入图片描述

电视列车到站时间监控

日常地铁站中会有专门的电视来展示下一班地铁到站的时间表,该系统中也模拟该效果,不过该系统暂时做了电视的模型,时间暂无对接,以下为效果图:在这里插入图片描述

场景监控交互

3D 场景中交互是比较简单的,主要是点击摄像头展示 2D 监控面板,在 2D 界面中主要是切换三种交互模式,三种交互模式为互斥的关系,以下是 3D 交互注册事件代码:

g3d.mi((e) = >{let {g2d,dm2d} = this;// 为点击类型if (e.kind === 'clickData') {// data 为当前点击的图元let data = e.data;// 当前图元的 shape3d 类型let shape3d = data.s('shape3d');// 判断当前 shape3d 类型是否为摄像头if (shape3d && shape3d.indexOf('摄像头') > 0) {let cameraPanel = dm2d.getDataByTag('cameraPanel');// toggle 切换摄像头 2d 面板g2d.isVisible(cameraPanel) ? cameraPanel.s('2d.visible', false) : cameraPanel.s('2d.visible', true);}}// 为点击 3d 场景背景类型if (e.kind === 'clickBackground') {let cameraPanel = dm2d.getDataByTag('cameraPanel');// 隐藏摄像头 2d 面板g2d.isVisible(cameraPanel) && cameraPanel.s('2d.visible', false);}
});

总结

工业互联网将人,数据和机器连接起来,地铁站 3D 可视化系统则是一个很好的展现,HT 的轻量化,数据的可视化,机器的可视化,资产的管理化帮助我们更好的监控。而物联网将通过各种信息传感设备,实时采集任何需要监控、连接、互动的物体或过程等各种需要的信息,通过与 HT 的结合更好的展现出可视化的优势,当然地铁站还可以与 VR 进行结合,在各地科技展会中我们可以见到各种 VR 场景操作,HT 中也可以结合 VR 设备进行操作,可以戴上设备在地铁站中漫游,让人有身临其境的感觉,由于场景本身的轻量化,所以 VR 场景下的流畅性也是十分的高,让用户不会有头晕的感觉。当然系统本身也可以在移动端运行,以下为移动端运行截图:
在这里插入图片描述
程序运行截图:在这里插入图片描述在这里插入图片描述

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



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

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

无人叉车3d激光slam多房间建图定位异常处理方案-墙体画线地图切分方案

墙体画线地图切分方案 针对问题:墙体两侧特征混淆误匹配,导致建图和定位偏差,表现为过门跳变、外月台走歪等 ·解决思路:预期的根治方案IGICP需要较长时间完成上线,先使用切分地图的工程化方案,即墙体两侧切分为不同地图,在某一侧只使用该侧地图进行定位 方案思路 切分原理:切分地图基于关键帧位置,而非点云。 理论基础:光照是直线的,一帧点云必定只能照射到墙的一侧,无法同时照到两侧实践考虑:关

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听