基于 H5与WebGL 的科幻风机 3D 展示

前言

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

70年代初期,由于“石油危机”,出现了能源紧张的问题,人们认识到常规矿物能源供应的不稳定性和有限性,于是寻求清洁的可再生能源遂成为现代世界的一个重要课题。风能作为可再生的、无污染的自然能源又重新引起了人们重视。

现在我希望可以通过这个风机 demo 使风力发电机的各个功能近距离的展示给大家,使大家能更了解风力发电机。

本 demo 使用 HT for Web 产品轻量化 HTML5/WebGL 建模的方案。

demo 链接:https://hightopo.com/demo/fan3d-magic/

风机主要功能介绍

效果:

  

周围环境功能:

  一.  风速值。

  虚拟一个风速值,风速值会影响风机的发电效率和变桨系统的变化。

  二.  数据统计

  

  环境温度、机舱温度、齿轮箱温度、风速的图形百分比会随着时间发生改变。

  三.  环境监测

  

  左边对风机的各个参数实施了监测,右面是风速变化的折线图。

  四.  数据监测  

  

  风机在发电的过程中发生的异常情况,发生的故障部位及故障发生的时间。异常信息的收集有利于人们进行异常分析以及异常处理。

  五. 偏航系统

  

  偏航系统,又称对风装置,是风力发电机机舱的一部分,其作用在于当风速矢量的方向变化时,能够快速平稳地对准风向,以便风轮获得最大的风能。

  . 变桨系统

  

  变桨系统作为大型风电机组控制系统的核心部分之一,对机组安全、稳定、高效的运行具有十分重要的作用。稳定的变桨控制已成为当前大型风力发电机组控制技术研究的热点和难点之一。

  变桨控制技术简单来说,就是通过调节桨叶的节距角,改变气流对桨叶的攻角,进而控制风轮捕获的气动转矩和气动功率。

按钮控制功能:

  风机启停:

  

  线框模式:

  

  机舱视角:

  

  发电工艺:

  

整理思路:

   场景部分

  这里把 3D 当做背景嵌套在 2D 场景中。

  这样在初始化图纸的时候,直接反序列化 2D 图纸即可。

  事件部分

  2D 图纸中有很多的按钮,通过它们来控制 3D 中的一些动画。

  实现思路是在反序列化图纸的时候把 2D、3D 的 模型和视图对象挂载到 window 上,这样在不同的场景中都可以获取到相应的数据模型。

  环境部分:

  风速、风向、变桨角度这些会在 2D、3D 中所表现,所以可以把他们放到数据池里面,方便管理。

具体代码实现:

场景搭建:上面说了,我们把 3D 当做背景嵌套在 2D 中,所以只需要序列化 2D 即可,里面需要进行背景判断的部分代码。

相关伪代码

graphView.deserialize(‘displays/demo/风力发电机/风力发电机结构查看.json‘, function (json, dm, gv, datas) {
  if (json.title) document.title = json.title
        if (json.a[‘json.background‘]) {
            var bgJSON = json.a[‘json.background‘]
            if (bgJSON.indexOf(‘displays‘) === 0) {
                var bgGv = new ht.graph.GraphView()
                bgGv.deserialize(bgJSON)
                bgGv.addToDOM()
                graphView.addToDOM(bgGv.getView())
            }
            else if (bgJSON.indexOf(‘scenes‘) === 0) {
                var bgG3d = new ht.graph3d.Graph3dView()
                bgG3d.deserialize(bgJSON)
                bgG3d.addToDOM()
                graphView.addToDOM(bgG3d.getView())
            }
            graphView.handleScroll = function () { }
        }
 })

模拟风速:每隔30s,随机产生一个值,当做风速值。

相关伪代码

// 模拟风速
mockWindSpeed() {
  return 8 + Math.random() * 12
}

数据统计:每隔30s,随机变换。

效果:

相关伪代码

// 指针和扇叶旋转的角度 进行变化
var oldPointerValue = pitchSystem.a(‘pointer‘) || 0
// 风机扇叶和变桨系统的旋转角度
var newRotateAngular = (this.windSpeed - 8) * 7.5 * translateAngularRadian.radian
var addPointerValue = newRotateAngular - oldPointerValue

var oldWindSpeedClip = environmentalData.a(‘windSpeedClip‘) || 0
var newWindSpeedClip = (this.windSpeed - 8) / 12
var addWindSpeedClip = newWindSpeedClip - oldWindSpeedClip

