前言

今天为大家带来一个很酷的作品,依然运用了强大的 HT for Web 的 3D 图形组件,动作流畅性能好,大家可以先来欣赏一下效果!

点我进入!

整体风格为科技金属风,制作精良,由于上传 gif 大小有限制,所以务必打开链接查看细节演示!

代码实现

做完场景后,首先我们要对它进行一些基本的设置,如:

// 设置 camera 的位置
gv.setEye([457, 9047, 434])
// 设置中心点位置
gv.setCenter([-4, -1, 0])
// 设置远端距离
gv.setFar(500000)

设置后可以让场景在反序列化后能够显示出我们想要的展示角度,设置远端位置能够避免造成场景显示不完全等问题。

为了使其看起来有一个进入的过程,我们给场景增加一个入场的动画来增色:

ht.Default.startAnim({
duration: 3000, // 动画周期毫秒数,默认采用`ht.Default.animDuration`
action: function (v) { // action函数必须提供,实现动画过程中的属性变化。
gv.setEye([gv.getEye()[0] + (1117 - gv.getEye()[0]) * (v / 5), gv.getEye()[1] + (450 - gv.getEye()[1]) * (v / 5), gv.getEye()[2] + (1139 - gv.getEye()[2]) * (v / 5)])
},
finishFunc: function () { // 动画结束后调用的函数。
gv.scene = {
eye: ht.Default.clone(gv.getEye()),
center: ht.Default.clone(gv.getCenter()),
far: ht.Default.clone(gv.getFar()),
near: ht.Default.clone(gv.getNear())
}
}
})

这个动画我们的思路是通过改变 camera 的位置来的实现,使用动画函数我们可以在指定的时间周期内完成动画,可理解为将某些属性由起始值逐渐变到目标值的过程。通过在 action 函数中我们对 carmera 进行细致地调整,就可以实现完美的入场效果了。finishFunc 函数中我们做了一个复制的操作,目的是要记住这个位置,以便于我们后面的功能实现,这个稍后会提到。

对了,我们还要对整个场景的视角及范围做限制:

var mapInteractor = new ht.graph3d.MapInteractor(gv)
gv.setInteractors([
mapInteractor
])
gv.mp(function (e) {
if (e.property === "eye") {
if (gv.getEye()[0] > 3500) {
gv.getEye()[0] = 3500
}
if (gv.getEye()[0] < -3500) {
gv.getEye()[0] = -3500
}
if (gv.getEye()[1] > 9000) {
gv.getEye()[1] = 9000
}
if (gv.getEye()[2] > 3500) {
gv.getEye()[2] = 3500
}
if (gv.getEye()[2] < -3500) {
gv.getEye()[2] = -3500
}
}
})

这样可以限制翻转到场景底面,然后再对 eye 做限制防止在拉远的时候超出天空球包裹的范围。

接下来我们要加一个场景视角复位的功能:

gv.mi(function (e) {
if (e.kind === 'doubleClickBackground') {
gv.moveCamera(gv.scene.eye, gv.scene.center, true)
}
...
})

事件监听一下,在双击的时候通过 moveCamera() 来移动中心点的位置,坐标就是我们在入场动画的操作中记录的位置。

为了加强性能及便利性,我们在点击事件中再添加一个控制面板开关的的逻辑,这样可以简约化显示:

if (e.kind === 'clickData') {
if (e.data.getTag() === '按钮') {
var status = dm.getDataByTag('面板1').s('3d.visible')
for (var i = 1; i <= 10; i++) {
dm.getDataByTag('面板' + i).s('3d.visible', !status)
}
}
}

通过对 2D 面板的属性改变来实现如下效果:

面板数值的变化也通过绑定的属性来修改,为了做演示,我用一些随机数来代替,这里就不多说了。

然后我们要把管道的流动、履带的运行、回转窑的运动以及磨轮转动等动画先实现出来:

function flow(name1, name2) {
for (var i = 1; i <= 6; i++) {
// uv 偏移
if (name2) {
dm.getDataByTag(name2 + i).s('shape3d.uv.offset', [dm.getDataByTag(name2 + i).s('shape3d.uv.offset')[0] + 0.005, dm.getDataByTag(name2 + i).s('shape3d.uv.offset')[1]])
}
// 设默认值
else {
dm.getDataByTag(name1 + i).s('shape3d.uv.offset', [0,0])
}
}
}
// 储料罐
function tank(name, num, v) {
for (var i = 1; i <= 8; i++) {
dm.getDataByTag(name + i).setScaleTall(dm.getDataByTag(name + i).getScaleTall() + (num[i - 1] - dm.getDataByTag(name + i).getScaleTall()) * v)
}
}
// 滚轮
function roller(name) {
for (var i = 1; i <= 12; i++) {
if (i % 2 === 0) {
value = -0.1
}
else {
value = 0.1
}
if (i <= 8) {
dm.getDataByTag(name + i).r3(dm.getDataByTag(name + i).r3()[0], dm.getDataByTag(name + i).r3()[1] + value, dm.getDataByTag(name + i).r3()[2])
}
else {
dm.getDataByTag(name + i).r3(dm.getDataByTag(name + i).r3()[0] + value, dm.getDataByTag(name + i).r3()[1], dm.getDataByTag(name + i).r3()[2])
}
}
}
anim()
function anim() {
var num = []
for (var i = 1; i <= 8; i++) {
num.push(Math.random() * 6)
}
ht.Default.startAnim({
duration: 1000,
action: function (v, t) {
dm.getDataByTag('流动2').r3(dm.getDataByTag('流动2').r3()[0] - 0.1, dm.getDataByTag('流动2').r3()[1], dm.getDataByTag('流动2').r3()[2])
flow('流动', '流动')
tank('储料罐', num, v)
roller('滚轮')
},
finishFunc: function () {
anim()
}
})
}

我把他们统一放在一个动画函数中循环播放,都是一些比较简单的动画,通过使高度、角度等属性的变化来实现相应的动画效果,如代码所示不一一细述。这里我稍微说一下关于这个管道和履带流动的实现思路,我是利用了调整 UV 贴图来完成的。

什么是 UV ?通俗的讲,UV 就是把三维立体模型的外表面剥离下来,展开铺平成二维平面状态,以便进行贴图绘制,就如同香烟盒上的包装图案其实是在纸盒片状态下印刷完成的一样。

首先我们需要绘制一张二方连续贴图(左右或上下可以无缝衔接的贴图),并且依照场景中管道和传送带流动的方向,将UV展成长条状,与贴图相匹配。

然后我们在通过代码驱动 UV 向 U 轴的正值方向偏移一个象限,并无限循环这一动作。回到三维场景中,你就会神奇的发现,管道和传送带在不间断的流动着!

最后我们来完成卡车的运行动画,整体流程先设计好:

var truck1 = dm.getDataByTag('卡车1')
var truck2 = dm.getDataByTag('卡车2')
var truck3 = dm.getDataByTag('卡车3')
var cargo1 = dm.getDataByTag('货斗1')
var cargo2 = dm.getDataByTag('货斗2')
var coal = dm.getDataByTag('货1')
var limestone = dm.getDataByTag('货2')
var panel1 = dm.getDataByTag('面板8')
var panel2 = dm.getDataByTag('面板9')
anim1()
// 出发
function anim1() {
ht.Default.startAnim({
duration: 4000,
easing: function (t) { return (t *= 2) < 1 ? 0.5 * t * t : 0.5 * (1 - (--t) * (t - 2)) },
action: function (v, t) {
truck1.p3(truck1.p3()[0], truck1.p3()[1], truck1.p3()[2] + (700 - truck1.p3()[2]) * (v / 10))
truck2.p3(truck2.p3()[0], truck2.p3()[1], truck2.p3()[2] + (700 - truck2.p3()[2]) * (v / 5))
truck3.p3(truck3.p3()[0] + (300 - truck3.p3()[0]) * (v / 20), truck3.p3()[1], truck3.p3()[2])
},
finishFunc: function () {
anim2()
}
})
}
// 掉头
function anim2() {
ht.Default.startAnim({
duration: 1000,
action: function (v, t) {
truck1.r3(truck1.r3()[0], truck1.r3()[1] + (180 * Math.PI / 180 - truck1.r3()[1]) * v, truck1.r3()[2])
truck2.r3(truck2.r3()[0], truck2.r3()[1] + (180 * Math.PI / 180 - truck2.r3()[1]) * v, truck2.r3()[2])
truck3.r3(truck3.r3()[0], truck3.r3()[1] + (-90 * Math.PI / 180 - truck3.r3()[1]) * v, truck3.r3()[2])
},
finishFunc: function () {
anim3()
}
})
}
// 卸货
function anim3() {
ht.Default.startAnim({
duration: 2000,
action: function (v, t) {
cargo1.r3(cargo1.r3()[0] + (70 * Math.PI / 180 - cargo1.r3()[0]) * v, cargo1.r3()[1], cargo1.r3()[2])
cargo2.r3(cargo2.r3()[0] + (70 * Math.PI / 180 - cargo2.r3()[0]) * v, cargo2.r3()[1], cargo2.r3()[2])
panel1.a('进度值', panel1.a('进度值') + (0 - panel1.a('进度值')) * v)
panel2.a('进度值', panel2.a('进度值') + (0 - panel2.a('进度值')) * v)
panel1.a('重量', panel1.a('进度值').toFixed(1))
panel2.a('重量', panel2.a('进度值').toFixed(1))
},
finishFunc: function () {
coal.s('3d.visible', false)
limestone.s('3d.visible', false)
anim4()
}
})
}
// 卸货
function anim4() {
ht.Default.startAnim({
duration: 2000,
action: function (v, t) {
cargo1.r3(cargo1.r3()[0] + (0 * Math.PI / 180 - cargo1.r3()[0]) * v, cargo1.r3()[1], cargo1.r3()[2])
cargo2.r3(cargo2.r3()[0] + (0 * Math.PI / 180 - cargo2.r3()[0]) * v, cargo2.r3()[1], cargo2.r3()[2])
},
finishFunc: function () {
anim5()
}
})
}
// 返回
function anim5() {
ht.Default.startAnim({
duration: 4000,
easing: function (t) { return (t *= 2) < 1 ? 0.5 * t * t : 0.5 * (1 - (--t) * (t - 2)) },
action: function (v, t) {
truck1.p3(truck1.p3()[0], truck1.p3()[1], truck1.p3()[2] + (1180 - truck1.p3()[2]) * (v / 10))
truck2.p3(truck2.p3()[0], truck2.p3()[1], truck2.p3()[2] + (1180 - truck2.p3()[2]) * (v / 5))
truck3.p3(truck3.p3()[0] + (1180 - truck3.p3()[0]) * (v / 20), truck3.p3()[1], truck3.p3()[2])
},
finishFunc: function () {
anim6()
}
})
}
// 掉头
function anim6() {
ht.Default.startAnim({
duration: 1000,
action: function (v, t) {
truck1.r3(truck1.r3()[0], truck1.r3()[1] + (0 * Math.PI / 180 - truck1.r3()[1]) * v, truck1.r3()[2])
truck2.r3(truck2.r3()[0], truck2.r3()[1] + (0 * Math.PI / 180 - truck2.r3()[1]) * v, truck2.r3()[2])
truck3.r3(truck3.r3()[0], truck3.r3()[1] + (90 * Math.PI / 180 - truck3.r3()[1]) * v, truck3.r3()[2])
},
finishFunc: function () {
panel1.a('进度值', 1)
panel2.a('进度值', 1)
panel1.a('重量', 10)
panel2.a('重量', 10)
coal.s('3d.visible', true)
limestone.s('3d.visible', true)
anim1()
}
})
}

这个是我实现卡车的整个运作流程的完整代码,分别由几段动画协调组合而成,只要搞清楚顺序以及每一个动作实现的逻辑并不难办到,无非就是方向、角度和距离的一些计算,还有面板进度条同步的设置。

经过我们的努力后,一个炫酷专业的工厂流程系统的演示我们就完成了!

总结

在互联网+ 概念飞速发展的今天,有太多的领域在等待着我们去挖掘,HT For Web 非常适用于各种的智慧建筑,监控系统以及电力、燃气等工业自动化 ( HMI / SCADA ) 领域。希望看了我的这篇博,大家能有所启发,挑战更多的不可能!

