基于 HTML5 WebGL 的 3D 智慧隧道漫游巡检
前言
这次为大家展示的是通过 HT for Web 灵活的图型化编辑工具打造的智慧隧道监控系统。通过 HTML5 技术实现了桌面和移动端的跨平台性,同时现实了可视化运维。
这次主要跟大家分享里面的漫游巡检功能,完美进行第一人称视角体验整体结构环境,酷似游戏一样给人一种真实的感受,比平面更加直观,随意游离与虚拟和现实之间。
代码实现
整个场景是由 3D 组件搭建而成的,需要大量的代码,为了简化,我用 HT 封装的 ht.JSONSerializer 来将场景序列化为一个 json 文件。在代码中,再通过 DataModel 数据模型反序列化,就是将 json 格式转化为对象并添加到数据模型中。可参考序列化手册。
我已经搭建好了场景,但是其中包含重要的一点就是我们在构建过程中一定要制作一条线来作为路径基础,这个我们稍后用到。
首先我们先记录一下整体场景的初始视角,以便于我们在结束漫游后可以恢复视角:
var dm = new ht.DataModel(); var g3d = new ht.graph3d.Graph3dView(dm) var aEye = ht.Default.clone(g3d.getEye()) var aCenter = ht.Default.clone(g3d.getCenter())
为了避免在漫游的过程中在视角运动上出现 bug 我们先将交互器关掉。3D 交互器是什么呢?默认 Graph3dView 提供的是围绕 Graph3dView#getCenter() 中心点旋转的操作模式,这种模式下进行 Drag 操作时会改变 Graph3dView#getEye() 的眼睛观察点位置,鼠标滚轮或触屏 pinch 缩放的效果,实质上也是改变 eye 的位置,使其更接近或者远离 center 中心位置,最终达到视觉缩放或者走近和远离物体的效果。因为在进入漫游时不允许其它操作来干涉进行,所以要先处理掉:
g3d.setInteractors(null)
要移动,肯定要走我们在场景中画的隐藏的线来做路径:
var point1 = path.getPoints().toArray()[0] var point2 = path.getPoints().toArray()[3]
通过控制路径中前后两点来设置 3D 场景中的 eye 和 center,这样就能营造出第一人称视角效果:
var distanceX = (point1.x - point2.x) var distanceY = (point1.y - point2.y) // 两点之间的距离通过三角形勾股定理计算 var distance = Math.sqrt(distanceX * distanceX + distanceY * distanceY) // 眼睛的位置 g3d.setEye([point2.x, 800, point2.y]) // "我"的位置 g3d.setCenter([point1.x, 800, point1.y])
这里我们将用到一个 walk 方法,它能够同时改变 eye 和 center 的位置,也就是 eye 和 center 在两点建立的矢量方向上同时移动相同的偏移量。第一个参数为偏移的矢量长度值,结束时恢复交互器并清空动画:
var anim = g3d.walk(distance, { frames:700, finishFunc: function () { g3d.setEye(aEye) g3d.setCenter(aCenter) g3d.setInteractors([ mapInteractor ]) anim = null } }, true)
之前关闭交互器还有一个原因就是在漫游过程中我们还要有相关操作,先监听鼠标滚轮事件,通过滚动来改变速度,向上加速,向下减速:
g3d.getView().addEventListener('mousewheel', function (e) { if (anim) { let detail = 0 if (!e) e = g3d.getView().e if (e.wheelDelta) { detail = e.wheelDelta/120 } else if (e.detail) { detail = -e.detail/3 } if (detail) // 改变速度 if (detail < 0) { // 向下滚动 if (anim.frames < 2000) { anim.frames += 50 } } else { // 向上滚动 if (anim.frames > 100) { anim.frames -= 50 } } } })
再监听点击事件来实现暂停、继续和退出:
g3d.getView().addEventListener('mousedown', function (e) { if (anim) { if (e.button === 0) { // 左键暂停 anim.pause() }else if (e.button === 2){ // 右键继续 anim.resume() }else if(e.button === 1){ // 中键退出 anim.stop() anim = null } } })
至此,漫游功能的实现代码解释完毕,很短的代码量,却做出了这么大的工程!
总结
同样也有很多包含这个功能模块的例子,都有着不错的效果:
机房(http://www.hightopo.com/demo/room-walkthrough/index.html)
地铁站(http://www.hightopo.com/demo/ht-subway/index.html)等都是很好的
这些都是跟我们生活紧密相连的,都可以用信息化的方式来表达,HT 的轻量化与之相结合更好的展现出数据可视化的优势。随着时代的进步和前端 HTML5、WebGL、WebVR 等技术的成熟,相信 Web 承担越来越重度的渲染呈现应用是不可逆的趋势!