var anim = {
  duration: 1e3,
  easing: (v) => {
    return v * v
   },
  action: (v) => {
    var windSpeed = Number(this.windSpeed.toFixed(2))
    var Max = Number(MaxValue.toFixed(2))
    var average = Number(Aver.toFixed(2))
    var windSpeedClip = oldWindSpeedClip + (addWindSpeedClip * v)
    // 设置发电参数随机数据
     generator.a({ windSpeed })
    // 设置环境监测随机数据
    environmentalData.a({ windSpeed, windSpeedClip })
    // 设置统计参数随机数据
    statisticalParam.a({ average, Max, windSpeed })
    // 设置变航系统的指针角度
    pitchSystem.a(‘pointer‘, oldPointerValue + (addPointerValue * v))
  }
}
ht.Default.startAnim(anim)

这里涉及到角度和弧度的转换。1° = Math.PI / 180°,1rad = 180° / Math.PI,因为场景中使用的是弧度制,所以需要把随机出的角度值转换成弧度。

这里解释下代码,先获取到当前的值。然后在加上 随机值 - 当前值。比如当前值为 16,随机出的数值有两种情况,1:比当前值大。2:比当前值小。

如果比当前值大的话,比如18,那么就是这样 16 + (18 - 16) * v ( easing 函数运算后的值)

如果比当前值小的话,比如13,那么就是这样 16 + (13 - 16) * v ( easing 函数运算后的值)

这样当随机的时候,就会从当前值平滑的改变到目标值。

数据统计:每隔30s,监测当前风机的故障信息。

效果:

这里使用了 table.json 文件,通过修改 ht.dataSource 属性添加实时信息。

相关伪代码

var checkInternals = () => {
  /**
   * 故障信息
   * 变桨系统 主轴 偏航系统 齿轮箱 油冷装置 发电机 风冷装置
   */
    var FailureStatus = {
        // 正常状态
        status1: new Map([
            [0, [‘舱内温度正常,变桨角度正常。‘, ‘i10‘]],
            [1, [‘舱内温度正常,主轴转速正常。‘, ‘i9‘]],
            [2, [‘偏航系统精确。‘, ‘i8‘]],
            [3, [‘齿轮箱温度正常。‘, ‘i1‘]],
            [4, [‘油冷装置温控表正常。‘, ‘i3‘]],
            [5, [‘发电机功率正常。‘, ‘i5‘]],
            [6, [‘风冷装置正常。‘, ‘i2‘]]
        ]),

        // 异常状态
        status2: new Map([
            [0, [‘变桨角度异常。‘, ‘i10‘]],
            [1, [‘主轴转速偏高。‘, ‘i9‘]],
            [2, [‘偏航系统出现偏移。‘, ‘i8‘]],
            [3, [‘齿轮箱温度偏高。‘, ‘i1‘]],
            [4, [‘油冷装置内积尘过多。‘, ‘i3‘]],
            [5, [‘发电机电流过大。‘, ‘i5‘]],
            [6, [‘风冷装置散热不足。‘, ‘i2‘]]
        ]),
    }

    // 返回设备正常的状况 status 1: 正常 2: 不正常
    var mockQquipmentFailure = (status) => {
        var { rangeRandom } = common
        var index = rangeRandom(7)

        // 返回随机出来的设备情况
        return FailureStatus[`status${status}`].get(index)
    }

      var info = randomInfo[0]
      var targetTag = randomInfo[1]

      this.tableArr = table.a(‘ht.dataSource‘)
      var currentTimeFormat = DateUtil.formatHourTime(new Date())

  // 默认是正常 如果找到故障关键字的话 赋值为 异常
  var status = ‘normal‘
  var time = 0
 this.tableArr.push({ status, info, time: currentTimeFormat })
}

我们需要两个 Map 数组方便进行取值操作。一个是正常信息数组,一个是异常信息数组。利用随机值当做一个索引,然后取到相对应的状态信息,添加到 table 中。

如果当前的 status 为 normal,说明是正常信息,否则为异常信息。异常信息的话就可以通过 table.json 的渲染回调函数 "drawCell": function(g, text, rect, option) { } 来修改它的颜色,使其高亮。

偏航系统:风机转动的过程中,随着风的位置的不同,通过偏航系统改变方向。

效果:

  

相关伪代码

/**
  * 随机偏航系统
  * @param { * }
  */
  randomYawSystem() {
    var { dm } = this
    var { d2d } = window
    var { rangeRandom } = common

    var poll = () => {
       // 随机数 30 - 50
        var random = 30 + rangeRandom(20)
        var cabin = dm.getDataByTag(‘cabin‘)

        // 将角度度换算成弧度 然后乘以随机数 实现随机风向
        var randomDegrees = translateAngularRadian.radian * random
        var defaultDegress = translateAngularRadian.radian * 180

         ht.Default.startAnim({
           duration: 1e3,
           action: (v) => {
             var oldValue = cabin.getRotationY()
             var newValue = randomDegrees
             var addValue = newValue - oldValue

           cabin.setRotationY(oldValue + addValue * v)
         }
      })
    } }

