基于 HTML5 WebGL 的发动机 3D 可视化系统
前言
工业机械产品大多体积庞大、运输成本高,在参加行业展会或向海外客户销售时,如果没有实物展示,仅凭静态、简单的图片说明书介绍,无法让客户全面了解产品,不仅工作人员制作麻烦,客户看得也费力。如果能在 Web 上做 3D 设备展示,销售人员可以不限平台随时给客户介绍演示。还可以不受现实条件限制,演示设备拆分和组装的过程,展示产品内部结构和动态运作时的效果,让客户更直观了解产品的部件组成,更准确、全面地了解产品的功能和特点,大大降低了沟通成本。为了解决这些行业痛点,本篇文章采用 Hightopo 的 HT for Web 产品实现了一个发动机设备 3D 可视化案例。
系统预览
预览地址:基于 HTML5 WebGL 的发动机 3D 可视化系统(http://www.hightopo.com/demo/engine/)
场景搭建
发动机模型是设计师通过 3ds Max 建模,然后导出 obj 与 mtl 文件,在 HT 中解析 obj 与 mtl 文件生成 3D 场景中可用的模型(可参考 obj 手册《通过JSON加载》章节),因为各个部件需要单独操作,所以设备模型拆分为多个 obj 文件后导入。
2D 面板部分则是通过 HT 的矢量绘制,我们需要创建 ht.graph.GraphView 和 ht.graph3d.Graph3dView 来呈现 2D 和 3D 的内容。相关代码如下:
var g2d = new ht.graph.GraphView();
var g3d = new ht.graph3d.Graph3dView();
// 将 3D 组件加入到 body 下
g3d.addToDOM();
// 将 2D 组件加入到 3D 组件的根 div 下
g2d.addToDOM(g3d.getView());
功能实现
设备拆解动画
当我们点击“展开”按钮时,给各个动画设置不同的延迟,使动画错开执行,以达到更好的视觉效果,让2D图纸和3D场景更好地联动起来。
如果我们的每个动画都匀速运行,那看起来难免有些单调。于是我给不同动画加上了不同的 Easing 函数,Easing 函数通过定义不同曲线的数据公式方式,来描述每一帧回调时需要改变图形参数属性的幅度,从而达到均匀、先快后慢、先慢后快,甚至先超出起始值和结束值再慢慢恢复的各种动画特效。这里还有个例子可以帮助我们更直观的感受不同 Easing 函数的效果:《From Easing》。
例如图纸中心的跟随部件拆解旋转放大的圆环,我给它设置了 Easing.backBoth 缓动效果,代码如下:
// 圆环动画
animCenter(data) {
ht.Default.startAnim({
duration: 4500,
// 设置缓动函数
easing: Easing.backBoth,
// 延迟一秒执行动画
delay: 1000,
action: function (v, t) {
// 修改图元缩放值
data.setScale(1 + v * 0.9, 1 + v * 0.9);
// 修改图元旋转角度
data.setRotation(Math.PI * v);
},
});
}
// 缓动函数
Easing.easeOutStrong = function (t) {
var BACK_CONST = 1.70158;
if ((t *= 2) < 1) {
return .5 * (t * t * (((BACK_CONST *= (1.525)) + 1) * t - BACK_CONST));
}
return .5 * ((t -= 2) * t * (((BACK_CONST *= (1.525)) + 1) * t + BACK_CONST) + 2);
};
设备部件的拆解动画,是通过改变节点的坐标和旋转角度来实现的,代码如下:
// targetP3 为拆解后的坐标,p3为当前坐标
var p3 = node.p3();
var offset = [targetP3[0] - p3[0], targetP3[1] - p3[1], targetP3[2] - p3[2]];
// targetR3 为拆解后的旋转角度,r3为当前旋转角度
var r3 = node.r3();
var offset = [targetR3[0] - r3[0], targetR3[1] - r3[1], targetR3[2] - r3[2]];
// 拆解动画
ht.Default.startAnim({
duration: 2000,
// 设置缓动函数
easing: Easing.easeOutStrong,
delay: 1000,
action: function (v, t) {
// 修改节点坐标
node.p3(p3[0] + offset[0] * v, p3[1] + offset[1] * v, p3[2] + offset[2] * v);
// 修改节点旋转角度
node.r3(r3[0] + offset[0] * v, r3[1] + offset[1] * v, r3[2] + offset[2] * v);
},
});
// 缓动函数
Easing.easeOutStrong = function (t) {
return 1 - (--t) * t * t * t;
};
还有图纸两侧的面板,可以通过设置它的裁剪方向和裁剪比例实现隐藏效果,代码如下:
// 设置图元裁剪方向为从右到左
node.s('clip.direction', 'left');
// 裁剪动画
ht.Default.startAnim({
duration: 1800,
easing: Easing.easeOutStrong,
action: function (v, t) {
// 修改图元裁剪比例
node.s('clip.percentage', 1 - v);
}
});
// 缓动函数
Easing.easeOutStrong = function (t) {
return 1 - (--t) * t * t * t;
};
设备内部运作动画
接下来我们实现视角变化动画来观察设备不同部件构造,3D 场景中的视角是由 Graph3dView 提供的 center(目标点坐标)和 eye(摄像机坐标)两个参数决定的,所以视角动画只要动态改变这两个参数,这里用了 HT 提供的 moveCamera 方法实现,代码如下:
g3d.moveCamera([-466, 93, -280], [40, -40, -40], {
duration: 2500,
easing: function (t) {
return 1 - (--t) * t * t * t;
},
});
设备中一些小的部件吸附在大部件上,会跟随大部件移动旋转。比如这个液压杆,当我们要实现小部件的运动动画时,如果用修改坐标的方式计算起来比较麻烦,所以我们用修改锚点的方式来实现,锚点影响着节点的位置,锚点也是旋转和缩放的中心点。这里通过修改液压杆的 Y 轴锚点实现动画,效果如下:
相关代码如下:
ht.Default.startAnim({
duration: 800,
action: function (v, t) {
// 修改节点 Y 轴锚点
node.setAnchor3d(0.5,v,0.5);
},
};
点击流动按钮后,我们可以看到管道内有液体流动的动画。要实现流动效果,首先我们需要一张二方连续贴图(左右或上下可以无缝衔接的贴图),然后我们再通过代码驱动 UV 向 U 轴的正值方向偏移一个象限,并无限循环这一动作,效果如下:
代码如下:
ht.Default.startAnim({
duration: 2000,
action: function (v, t) {
// 修改贴图uv值
node.s('shape3d.uv.offset', [v, 0]);
},
};
设备复原动画
鼠标移入效果
为了能透过外壳清楚的观察到设备内部结构,所以当鼠标悬停在部件上时,我调整了外壳模型透明度并设置模型高亮模式,相关代码如下:
// 设置高亮颜色
ht.Style['highlight.color'] = 'rgba(255,255,255,0.6)';
// 设置当前高亮的模式
g3d.setHighlightMode('mouseover');
// 节点启用高亮效果
data.s('highlight.visible', true);
// 节点设置为可交互
data.s('interactive', true);
// 节点开启交互后,不阻止场景上默认的交互行为
data.s('preventDefaultWhenInteractive', false);
// 监听交互事件
g3d.mi(function (e) {
// 鼠标移入事件
if (e.kind === 'onEnter') {
// 节点开启透明
data.s('shape3d.transparent', true);
// 设置节点透明度
data.s('shape3d.opacity', 0.25);
}
// 鼠标移出事件
if (e.kind === 'onLeave') {
data.s('shape3d.transparent', false);
}
});
场景视角限制
最后,我们再对整个场景的视角范围做下限制,代码如下:
// 设置最大角度
ht.Default.graph3dViewMaxPhi = Math.PI / 2;
// 设置最小角度
ht.Default.graph3dViewMinPhi = Math.PI / 4;
总结
通过案例我们可以感受到,相较于传统方式,设备的三维展示具有更灵活的表现形式和更直观生动的效果,对于出口型企业,生动的演示动画能让外商更快了解产品的工作原理和优势,还能避免因语言误差而造成误解。而且比起普通的工业动画,Web 上的可视化系统展示内容更丰富、自由度更高,后续需求更改也更为灵活、成本更低。
本文使用的设备模型是设计师虚构的核动力发动机,更注重于模型的展示效果,如果应用于实际产品中,还可以制作更还原实际的设备拆解流程,通过线上的 3D 产品操作演练,对工作人员进行产品组装、拆分、维修培训。有兴趣可以参考我们另一个案例《基于 HTML5 WebGL + WebVR 的 3D 虚拟现实可视化培训系统》。
基于 HTML5 WebGL 的发动机 3D 可视化系统的更多相关文章
- 基于 HTML5 WebGL 的地铁站 3D 可视化系统
前言 工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCAD ...
- 基于 HTML5 + WebGL 的地铁 3D 可视化系统
前言 工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCAD ...
- 基于 HTML5 + WebGL 的无人机 3D 可视化系统
前言 近年来,无人机的发展越发迅速,既可民用于航拍,又可军用于侦察,涉及行业广泛,也被称为“会飞的照相机”.但作为军事使用,无人机的各项性能要求更加严格.重要.本系统则是通过 Hightopo 的 ...
- 基于 HTML5 WebGL 的挖掘机 3D 可视化应用
前言 在工业互联网以及物联网的影响下,人们对于机械的管理,机械的可视化,机械的操作可视化提出了更高的要求.如何在一个系统中完整的显示机械的运行情况,机械的运行轨迹,或者机械的机械动作显得尤为的重要,因 ...
- 基于 HTML5 WebGL 的加油站 3D 可视化监控
前言 随着数字化,工业互联网,物联网的发展,我国加油站正向有人值守,无人操作,远程控制的方向发展,传统的人工巡查方式逐渐转变为以自动化控制为主的在线监控方式,即采用数据采集与监控系统 SCADA.SC ...
- 基于 HTML5 WebGL 的智慧楼宇可视化系统
前言 可视化的智慧楼宇在 21 世纪是有急迫需求的,中国被世界称为"基建狂魔",全球高层建筑数量位居首位,所以对于楼宇的监控是必不可少.智慧楼宇可视化系统更多突出的是管理方面的功能 ...
- 基于 HTML5 WebGL 的高炉炼铁厂可视化系统
前言 在当今 工业4.0 新时代的推动下,不仅迎来了 工业互联网 的发展,还开启了 5G 时代的新次元.而伴随着带宽的提升,网络信息飞速发展,能源管控上与实时预警在工业互联网中也占着举足轻 ...
- 基于 HTML5 WebGL 的 水泥工厂可视化系统
前言 如今的制造行业,基于数据进行生产策略制定与管理已经成为一种趋势,特别是 工业4.0 的浪潮下,数据战略已经成为很多制造企业的优先战略,而数据可视化以更直观的方式,帮助指导决策,成为数据分析传递信 ...
- 基于 HTML5 + WebGL 的太阳系 3D 展示系统
前言 近年来随着引力波的发现.黑洞照片的拍摄.火星上存在水的证据发现等科学上的突破,以及文学影视作品中诸如<三体>.<流浪地球>.<星际穿越>等的传播普及,宇宙空间 ...
随机推荐
- hadoop datanode 启动正常,但master无法识别(50030不显示datanode节点)
start-all.sh 启动 坑爹 找不出错 试了各种办法,重新formaet 查看 集群ID是否相同.都无效 日志也没看到错 按官网方法手动一步步启,问题照旧 master节点,yarn name ...
- Python如何规避全局解释器锁(GIL)带来的限制
编程语言分类概念介绍(编译型语言.解释型语言.静态类型语言.动态类型语言概念与区别) https://www.cnblogs.com/zhoug2020/p/5972262.html Python解释 ...
- JavaScript if为true的情况
变量如果不为0,null,undefined,false,都会被处理为true.只要变量有非0的值或是某个对象,数组,字符串,都会认为true
- 产品需求说明书PRD模版
<软件自动化测试开发>出版了 XXX产品需求说明书 [版本号:V+数字] 编 制: 日 期: 评 审: 日 期: 批 准: 日 期: ...
- 查漏补缺:socket编程:TCP粘包问题和常用解决方案(上)
1.TCP粘包问题的产生(发送端) 由于TCP协议是基于字节流并且无边界的传输协议,因此很容易产生粘包问题.TCP的粘包可能发生在发送端,也可能发生在接收端.发送端的粘包是TCP协议本身引起的,TCP ...
- L53-Maximum-Subarray
题目描述 Find the contiguous subarray within an array (containing at least one number) which has the lar ...
- Rails工程实战记录
项目git:https://github.com/yixiaoyang/ruby 为熟悉Rails的基本特性创建的工程,本博文仅作更新记录. (1)2013.10.1-2013.10.5 Ruby基本 ...
- 安卓权威编程指南 挑战练习:实现高效RecyclerView刷新
Adapter的notifyDataSetChanged方法会通知RecyclerView刷新全部的可见列表项. 在CriminalIntent应用里,这个方法不够高效,我们知道,返回CrimeLis ...
- USB小白学习之路(6) IIC EEPROM读取解析
IIC EEPROM读取解析 1. 编译错误处理(这里可以忽略) 在解压包解压了程序后,直接编译,出现如下错误. *** WARNING L14: INCOMPATIBLE MEMORY MODEL ...
- 《数据结构与算法》—— O(3N)=O(N) ?
上帝的磨盘转动很慢,但是却磨得很细. --毛姆 本文已经收录至我的GitHub,欢迎大家踊跃star 和 issues. https://github.com/midou-tech/articles ...