基于 H5和 3D WebVR 的可视化虚拟现实培训系统

前言

2019 年 VR, AR, XR, 5G, 工业互联网等名词频繁出如今咱们的视野中,信息的分享与虚实的结合已经成为大势所趋,5G 是新一代信息通讯技术升级的重要方向,工业互联网是制造业转型升级的发展趋势。本文所讲的 VR 是机械制造业与设备的又一次交流,当技术新星赶上制造潮流,无疑将成为制造业,工控业等行业数字化转型的重要驱动力。“5G + VR + 工业互联网”必将成为新的一年不变的话题,如何将当前工业中遇到的问题经过虚拟现实结合起来,让咱们能够更近的去交流,去感觉技术带给咱们的变化。在今年苹果的发布会上,相信你们都知道苹果的 5G 手机没有问世,说明 5G 的应用和发展还处在快速发展的阶段,可是手机结合 AR 功能的 APP 已经早就问世,5G 的速度加上 AR, VR 的身临其境,让咱们感觉到的不只仅是技术的革新,更是让咱们感觉到技术在不一样领域的实际应用场景,我相信 2020 年新的一年一定是 “5G + VR + 工业互联网” 应用的又一个新的开始,本文接下来所讲的就是 HT for Web 结合 WebVR 开发的具体应用案例。javascript

系统预览

预览地址:基于 HTML5 WebGL 与 WebVR 3D 虚拟现实的可视化培训系统 http://www.hightopo.com/demo/...html

VR 拆解还原

VR 拆解还原.gif

VR 操做

vr操做.gif

VR 场景切换

VR 场景切换.gif

PC 端拆解还原

PC 端拆解还原.gif

PC 端考试

PC 端考试.gif

系统介绍

该系统共分为三个实际应用层面:java

  • 三维培训: 用户经过 mb 端手指触摸或者 pc 端鼠标拖拽能够将设备拆解开来,以后能够经过一键还原来将设备还原到最初的状态,或者能够经过拆解 or 还原按钮查看设备自动拆解的过程以及拆解以后自动还原的过程。
  • 考试系统: 这部分是考验你对设备拆解的熟悉程度,在第一步的三维培训以后,能够在该系统中考核你对拆解过程的了解。
  • VR 模式: 该部分即是三维场景结合 WebVR 的具体实现应用,在进入 VR 以后能够经过操做 VR 手柄,进行设备的拆解还原。

文章主要讲解第三部分的 VR 模式,让咱们了解如何结合 HT 来搭建 VR 场景。下面描述了 VR 中的主要操做,没有进入 VR 的时候不会出现以下所说的六个按钮操做,在点击进入 WebVR 时,系统自动显示出 VR 场景里的六个操做按钮,反之退出 VR 时,系统也会自动隐藏三维中的六个操做按钮,VR 中的主要操做以下:node

  • 设备切换: 顾名思义,能够经过手柄射线对准场景中左侧列表,按动板机进行场景设备切换。
  • 操做切换: VR 中对设备有以下两种操做,能够经过右下角的模式按钮点击切换。git

    • 平移模式: 该模式下,用户能够对准设备而且按动板机将设备从一个位置移动到另外一个位置,而且能够经过触摸触摸板来拉近和拉远设备零件。
    • 抓取模式: 该模式下,用户能够对准设备而且按动板机将设备抓取过来,抓取过来以后,能够经过触摸触摸板来旋转以及放大或者缩小零件。
  • 一键还原: 将设备各部分零件还原到最初始的位置。
  • 拆解动画: 将设备的各部分零件经过以前预约好的位置按步骤一步一步拆解开来。
  • 还原动画: 该操做能够理解为拆解动画的倒放,即将拆解的过程逆序还原。
  • 线框切换: HT 支持将设备节点的三角面表示出来,能够具体的看到该设备的线框轮廓。

系统开发

三维场景