上面讲到过角度弧度转换,这里先将随机出的角度转换成弧度,然后赋值,进行旋转。

变桨系统:风速的变化影响风机扇叶的角度。

效果:

相关伪代码:

var old3Value = whiteShell3Line.getRotationX()
var old4Value = whiteShell4Line.getRotationX()
var old5Value = whiteShell5Line.getRotationX()

// 指针和扇叶旋转的角度 进行变化
var oldPointerValue = pitchSystem.a(‘pointer‘) || 0
// 风机扇叶和变桨系统的旋转角度
var newRotateAngular = (this.windSpeed - 8) * 7.5 * translateAngularRadian.radian
var addPointerValue = newRotateAngular - oldPointerValue

whiteShell3Line.setRotationX(old3Value + ((newRotateAngular - oldPointerValue)))
whiteShell4Line.setRotationX(old4Value + ((newRotateAngular - oldPointerValue)))
whiteShell5Line.setRotationX(old5Value + ((newRotateAngular - oldPointerValue)))

先获取到每个扇叶当前的 X 轴旋转值,再获取到需要旋转的角度值,进行赋值。

风机启停:风机的启动和停止

相关伪代码:

var fanWireframe = d3d.getDataByTag(‘fanWireframe‘)
fanWireframe.setRotationMode(‘zxy‘)
this.allAnimManage = new Map([[‘fanRotate‘, null]])
var fanRotating = (easeType) => {
  anim = ht.Default.startAnim({
    duration: 5e3,
    easing: (t) => easeIn(t),
    action: (v) => {
      fanWireframe.setRotationZ(fanWireframe.getRotationZ() + speed)

        // 风机轮毂旋转
        if (fanWireframe.getRotationZ() <= -6.28) {
          fanWireframe.setRotationZ(0)
        }

        // 风机扇叶 uv 偏移
        for (let i = 1; i < 17; i++) {
          var node = d3d.getDataByTag(`q${i}`)
          node.s(‘shape3d.uv.offset‘, fanOffsetData(v)[i - 1])
        }

        // 暂停命令
        if (isStop) {
          stopFanRotate(fanWireframe.getRotationZ())
          anim.pause()
          anim = null
        }
    },
      finishFunc: () => {
        fanRotating(false)
      }
    })

    this.allAnimManage.set(‘fanRotate‘, anim)
}

因为可以启动和停止,那么我们就可以通过控制 ht.Default.startAnim() 的返回对象的 resume 和 pause 来达到效果。

所以我把风机旋转的动画添加到了全局对象中,方便进行调用。

setRotationMode(‘zxy‘) 方法是设置三维旋转模式,顺序是 z -> x -> y,先进行z轴旋转,再进行x轴旋转,最后进行y轴旋转。设置目的是为了避免坐标轴受外部旋转的影响。

风向: 根据风的角度,判断当前是什么位置的风。

 效果:

相关伪代码:

// 判断风向
var windDirection = (rotate) => {
    let direction

    switch (true) {
    case rotate === 0:
        direction = ‘南‘
        break
    case rotate === 90:
        direction = ‘东‘
        break
    case rotate === 180:
        direction = ‘北‘
        break
    case rotate === 240:
        direction = ‘西‘
        break
    case rotate > 0 && rotate < 90:
        direction = ‘东南‘
        break
    case rotate > 90 && rotate < 180:
        direction = ‘东北‘
        break
    case rotate > 180 && rotate < 270:
        direction = ‘西北‘
        break
    case rotate > 270 && rotate < 360:
        direction = ‘西南‘
        break
    default:
        direction = ‘没有找到风向‘
    }

    return direction
}
// 判断是哪个方向
var angular = randomDegrees * translateAngularRadian.angular
var direction = windDirection(angular)

将罗盘的指针角度放到 switch 进行判断,如果找到对应的风向就返回。

总结

风力发电是一个工业互联网的典型例子,我们可以通过对风机模型或者监测数据进行分析,可以减轻我们工作复杂程度,帮助我们快速了解发电内部结构及发电功能。

HT 能做的东西远远不止于此,这需要我们丰富的想象力以及自身过硬的技术。我希望可以通过这篇文章向大家传递一种能量,让大家更有兴趣、迸发更多新鲜的想法,去做更多好玩的东西。

原文地址:https://www.cnblogs.com/xhload3d/p/12306412.html

时间: 2024-08-02 19:49:00

基于 H5与WebGL 的科幻风机 3D 展示的相关文章

基于 H5 和 webGL 的 3D 智慧城市

