基于 HTML5 + WebGL 的垃圾分类系统

前言

垃圾分类,一般是指按一定规定或标准将垃圾分类储存、分类投放和分类搬运,从而转变成公共资源的一系列活动的总称。分类的目的是提高垃圾的资源价值和经济价值,力争物尽其用。垃圾在分类储存阶段属于公众的私有品,垃圾经公众分类投放后成为公众所在小区或社区的区域性准公共资源,垃圾分类搬运到垃圾集中点或转运站后成为没有排除性的公共资源。从国内外各城市对生活垃圾分类的方法来看,大致都是根据垃圾的成分、产生量,结合本地垃圾的资源利用和处理方式来进行分类的。到2019年6月25日,生活垃圾分类制度将入法。一套应用于工业物联网的智能一体化的垃圾分类机械臂将随之而来,由此,我应用 HT for Web 的图型化编辑工具打造了一款形象生动的例子:Garbage classification,也借此机会与大家一起分享和学习。

代码实现

(注:gif 的上传大小有限,实际效果与还请参考 demo 链接)

首先,我应用已经精心布置好的 3D 场景,为了有更好的操作体验感,我们要从它的基本设置开始:

gv.setMovableFunc(() => { return false }) // 禁止拖动
gv.getWireframe = (d) => { d.s('wf.visible', false) }  // 隐藏选中边框
gv.setEye([583, -212, -789]) // 设置眼睛
gv.setCenter([-76, -654, -133]) // 设置中心点
gv.setFar(100000) // 设置远端位置
gv.setNear(10) // 设置近端位置
gv.setInteractors([ new ht.graph3d.MapInteractor(gv) ]) // 设置交互限制
gv.setSkyBox(dm.getDataByTag('skyBox')) // 设置天空球
window.document.oncontextmenu = () => { return false } // 全局设置右键菜单禁用
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()),
}

我复制了一下整个场景的初始视角情况方便我做稍后的处理,我监听了部分鼠标事件来形成自己的操作风格(比如双击背景还原视角以及双击模型拉近视角):

gv.mi(e => {
    let data = e.data
    let kind = e.kind
    if (kind === 'doubleClickBackground') { // 双击背景
        gv.moveCamera(this.gv.scene.eye, this.gv.scene.center, {duration : 1000}) // 恢复视角
    }
    else if (kind === 'doubleClickData') { // 双击模型
        gv.flyTo(data, {animation : {duration : 500}, distance : 800}) // 拉近视角
    }
})

好了,准备工作做好了,下面来实现动画部分,除了了解 垃圾分类 的方式外我还参考了网上很多机械臂的视频,学习它的运动模式和动作细节,对每个结构和部位的动画进行步骤的排序和构思。这里我挑选几处动画的实现方式来展示:

function mechanicalArmAnim1() {
  ht.Default.startAnim({
    duration: 1000,
    easing: (t) => { return t },
    action: (v, t) => {
      postbrachium.r3(degrees(0) + (degrees(20) - degrees(0)) * v, postbrachium.r3()[1], postbrachium.r3()[2]) // 后臂向下移
    },
    finishFunc: () => {
      setTimeout(() => {
        mechanicalArmAnim2()
      }, 300)
    }
  })
}
function mechanicalArmAnim2() {
  ht.Default.startAnim({
    duration: 1000,
    easing: (t) => { return t },
    action: (v, t) => {
      postbrachium.p3(-208 + (-184 + 208) * v, postbrachium.p3()[1], postbrachium.p3()[2]) // 后臂前伸
      hydraulicRod1.r3(degrees(0) + (degrees(8) - degrees(0)) * v, hydraulicRod1.r3()[1], hydraulicRod1.r3()[2]) // 液压杆1倾斜
      extensionRod1.r3(degrees(0) + (degrees(8) - degrees(0)) * v, extensionRod1.r3()[1], extensionRod1.r3()[2]) // 伸长杆1倾斜
      extensionRod1.p3(-169 + (-185 + 169) * v, -516 + (-511 + 516) * v, extensionRod1.p3()[2]) // 伸长杆1伸长
      hydraulicRod2.r3(degrees(0) + (degrees(-8) - degrees(0)) * v, hydraulicRod2.r3()[1], hydraulicRod2.r3()[2]) // 液压杆2倾斜
      extensionRod2.r3(degrees(0) + (degrees(-8) - degrees(0)) * v, extensionRod2.r3()[1], extensionRod2.r3()[2]) // 伸长杆2倾斜
      extensionRod2.p3(-169 + (-185 + 169) * v, -516 + (-511 + 516) * v, extensionRod2.p3()[2]) // 伸长杆2伸长
    },
    finishFunc: () => {
      setTimeout(() => {
        mechanicalArmAnim3()
      }, 300)
    }
  })
}
function mechanicalArmAnim3() {
  let oldValue = antebrachium.r3()[0]
  ht.Default.startAnim({
    duration: 1000,
    easing: (t) => { return t },
    action: (v, t) => {
      hydraulicRod1.r3(degrees(8) + (degrees(7) - degrees(8)) * v, hydraulicRod1.r3()[1], hydraulicRod1.r3()[2]) // 液压杆1倾斜
      extensionRod1.r3(degrees(8) + (degrees(7) - degrees(8)) * v, extensionRod1.r3()[1], extensionRod1.r3()[2]) // 伸长杆1倾斜
      extensionRod1.p3(-185 + (-186 + 185) * v, -511 + (-507 + 511) * v, extensionRod1.p3()[2]) // 伸长杆1伸长
      hydraulicRod2.r3(degrees(-8) + (degrees(-7) - degrees(-8)) * v, hydraulicRod2.r3()[1], hydraulicRod2.r3()[2]) // 液压杆2倾斜
      extensionRod2.r3(degrees(-8) + (degrees(-7) - degrees(-8)) * v, extensionRod2.r3()[1], extensionRod2.r3()[2]) // 伸长杆2倾斜
      extensionRod2.p3(-185 + (-186 + 185) * v, -511 + (-507 + 511) * v, extensionRod2.p3()[2]) // 伸长杆2伸长
      postbrachium.r3(degrees(20) + (degrees(25) - degrees(20)) * v, postbrachium.r3()[1], postbrachium.r3()[2]) // 后臂向下移
      antebrachium.r3(oldValue + (degrees(-40) - oldValue) * v, antebrachium.r3()[1], antebrachium.r3()[2]) // 前臂向下移
      claw1.r3(degrees(-20) + (degrees(-60) - degrees(-20)) * v, claw1.r3()[1], claw1.r3()[2]) // 上爪抓取
      claw2.r3(degrees(-60) + (degrees(-30) - degrees(-60)) * v, claw2.r3()[1], claw2.r3()[2]) // 下爪抓取
    },
    finishFunc: () => {
      mechanicalArmAnim4()
    }
  })
}

