前言

今天找到了 HT 的官网里的 Demo 网站( http://www.hightopo.com/demos/index.html ),看的我眼花缭乱,目不暇接。 而且 HT 的用户手册,将例子和文档无缝融合一体,小小 10 来兆开发包居然包含了四十五份手册,数百个活生生的 HTML5 例子,还没体验过的朋友赶紧来看一看,这回可玩嗨了!

对于 HT 初学者,面对这一堆数百个涵括通用组件、网络拓扑图组件、3D 组件、矢量图形、各种编辑器等等五法八门的 HTML5 例子盛宴,往往无从下手。为此,老郑我打算为像我一样喜欢这方面的新手朋友多写几篇这样的博客,慢慢的给大家讲述各种各样的越来越多的有趣的小功能!

效果图

( https://hightopo.com/demo/CabinetAnimat/ )

代码实现

HT 提供了基于 WebGL 的 3D 技术的图形组件 ht.graph3d.Graph3dView,WebGL 基于 OpenGL ES 2.0 图形接口,因此 WebGL 属于底层的图形 API 接口,二次开发还是有很高的门槛,HT 的 Graph3dView 组件通过对 WebGL 底层技术的封装,与 HT 其他组件一样,基于 HT 统一的 DataModel 数据模型来驱动图形显示,极大降低了 3D 图形技术开发的门槛。同时 HT 提供了强大的完全基于 HTML5 技术 3D 图形建模设计器,用户无需编码即可快速可视化搭建各种 3D 场景,可以说 HT 的 3D 开发模式完全打破了传统 3D 开发模式,绝大部分应用不再需要依赖精通 3ds Max 或 Maya 的专业 3D 设计师来建模,也不需要整合 Unity3d 等引擎做图形渲染,HT 一站式的提供了从建模到渲染,包括和 2D 组件呈现和数据融合的一站式解决方案。

我本次讲解的就是这个 3D 的界面,所以我们首先要创建 3D 渲染引擎组件,可视化呈现数据模型的三维环境场景。

var dm = new ht.DataModel()
var g3d = new ht.graph3d.Graph3dView(dm)

我们还要设置眼睛(或Camera)所在位置以及中心点(目标)的位置,格式均为 [x, y, z] 。

g3d.setEye([-376, 270, 896])
g3d.setCenter([-16, 118, -186])

这里给大家说一下,可参考 3D 手册( http://www.hightopo.com/guide/guide/core/3d/ht-3d-guide.html )。如上图所示,透视投影最终显示到屏幕上的内容只有截头锥体 ( View Frustum ) 部分的内容, 因此 Graph3dView 提供了 eye ,center , up ,far ,near ,fovy 和 aspect 参数来控制截头锥体的具体范围:

  • getEye() | setEye([x, y, z]) ,决定眼睛(或 Camera )所在位置,默认值为 [0, 300, 1000]
  • getCenter() | setCenter([x, y, z]) ,决定目标中心点(或 Target )所在位置,默认值为 [0, 0, 0]
  • getUp() | setUp([x, y, z]) ,决定摄像头正上方向,该参数一般较少改动,默认值为 [0, 1, 0]
  • getNear() | setNear(near) ,决定近端截面位置,默认值为 10
  • getFar() | setFar(far) ,决定远端截面位置,默认值为 10000
  • getFovy() | setFovy(fovy) ,fovy 决定垂直方向的视觉张角弧度,默认值为 Math.PI/4
  • getAspect() | setAspect(aspect) ,决定截头锥体的宽高比,该参数默认自动根据屏幕的宽高比决定,一般不需要设置。

然后我们再给它加上一些选中效果。Graph3dView 中被选中的图元会显示为较暗的状态,变暗系数是由图元 style 的 brightness 和 select.brightness 属性决定,select.brightness 属性默认值为 0.7,最终返回值大于 1 变亮,小于 1 变暗,等于 1 或为空则不变化。Graph3dView#getBrightness 函数控制最终图元亮度,因此也可以通过重载覆盖该函数自定义选中图元亮度。

g3d.getBrightness = function (data) {
  if (data.s('isFocused')) {
  return 0.7;
}
  return null;
};
lastFocusData = null;
g3d.getView().addEventListener('mousemove', function (e) {
  // 传入逻辑坐标点或者交互 event 事件参数,返回当前点下的图元
var data = g3d.getDataAt(e);
if (data !== lastFocusData) {
  if (lastFocusData) {
  astFocusData.s('isFocused', false);
}
if (data) {
data.s('isFocused', true);
}
astFocusData = data;
  }
});

接下来我们要为这些零件设置吸附:

dm.getDataByTag('机柜').setHost(dm.getDataByTag('地板'))
dm.getDataByTag('设备').setHost(dm.getDataByTag('机柜'))
dm.getDataByTag('门').setHost(dm.getDataByTag('机柜'))
...

吸附功能对于设计有层次关系的模型非常方便,例如设备面板吸附上设备机框,设备端口吸附上设备面板,这样从机框 - 面板 - 端口的层次关系吸附,使得用户拖动整体机框时所有这个层次下的图元都会跟随移动。对于 3D 的场景下,吸附的概念更进一步延伸,当机框在三维空间进行任意位置偏移以及任意角度旋转时,所有吸附的相关图元都会正确的跟随平移,并做出相应位置对应的旋转,以达到整体设备各个图形部分保持物理相对位置一致。简单来说就是当图元吸附上宿主图元时,宿主移动或旋转时会带动所有吸附者。

  • Node#getHost() 和 Node#setHost(node) 获取和设置吸附的图元对象
  • Node#getAttaches() 返回目前吸附到该图元的所有对象,返回 ht.List 链表对象,无吸附对象时返回空
  • Node#isHostOn(node) 判断该图元是否吸附到指定图元对象上
  • Node#isLoopedHostOn(node) 判断该图元是否与指定图元相互形成环状吸附,例如 A 吸附 B ,B 吸附 C,C 又吸附回 A,则 A,B 和 C 图元相互环状吸附

因为我这里是有 6 个设备,我要把每一个都给一个属性值来记录变化的状态一会儿用到:

dm.getDataByTag('门').a('open', false)
for (var i = 1; i < 7; i++) {
  dm.getDataByTag('设备' + i).a('open', false)
}

上一篇关于 SCADA 组态电机的随笔里面咱们已经用到过动画,这回让我们通过事件监听在双击它的时候来为其加上动画效果:

// 监听事件
g3d.mi(function (event) {
  if (event.kind === 'doubleClickData') {
    var tag = event.data.getTag()
    if (tag === '门') {
      if (anim) {
        anim.stop(true)
      }
      //获取旋转角度
      var oldAngles = event.data.getRotation(),
         angles = (open ? 2 : -2)
      //启动动画
      anim = ht.Default.startAnim({
        action : function(t) {
          event.data.setRotation(oldAngles + t * angles)
        },
      })
      open = !open
    }
    //检测字符串是否以指定的前缀开始
    else if (tag.startsWith('设备')) {
      //设备动画函数
      animation(event.data)
    }
  }
}

设备动画的函数在这里:

function animation(data) {
  //设置每个设备依次的变化参数
  var v
  for (var i = 1; i < 7; i++) {
    if (tag === '设备'+ i) {
    v= i / 2
    }
  }
  if (data.anim) {
    data.anim.stop(true)
    data.anim = null
  }
  var open = data.a('open'),
    p3 = data.p3(),
    s3 = data.s3()
  if (open) {
    data.anim = ht.Default.startAnim({
      action : function(t) {
        data.p3(p3[0], p3[1], p3[2] + t * -s3[2] * v)
      }
    })
    data.a('open', false)
  }
  else {
    data.anim = ht.Default.startAnim({
      action : function(t) {
        data.p3(p3[0], p3[1], p3[2] + t * s3[2] * v)
      }
    })
    data.a('open', true)
  }
}

这里面有一些简写跟大伙儿说下。比如 mi 是增加交互事件监听器,addInteractorListener 的缩写,另外 event 格式有:

  • kind: 'clickData', // 事件类型
  • data: data, // 事件相关的数据元素
  • part: "part", // 事件的区域, icon 、label 等
  • event: e // html 原生事件

同时还有 3D 的一些:

  • setPosition3d(x, y, z) | setPosition3d([x, y, z]) 可简写为 p3(x, y, z) | p3([x, y, z])
  • getPosition3d() 可简写为 p3()
  • setSize3d(x, y, z) | setSize3d([x, y, z]) 可简写为 s3(x, y, z) | s3([x, y, z])
  • getSize3d() 可简写为 s3()
  • setRotation3d(x, y, z) | setRotation3d([x, y, z]) 可简写为 r3(x, y, z) | r3([x, y, z])
  • getRotation3d() 可简写为 r3()

建议熟记常用函数简写可提高编码效率,可参考入门手册中函数简写( http://www.hightopo.com/guide/guide/core/beginners/ht-beginners-guide.html )。最后别忘记 g3d.addToDOM() 呦!嘿嘿~~~

总结

这个小 demo 就说到这里吧,我会不定期的写一些技术随笔,既帮助自己整理知识,也能够跟大家一起学习,我们由浅至深,循序渐进。希望看了我的文章能得你们带来帮助,同时也希望大家能多多支持和鼓励!

基于 HTML5 Canvas 的 3D 渲染引擎构建机架式服务器的更多相关文章

  1. 基于 HTML5 Canvas 的 3D 渲染引擎构建生产管控系统

    前言 大家好,老郑我又回来了.这一期为大家带来一个非常好玩的 demo,我们制作一套自己的 3D 管道控制系统,运用了( http://www.hightopo.com )HT 的 Graph3dVi ...

  2. 基于 HTML5 Canvas 的 3D 机房创建

    对于 3D 机房来说,监控已经不是什么难事,不同的人有不同的做法,今天试着用 HT 写了一个基于 HTML5 的机房,发现果然 HT 简单好用.本例是将灯光.雾化以及 eye 的最大最小距离等等功能在 ...

  3. 基于 HTML5 Canvas 的 3D WebGL 机房创建

    对于 3D 机房来说,监控已经不是什么难事,不同的人有不同的做法,今天试着用 HT 写了一个基于 HTML5 的机房,发现果然 HT 简单好用.本例是将灯光.雾化以及 eye 的最大最小距离等等功能在 ...

  4. 基于 HTML5 Canvas 的 3D 热力云图效果

    前言 数据蕴藏价值,但数据的价值需要用 IT 技术去发现.探索,可视化可以帮助人更好的去分析数据,信息的质量很大程度上依赖于其呈现方式.在数据分析上,热力图无疑是一种很好的方式.在很多行业中都有着广泛 ...

  5. 基于 HTML5 Canvas 的 3D 模型贴图问题

    之前注意到的一个例子,但是一直没有沉下心来看这个例子到底有什么优点,总觉得就是一个 list 列表,也不知道右边的 3d 场景放两个节点是要干嘛,今天突然想起来就仔细地看了一下这个例子的代码,实际操作 ...

  6. 基于 HTML5 Canvas 的 3D 模型列表贴图

    少量图片对于我们赋值是没有什么难度,但是如果图片的量大的话,我们肯定希望能很直接地显示在界面上供我们使用,再就是排放的位置等等,这些都需要比较直观的操作,在实际应用中会让我们省很多力以及时间.下面这个 ...

  7. 基于 HTML5 Canvas 的 3D 碰撞检测

    这是公司大神写的一个放官网上给用户学习的例子,我一开始真的不知道这是在干嘛,就只是将三个形状图元组合在一起,然后可以同时旋转.放大缩小这个三个图形,点击"Animate"就能让中间 ...

  8. 基于HTML5 Canvas的3D动态Chart图表

    发现现在工业SCADA上或者电信网管方面用图表的特别多,虽然绝大部分人在图表制作方面用的是echarts,他确实好用,但是有些时候我们不能调用别的插件,这个时候就得自己写这些美丽的图表了,然而图表轻易 ...

  9. 基于 HTML5 Canvas 的 3D 压力器反序列化

    在实际应用中,我觉得能够通过操作 JSON 文件来操作 3D 上的场景变化是非常方便的一件事,尤其是在做编辑器进行拖拽图元并且在图元上产生的一系列变化的时候,都能将数据很直观地反应给我们,这边我们简单 ...

随机推荐

  1. 安装 Python IDLE (Linux)

    Python IDLE (Integrated Development and Learning Environment) 是一个官方的轻量级 Python IDE.在不同的 Linux 的发布版本中 ...

  2. FileWriter与BufferedWriter的适用场景

    IO这块,各种Writer,Reader,让人眼晕 而在网上基本找不到在什么时候用哪个类,并且网上的IO demo 很多用法都是错的 在这简单的分析一下FileWriter与BufferedWrite ...

  3. is invalid; nested exception is org.xml.sax.SAXParseException: cvc-complex-type.2.4.c:严格输入了匹配通配符,但还是找不到元素“jee:jndi-lookup”的声明。

    由于未添加xsd声明引起

  4. Sqlserver函数基础使用

    函数基本功能: 转换工厂日期,将8点20之前的时间转化为前一天的时间. if exists (select * from sysobjects where xtype='fn' and name='F ...

  5. strncpy()函数【转】

    C/C++中的strncpy()函数功能为将第source串的前n个字符拷贝到destination串,原型为: char * strncpy ( char * destination, const ...

  6. webbench 网站压力测试

    [root@localhost ~]# webbench -c 500 -t 4 http://172.24.61.41/Webbench - Simple Web Benchmark 1.5Copy ...

  7. IOS Singleton(单例)

    Singleton.h // .h #define singleton_interface(class) + (instancetype)shared##class; // .m #define si ...

  8. PhoneGap的通知

    一.通知类型列表 1.notification.alert         提示警告框 2.notification.confirm                  确认对话框 3.notifica ...

  9. BZOJ2223/3524:[POI2014] Couriers(主席树)

    Description 给一个长度为n的序列a.1≤a[i]≤n. m组询问,每次询问一个区间[l,r],是否存在一个数在[l,r]中出现的次数大于(r-l+1)/2.如果存在,输出这个数,否则输出0 ...

  10. BZOJ1014:[JSOI2008]火星人(Splay,hash)

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam, 我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 ...