HT 支持 obj 模型的导入,VR 场景所出现的设备零件均为 obj 模型,因为须要在以后进行设备的拆解,因此建模的时候须要分别对设备的各部分零件进行建模,而不是对设备总体进行建模,若是对设备总体建模那么在 HT 的场景中就是一个 Data 节点,从而不能对零件进行拆解,若是拆解开来,那么在 HT 中能够加载多个 obj 则就有多个 Data 节点,有多个零件的 Data 节点以后就能够对设备零件进行移动或者其它旋转操做,具体的 Data 在 HT 的含义能够参考 HT for Web 数据模型手册github

以下为导入场景中的 obj 模型:web

导入场景中的obj模型.png

从上图能够看出咱们导入 obj 以后零件之间是分散的,因此须要对零件的初始位置进行调整,从而调整出一个由许多零件构成的完整设备,固然调整不可能经过代码来调整,对应的有三维编辑器能够调整,进行拖拖拽拽将不一样零件拼凑起来,以下为组合以后的设备总体:json

组合以后的设备总体.png

VR 搭建

VR 场景的搭建是在第一步的基础上进行搭建,上面所说的只在 VR 场景中显示的按钮也是在场景中进行搭建,在正常的场景时候咱们能够隐藏掉对应的节点,node.s('3d.visible', false) 上面的代码就是 HT 中在三维下面隐藏三维节点的代码,由于进入 VR 和离开 VR 的时候,HT 内部会派发出对应的状态告诉用户此时已经进入 VR 或者此时已经离开 VR,相应伪代码以下:浏览器

// graph3dView 为 HT 中的三维场景视图容器
 // vr 获取挂载在 graph3dView 上的 vr 对象
var vr = graph3dView.vr;
vr.mp(function (e) {
     // property 对应的 vr 事件类型,detail 此时事件的状态
    var property = e.property;
    var detail = e.newValue;
     // present 表明此时进入或者离开 VR 场景
    if (property === 'present') {
          // 此时 detail 为 true 表示进入 vr,false 表示离开 vr
        if (detail) {
            // 执行显示 vr 场景中须要显示的节点操做
        }
        else {
            // 执行隐藏 vr 场景中须要隐藏的节点操做
        }
    }
});

上面 property 在 HT 总共会派发出如下几种类型,主要是包括 VR 的状态和手柄的操做类型:安全

  • enable: vr 的 enable 信息发生变化
  • present: vr 的 present 信息发生变化,代表进出 vr 世界
  • gamepad.pose: 手柄位置或旋转发生变更,参数 id,position,rotation
  • gamepad.axes: 手柄中间的转盘触摸点位变更,参数 id,axes;其中 axes 格式形如:[ 0.2, 0.7 ],分辨表示横纵百分比
  • gamepad.button.thumbpad: thumbpad 按键被按下,参数 id,state,其中 state 包含 down 跟 up 两种
  • gamepad.button.trigger: trigger 按键被按下,参数 id,state,其中 state 包含 down 跟 up 两种
  • gamepad.button.grips: grips 按键被按下,参数 id,state,其中 state 包含 down 跟 up 两种
  • gamepad.button.menu: menu 按键被按下,参数 id,state,其中 state 包含 down 跟 up 两种

VR 中有一个关键的配置就是比例尺,由于 VR 里面的单位是和现实中的长度单位是一致的,咱们戴着头盔往前走 1m 那么对应在 HT 三维场景中须要往前走多远这须要一个对应关系,HT 提供的 VR 插件中会提供一个 measureOflength 的配置项,以下:

var vr_config = {
    measureOflength: 0.01,
}

上面 0.01 表明的意思就是 HT 场景中的单位长度 1 表明现实场景的 0.01 米,因此若是此时现实场景你戴着头盔往前移动 1m,那么 HT 中对应的视角会往前移动 100 个单位,因此若是须要搭建 VR 场景要注意场景的模型建模比例和现实世界是相差多少,按照统一的比例来建模,否则在 VR 场景中会出现设备大小不一的问题,致使出现错觉,以下对比图,左侧是 0.01 的比例,射线的小点很小,右侧是是 0.001 的比例致使射线的小点变大。