基于 HTML5 WebGL 的 3D 水泥工厂生产线的更多相关文章

  1. 基于 HTML5 WebGL 的 3D 风机 Web 组态工业互联网应用

    基于 HTML5 WebGL 的 3D 风机 Web 组态工业互联网应用 前言 在目前大数据时代背景之下,数据可视化的需求也变得越来越庞大,在数据可视化的背景之下,通过智能机器间的链接并最终将人机链接 ...

  2. 基于 HTML5 + WebGL 的 3D 可视化挖掘机

    前言 在工业互联网以及物联网的影响下,人们对于机械的管理,机械的可视化,机械的操作可视化提出了更高的要求.如何在一个系统中完整的显示机械的运行情况,机械的运行轨迹,或者机械的机械动作显得尤为的重要,因 ...

  3. 基于 HTML5 + WebGL 实现 3D 可视化地铁系统

    前言 工业互联网,物联网,可视化等名词在我们现在信息化的大背景下已经是耳熟能详,日常生活的交通,出行,吃穿等可能都可以用信息化的方式来为我们表达,在传统的可视化监控领域,一般都是基于 Web SCAD ...

  4. 基于 HTML5 + WebGL 实现 3D 挖掘机系统

    前言 在工业互联网以及物联网的影响下,人们对于机械的管理,机械的可视化,机械的操作可视化提出了更高的要求.如何在一个系统中完整的显示机械的运行情况,机械的运行轨迹,或者机械的机械动作显得尤为的重要,因 ...

  5. 基于 HTML5 WebGL 构建 3D 智能数字化城市全景

    前言 自 2011 年我国城镇化率首次突破 50% 以来,<新型城镇化发展规划>将智慧城市列为我国城市发展的三大目标之一,并提出到 2020 年,建成一批特色鲜明的智慧城市.截至现今,全国 ...

  6. 基于 HTML5 WebGL 的 3D 网络拓扑图

    在数据量很大的2D 场景下,要找到具体的模型比较困难,并且只能显示出模型的的某一部分,显示也不够直观,这种时候能快速搭建出 3D 场景就有很大需求了.但是搭建 3D 应用场景又依赖于通过 3ds Ma ...

  7. 基于 HTML5 WebGL 的 3D 服务器与客户端的通信

    这个例子的初衷是模拟服务器与客户端的通信,我把整个需求简化变成了今天的这个例子.3D 机房方面的模拟一般都是需要鹰眼来辅助的,这样找产品以及整个空间的概括会比较明确,在这个例子中我也加了,这篇文章就算 ...

  8. 基于 HTML5 WebGL 的 3D SCADA 主站系统

    这个例子的初衷是模拟服务器与客户端的通信,我把整个需求简化变成了今天的这个例子.3D 的模拟一般需要鹰眼来辅助的,这样找产品以及整个空间的概括会比较明确,在这个例子中我也加了,这篇文章就算是我对这次项 ...

  9. 基于 HTML5 WebGL 的 3D 科幻风机

    前言 许多世纪以来,风力机同水力机械一样,作为动力源替代人力.畜力,对生产力的发展发挥过重要作用.近代机电动力的广泛应用以及二十世纪50年代中东油田的发现,使风机发电机的发展缓慢下来. 70年代初期, ...

随机推荐

  1. mac 下常用快捷键

    1.快速搜索某个类 双击thift 2.切换不同的类: ctrl+方向键 3.alt+command+B 进入到具体的子类 但是 ctrl+方向键一直切的是电脑上 桌面的切换.打开 系统偏好设置-快捷 ...

  2. C#des加密算法指定键的大小对于此算法无效

    api接口调用的时候,需要和java的进行加密通信,通信过程中用到DES加密,java那边DES的key为64位字符串,而之前c#的DES加密是key为8位 DESCryptoServiceProvi ...

  3. 如何查看服务器CPU核心数和线程数

    知道服务器CPU型号,那么我们如何在服务器里面查看服务器CPU核心数和线程数呢? 步骤: 先用鼠标右键点击屏幕最下方的任务栏空白处.会弹出一个菜单. 在菜单中用鼠标左键点选“启动任务管理器”. 点击任 ...

  4. 【Oracle】DBMS_STATS.GATHER_SCHEMA_STATS详解

    dbms_stats能良好地估计统计数据(尤其是针对较大的分区表),并能获得更好的统计结果,最终制定出速度更快的SQL执行计划. exec dbms_stats.gather_schema_stats ...

  5. 打通版微社区(3):在Web服务器上部署memcache For DZ3.2

    写在前面:首先这个数据库加速程序的原理,是将数据库内容缓存到Web服务器的内存上,也就是内存换速度.我本次微社区的应用其实应该用不了这个,只是看到好多DZ论坛部署的都安装了这个,我就练手一下以便不时之 ...

  6. Xcode 下载地址 与Macos版本要求

    Xcode下载地址:https://developer.apple.com/download/more/ 参考文档:https://zh.wikipedia.org/wiki/Xcode

  7. There was a problem confirming the ssl certificate: [SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:661) - skipping

    Could not fetch URL https://pypi.python.org/simple/xlrd/: There was a problem confirming the ssl cer ...

  8. Nowcoder Girl 初赛 T5

    Nowcoder Girl 初赛第五题 来源 Nowcoder Girl 初赛第五题 题面 \(n(1<=n<=10000)\)件武器,每件武器对于属性有加成,一共五种属性.若使用其中的\ ...

  9. Maven编译Java程序配置

    Hive 需要在工程里添加的Jar包: hadoop-2.2.0/share/hadoop/common/hadoop-common-2.2.0.jar $HIVE_HOME/lib/hive-exe ...

  10. BZOJ 2038 小Z的袜子(hose) 莫队算法模板题

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=2038 题目大意: 作为一个生活散漫的人,小Z每天早上都要耗费很久从一堆五颜六色的袜子中 ...