这一段动画是机械臂从初始化状态到向下抓取的一个过程,我将每段动画分成函数来写比较方便后续管理,每一处也代表了一个步骤。这其中最复杂且细微的步骤要数液压杆的运动了,为了让动画看起来更加真实,我除了将手臂单独运动的过程中加入了延时执行下一段动画以体现机器运动的特点外,也把液压杆的部分也做了动画,如果不做处理,那么机械臂在上下移动的时候就会有不科学的效果出现。动画函数 在这种 demo 中应用的最广,而且里面也包含了一些缓动函数,有兴趣的博友们可以 点此处 自己亲自动手玩一玩~

这里面的拾取垃圾步骤还应用了我过去介绍过的 吸附 功能,这个方法非常的适合抓取物体的动作,通过 setHost 使节点吸附于宿主,这样就相当于子节点跟随父节点移动,此时只需要对机械臂进行偏移和旋转的操作,垃圾便会随之一起运动了,大大减少了工作量!

还有一部分更酷的属性设置给大家展示一下,可以让 3D 场景整体有更真实的阴影处理效果。首先我们要注意将无关的节点阴影通过 node.s('shadow.cast', false) 关闭,比如编组用的box,背景,地板和面板等。

最后我们就把阴影的细节做下调整,达到比较好的效果:

gv.enableShadow(true, {
  degreeX : 0,       // 投影 x 轴角度
  degreeZ : -25,      // 投影 z 轴角度
  intensity : 0.3,    // 阴影强度, 1 为黑色
  quality : 'high',  // low / medium / high / ultra / 4096数值, 质量
  type : 'soft',     // none / hard / soft
  radius : 0.2,      // type 为 hard / soft 时,补充的边缘厚度,用来提供更柔和的边缘
  bias : -0.003     // 深度浮点偏差补足
})

总结

更多动画 demo 以及工业化领域的文章请继续关注

医疗站(https://www.cnblogs.com/htdaydayup/p/11558748.html

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏相约机器人

【ICCV2019教程】手把手带你重现SOTA深度学习模型,附相关资料下载

【导读】深度学习已经成为计算机视觉领域事实上的标准算法。针对各种不同的任务,每年研究者都会提出大量的方法。重现整个系统的每个细节,可能不仅有问题而且耗时,尤其是...

11520
来自专栏HT

H5 + WebGL 实现的地铁站 3D 可视化系统

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

9020
来自专栏前端资源

纯CSS绘制三角形、梯形及border属性的延伸

利用CSS实现三角形效果,比较常用的思路是使用 border 边框来实现,border 边框是由四个三角形组成的,通过调整四个边来实现不同形状的三角形。

8710
来自专栏Creator星球游戏开发社区

Creator 3D v1.0.1 测试版发布,提供最新案例在线体验!

Cocos官方除了更新引擎的诸多功能外,还提供几个完整的 Demo 案例。晓衡成功将最近两个具有魔性 Demo 小游戏在 Creator 3D 1.0.1 上构...

7820
来自专栏镁客网

拔刺 | VR产业背后的技术支撑是什么?

最近几年,随着技术的发展,VR(Virtual Reality)跟人工智能一样,火的简直不能再火了。其带来的视觉上的冲击、沉浸式的感官体验有很多人跃跃欲试,于是...

6620
来自专栏镁客网

第一批被AI "变脸 "的人

拍图三十秒,修图半小时,互联网公司们都深谙这种心理,使出浑身解数,让“变脸”更加完美。比如一直针对女性群体,主打拍照的OV手机(OPPO和Vivo),在这两年逆...

6020
来自专栏镁客网

无人再谈CV:计算机视觉公司的困境

CV赛道的战争是否已经结束?行业排位是否已成定局?新涌现的CV公司,是否还能破局?

8310
来自专栏音视频技术

基于FPGA异构计算快速构建高性能图像处理解决方案

大家好,我是深维科技创始人/CEO 樊平,非常高兴有这个机会跟大家分享和交流一下,如何基于FPGA来构造高性能的图像处理解决方案。

10310
来自专栏相约机器人

HoloGAN(一种新的生成模型)从自然图像中学习3D表示

一组研究人员提出了一种新的生成对抗网络(GAN),该网络使用自然图像执行3D表示的无监督学习。

12020
来自专栏静Design

[译文]重磅!Behance官方最全2020设计趋势

静电说:每年Behance官方出的设计趋势文章都成为各大设计媒体争先翻译的对象,虽然网络上已经有流传。但是静电还是花了大半天的时间,借助自身与翻译工具,将全文进...

16850

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励