vr视觉.png

HT 中已经对浏览器提供的 WebVR 相关接口的 API 进行了封装,包括获取设备 navigator.getVRDisplays() 这是进入 VR 世界的第一步,若是此时执行此代码返回的结果为空表明获取 VR 设备失败,那么以后更不用说了,以及获取手柄信息 navigator.getGamepads(),用户能够经过在浏览器控制台敲入上面两行代码,查看浏览器是否已经获取到了 VR 设备信息和 VR 手柄信息,若是返回为空则说明获取失败。HT 只要经过执行 graph3dView.vr.enable = true 就能够开启 VR,固然用户不用执行该代码,HT 提供的 VR 插件也会提供对应的配置项 vrEnable: true 来表明开启 VR,对应的配置也挂在在上面的 vr_config 对象内,以下:

var vr_config = {
    measureOflength: 0.01,
    vrEnable: true, // 表明开启 VR
}

在该展现的系统中有直接在 VR 中切换场景的功能,因为每一个场景的 vr_config 中的配置项值可能会有差异,例如第一个场景的 measureOflength 比例尺的大小为 0.01,可能第二个场景的比例尺大小 measureOflength 就变成了 0.02,因此 VR 插件提供一个销毁的功能,用来销毁上一个场景的资源,销毁场景的资源包括清空上一个场景的全部节点,因此在加载新的场景时,不须要再执行清空场景节点的操做,即不须要执行 dataModel.clear(),由于 VR 提供的销毁功能已经都清空了,手柄和射线都是场景中的一个 Data 节点,因此在新的场景不须要额外的清除手柄和射线这两个节点,故插件帮你管理场景的节点。在调用销毁功能以后,能够调用 graph3dView 的序列化函数 graph3dView.deserialize('场景资源json地址') 来序列化新的场景 json 文件,在序列化完成的回调函数中,能够根据新的场景修改此时 vr_config 的值,而后再次调用 graph3dView.initVRForScene() 来再次初始化 VR 场景。相关的步骤伪代码以下:

// window.GVR 是在调用 graph3dView.initVRForScene() 以后初始化的一个全局 VR 插件变量 用于用户获取插件对象
window.GVR.destory();
 // 执行新的场景序列化操做
graph3dView.deserialize('场景资源json地址', function (json, dm, g3d, datas) {
      // 修改新的场景比例尺为 0.02
    window.vr_config.measureOflength = 0.02;
     // 修改新的 VR 场景初始化视角
    window.vr_config.vrEye = ht.Default.clone(g3d.getEye());;
     // 再次初始化 VR 场景
    graph3dView.initVRForScene()
});

固然 HT 提供的 VR 插件还有不少的配置项,方便用户更好的调整 VR 场景,包括刷地形,场景移动方式,场景操做方式均可以经过配置进行配置,利用 HT 进行 VR 搭建主要流程以下流程图所示:

vr场景搭建流程图.png

经过上面的流程图,咱们大致能够了解配合 HT 提供的 VR 插件如何进行快速的搭建 VR 场景。

目前谷歌浏览器和火狐浏览器都很友好的支持 VR,能够经过火狐官网提供的 WebVR Demo 在线感觉下官方提供的 VR 场景。

拆解规则

从文章前面的部分效果图能够看到咱们每一个场景的设备都有拆解,而且每一个设备的零件数量,零件位置,零件拆解的方向,偏移的长短都是不一致的,因此不可能经过代码来将上面的偏移长短,偏移方向写死,须要制定一套拆解规则来帮助咱们能够更方便制做每一个场景的拆解动画,这样只须要设计师根据与程序约定好的拆解规则进行配置就能够配置出不一样场景不一样设备的拆解动画。该系统的拆解分为两种状况:

  • 单体移动: 单个设备零件沿着父节点位置和该节点位置的链接线方向移动
  • 组合移动: 多个设备零件的组合沿着某个方向移动,组合移动以后,设备零件能够在组合移动以后的位置进行再沿着某个方向进行移动,能够无限进行嵌套,即组合以后还能够组合移动,或者单体移动