前言 中共中央.国务院在今年12月印发了<长江三角洲区域一体化发展规划纲要>(下文简称<纲要>),并发出通知,要求各地区各部门结合实际认真贯彻落实. <纲要>强调,要提升基础设施互联互通水平,打造数字长三角,协同建设新一代信息基础设施,共同推动重点领域智慧应用.大力发展基于物联网.大数据.人工智能的专业化服务,提升各领域融合发展.信息化协同和精细化管理水平.围绕城市公共管理.公共服务.公共安全等领域,支持有条件的城市建设基于人工智能和 5G 物联的城市大脑集群. 城市治

基于H5与webGL的 3d 电子围栏展示

前言 现代工业化的推进在极大加速现代化进程的同时也带来的相应的安全隐患,在传统的可视化监控领域,一般都是基于 Web SCADA 的前端技术来实现 2D 可视化监控,本系统采用 Hightopo 的 HT for Web 产品来构造轻量化的 3D 可视化场景,该 3D 场景从正面展示了一个现代化工厂的现实场景,包括工厂工人的实时位置.电子围栏的范围.现场的安全情况等等,帮助我们直观的了解当前工厂人员的安全状况. 本篇文章通过对工厂可视化场景的搭建和模型的加载,人物实时定位代码的实现.电子围栏和轨

基于 H5与webGL 的低碳工业园区监控系统

前言 低碳工业园区的建设与推广是我国推进工业低碳转型的重要举措,低碳工业园区能源与碳排放管控平台是低碳工业园区建设的关键环节.如何对园区内的企业的能源量进行采集.计量.碳排放核算,如何对能源消耗和碳排放进行实时动态监测等问题,涉及多个技术领域,专业性强.其数据不仅要求准确,更要求真实可靠(即可核查.可溯源).这是低碳工业园区“管控平台”建设的核心任务,也是当前我国工业园区建设中需要迫切解决的主要问题之一. http://www.hightopo.com/demo/HTBuilding/index

基于HTML5的WebGL呈现A星算法的3D可视化

http://www.hightopo.com/demo/astar/astar.html 最近搞个游戏遇到最短路径的常规游戏问题,一时起兴基于HT for Web写了个A*算法的WebGL 3D呈现,算法基于开源 https://github.com/bgrins/javascript-astar 的javascript实现,其实作者也有个不错的2D例子实现 http://www.briangrinstead.com/files/astar/ ,只不过觉得所有A*算法的可视化实现都是平面的不够

基于H5的微信支付开发详解

这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可供参考,有的朋友直接看文档就可以自己实现此支付接口的开发了. 一.前言 为何我还写一篇微信支付接口的博文呢?第一,我们必须知道,所谓的工作经验很多都是靠总结出来的,你只有总结了更多知识,积累了更多经验,你才能在该行业中脱颖而出,我个人觉得如今的招聘,很多都需要工作经验(1年.3年.5年....),其

****基于H5的微信支付开发详解[转]

这次总结一下用户在微信内打开网页时,可以调用微信支付完成下单功能的模块开发,也就是在微信内的H5页面通过jsApi接口实现支付功能.当然了,微信官网上的微信支付开发文档也讲解的很详细,并且有实现代码可供参考,有的朋友直接看文档就可以自己实现此支付接口的开发了. 一.前言 为何我还写一篇微信支付接口的博文呢?第一,我们必须知道,所谓的工作经验很多都是靠总结出来的,你只有总结了更多知识,积累了更多经验,你才能在该行业中脱颖而出,我个人觉得如今的招聘,很多都需要工作经验(1年.3年.5年....),其

基于h5的图片无刷新上传(uploadifive)

基于h5的图片无刷新上传(uploadifive) uploadifive简介 了解uploadify之前,首先了解来一下什么是uploadify,uploadfy官网,uploadify和uploadifive是一家的,他们都是基于jquery的插件,都支持多文件异步上传,支持显示上传进度,不同的是uploadify基于swfUpload这一开源无刷新上传插件开发,基于flash,而uploadifive则是基于html5,不依赖于flash. 基于他们的不同点,我们可以根据自己的需求来进行选

WebGL是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起

WebGL是一种3D绘图标准,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化. 显然,WebGL技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂3D结构的网站页面,甚至可以用来设计3D网页游戏等等.

[WebGL入门]三,3D绘图的基础知识

注:文章译自http://wgld.org/,原作者杉本雅広(doxas),文章中如果有我的额外说明,我会加上[lufy:],另外,鄙人webgl研究还不够深入,一些专业词语,如果翻译有误,欢迎大家指正. 二维和三维 三维空间--我们生活这个这个现实的世界就是一个三维空间. 在三维的世界里,所有的东西都由横,竖,深度.将这些东西重现,就是一个实时3D渲染.但是再现这个3D空间,我们是在一个2D的显示器上来实现的. 电脑和手机的屏幕,都是一个2D的显示器.至少现在还没有一个3D的显示设备,当然,研