单体移动示意图以下:

单体移动.gif

组合移动示意图以下:

组合移动.gif

在 HT 中能够经过 data.setDisplayName('名称') 来给节点设置名称,这里约定经过不一样设备的名称,来获取到不一样设备的偏移信息,例如 data.setDisplayName('1-0.5-1000') 该名称就是和设计师约定好的配置规则,1 表明拆解步骤的第一步执行,固然场景中能够有多个 1,即第一步同时拆解这些零件。0.5 表明朝着父节点的方向偏移本身位置和父节点位置链接线长度的 50%1000 表明偏移的过程持续 1000 毫秒,固然以后能够约定旋转以及旋转的角度等信息。设计师知道这些配置规则以后即可以经过可视化编辑器进行不一样零件的配置,这样程序方面只须要写一套通用的逻辑就能够对不一样的设备进行拆解和还原。

系统中维护了一个队列和一个队列用来记录拆解顺序用来记录还原顺序。拆解的过程经过配置的序号,按顺序推动队列,采用队列的数据结构即是由于队列先进先出的特色,第一个压入队列的零件则第一个执行,最后压入队列的零件最后一个执行拆解顺序。拆解出队列的零件则同时压入栈,采用记录还原顺序是由于先进后出的特色,即第一个执行完拆解的零件,在还原的时候倒是最后一个执行还原的动做。因此上述采用的不一样数据结构即是为了更好的记录数据。如下为相关 js 伪代码:

// 记录拆解顺序
const queue = [];
 // 记录还原顺序
const stack = [];
 // each 循环中用来记录拆解队列 queue 顺序
dataModel.each((node) => {
    const displayName = node.getDisplayName();
    if (displayName) {
        const [ index, distancePer, during ] = displayName.split('-');
        if (index !== void 0) {
            if (queue[index]) {
                if (queue[index] instanceof Array) {
                    queue[index].push(node);
                }
                else {
                    const tempNode = queue[index];
                    queue[index] = [ tempNode, node ];
                }
            }
            else {
                queue[index] = node;
            }
        }
    }
});

相关逻辑以下流程图:

拆解还原逻辑流程图.png

经过上面的约定,设计师可使用可视化编辑器来配置不一样零件的移动规则,大大提升了动画的制做效率。

代码分析

该部分主要对拆解还原动画的代码进行分析,主要采用向量和部分三角函数的概念来计算不一样零件在三维空间的位置,初始的时候须要记录下每一个零件在前面全部组合移动以后的初始移动位置向量,以及零件没有组合移动以前的初始位置向量,获取这两个位置向量目的是一是为了零件拆解在前面所说组合以后移动,和零件在拆解以后恢复到一整个设备形态的初始位置,两个位置向量都有重要的做用,如下为相关伪代码:

// Vector3 为 HT 封装的三维向量
const Vector3 = ht.Math.Vector3;
 // 记录第一个重要位置向量
node.a('relativeP3Vec', new Vector3(node.p3()));
 // node 当前零件节点
 // moveQueue 为移动顺序在 node 以前的,而且为 node 节点的祖先节点
for (let i = 0, l = moveQueue.length; i < l; i++) {
    const moveNode = moveQueue[i],
    parentMoveNode = moveNode.getParent();
    if (parentMoveNode) {
        const[ , distancePer ] = moveNode.getDisplayName().split('-');
        moveNode.a('defP3', moveNode.p3()) 
        moveNode.p3(new Vector3().lerpVectors(new Vector3(moveNode.p3()), new Vector3(parentMoveNode.p3()), distancePer).toArray());
    }
}
 // 记录组合节点移动以后的第二个重要相对位置向量
node.a('relativeP3Vec', new Vector3(node.p3()));
 // 逆序还原组合的父节点位置
for (let i = moveQueue.length - 1; i >= 0; i--) {
    const moveNode = moveQueue[i];
    moveNode.p3(moveNode.a('defP3'));
    moveNode.a('defP3', undefined);
}

因为在场景拆解过程当中须要设置设备零件节点不可选择,因此须要记录下不可选择以前的零件是否可选择状态,用来恢复节点初始状态,相关伪代码以下:

dm3d.each((node) = >{
    node.a('defSelectable', node.s('3d.selectable'));
});

文中所示的线框效果为 HT 核心包支持的线框模式,能够经过以下代码进行配置:

dm3d.each((data) = >{
    if (data.s('shape3d') && data.s('shape3d').startsWith('models/')) {
        data.s({
            'shape3d.transparent': true,
            'shape3d.opacity': 0, // 目的为隐藏本来的模型
            'wf.geometry': true, // 开启线框模式
            'wf.combineTriangle': 2, // 线框三角面合并类型
            'wf.color': 'rgba(96,172,252,0.3)' // 线框颜色
        });
    }
});

上述 wf.combineTriangle 主要包括

  • false,0: 不合并三角形
  • true,1: 合并相邻三角为四边面,原来的效果
  • 2: 融合全部联通的共面三角面
  • 3: 根据法线信息融合全部平滑三角面

VR 软件以及硬件安装

本系统采用的 VR 硬件设备为 HTC VIVE 接下来说的是安装 HTC VIVE 的过程和步骤。

第一步:撮合 HTC VIVE 和电脑主机

HTC 官网找到链接指南,而后按照步骤安装便可,咱们只需看如下截图部分的目录便可。

vr-step-1.png

第二步:下载软件

Steam 官网下载 Steam,下载完 Steam 能够在 Steam 中下载 Stream VR。

第三步:打开 Stream VR 检查设备状态

打开 Stream VR,会出现如下画面,这是用来表示 HTC VIVE 头显的工做状态的,经过图标咱们便可查看头显、手柄控制器和定位器等配件的工做状况。

vr-step-3.png

第四步:选择房间设置模式

若是您的房间位置比较大能够选择第一项,我选择的模式为第二项,站立模式。建议选择一种房间规模,能够完整的进行设置。

vr-step-4.png

第五步:将头盔、两个手柄控制器放置在两个定位器可视范围内,创建定位

vr-step-5.png

第六步:校准头盔中心点

该步为设置头盔默认的朝向。

vr-step-6.png

第七步:定位地面

将两个手柄控制器放置在定位器可视范围内,而后点击电脑屏幕上的按钮“校准地面”,等待系统校准

vr-step-7.png

第八步:进入 Steam VR 自带房间进行测试

设置完毕以后能够进入 Steam VR 自带的房间进行体验。

总结

当人们谈起 5G 时代的新应用,VR、AR 老是一大热门话题。4G 时代移动网络已经足以承载起高清视频,那么 5G 时代理所固然就能传输数据量更大的沉浸式 VR、AR 影像。所以,很多人将 5G 视为 VR、AR 崛起的踏板,随时随地身临天涯海角,彷佛并不是是高不可攀的梦。当前 4G 网络应用在 VR/AR 上会带来大约 70ms 的时延,这个时延会致使体验者存在眩晕感,而 5G 数据传输的延迟可达到毫秒级,能够有效解决数据时延带来的眩晕感,有助于 VR/AR 的大规模应用。目前随着 5G 网络的逐渐普及,VR/AR 产业正逐步走向复苏,市场热情在逐渐升温,虚拟现实游戏、虚拟现实现场直播等都是 5G 在 VR/AR 上的具体应用。在科技进步的今天,安全也是一个重要的话题,VR 结合仿真的应用也是大势所趋,仿真可让用户真实切身感觉,例如消防预警管道预警,可让用户在 VR 世界中体验消防灭火等消防员的操做,让用户沉浸在 VR 世界中感觉到火灾来临时怎么进行实际操做。因此 VR 带来的应用远远不止仿真,模拟等体验,更多带来的是能为人们提供真实的实际做用,而不是噱头。

程序手机端运行截图:

手机端1.PNG

手机端2.PNG