HTML5,不仅是看上去很美(第二弹:打造最美3D机房)

前言

最近项目开发任务告一段落,恰好有时间整理这大半年的一些成果。使用html5时间还不久,对js的认识还不够深刻。没办法,之前一直搞java,对js的一些语言特性和概念一时还转换不过来。html

上一篇第一弹介绍了项目中作的一个彩虹爆炸图,主要用了 html5的canvas的2d绘制技术。这一回我想介绍一下项目中的一个亮点技术:html5的3D,以及如何用它打造精美的3D机房监控系统。前端

------------------------10月27日更新-----------------------------
没想到这篇的点击率这么高,感谢你们给予的厚爱。
受到你们的启发和鼓励,这个3D机房系列已经有了长足的进步。
补上后续两篇的传送门:
第二季:场景和功能的丰富,包括机柜、设备、走线、路径规划等功能
第三季:功能的进一步丰富,包括资产管理,动环监控等的可视化管理html5

另外,录了两个视频,懒得看长文的朋友能够直接戳:
http://v.youku.com/v_show/id_...
http://v.youku.com/v_show/id_...java

插播一则广告(长期有效)

MONO哥须要在武汉招JavaScript工程师若干
要求:对前端技术(JavasScript、HTML、CSS),对可视化技术(Canvas、WebGL)有浓厚的兴趣
基础很差的可培养,基础好的可共谋大事
感兴趣的给我发邮件:hr@servasoft.com程序员

目标效果图

下图是领导给找的一张的效果参考图,客户但愿机房至少能达到下面的3D效果。
图片描述
懂的人都知道,这但是一张设计公司出的装修效果图啊,就算是用max建模,也须要大量的工做,况且咱但是程序员在作数据中心的可视化项目啊。。。强忍心中奔腾的万千头**马,静下心来思考,那就先从搭建一个webGL的场景开始吧。web

WebGL基本场景搭建

在html5里面使用3D已经不是什么高深技术,它的基础是WebGL,一个OpenGL的浏览器子集,支持大部分主要3D功能接口。目前最新的浏览器都有比较好的支持,IE须要到11(是的,你没有看错)。chrome

要检测你的浏览器是否支持webGL,可直接访问网页http://get.webgl.org/ 看是否能看到一个旋转的立方体。若是能看到,说明你的浏览器支持webgGL,不然,能够下一个最新的chrome试试吧。相对来讲chrome对webGL的支持最好,效率也很优秀。数据库

要在浏览器里面使用webGL,就要研究webGL相关的技术和用法。作3D应用并非一件轻松的事。就算最简单的搭建一下webGL场景,也须要下面这些代码:json

var width = window.innerWidth;  
var height= window.innerHeight;  
var container = document.createElement( 'div' );  
document.body.appendChild( container );  
var webglcanvas = document.createElement('canvas');               
container.appendChild(webglcanvas);   
var gl = webglcanvas.getContext("experimental-webgl");                

function updateFrame () {             
  gl.viewport ( 0, 0, width, height );  
        gl.clearColor(0.4, 0.4, 0.7, 1);  
        gl.clear ( gl.COLOR_BUFFER_BIT );       
         setTimeout(   
    function(){updateFrame()},  
            20);  
     }  

setTimeout(   
  function(){
    updateFrame();
  },  
20);

和html同样,须要先建立一个canvas元素,并得到其webgl上下文:canvas

var gl = webglcanvas.getContext("experimental-webgl");

而后在一个updateFrame的函数中,像html5的2D context同样,去绘制3D的内容。

另外,要再起一个死循环,每隔**毫秒调用一次这个updateFrame函数来重绘场景。和2D不一样,3D场景里面的变化是随时随地的,因此须要不停刷新,就像播放电影或视频,静止不动的画面基本没有,因此死循环刷新基本是必要的。不过实际项目使用中会有不少优化,尽可能作到“按需刷新”,节省cpu和移动设备电量。有感兴趣的同窗,哥能够单独写文章介绍。这段程序基本上什么也没作,就画了一个静止不动的区域,以下图:

图片描述

虽然看不见任何3D的内容,不过它已是一个最简单的webgl程序了。咱们的3D机房,也就是在这上面不断丰富而已。

对象封装

要作项目,搭建下去工做量太大了,时间周期也不容许。使用第三方辅助工具是不可避免的,像Three.js, twaver.js都是选择。这些工具均可以提供3D的基本对象和各类特效,固然这都不是最主要的,主要是如何利用它作出我想要的效果:好看。为了不大量修改代码,在项目里作了一些封装,即把原始3D的立方体等对象进行进一步封装,让一个json数据就能够提供这些对象的定义。这样使用起来就比较方便了。json大体结构以下:

var json={    
objects: [{
    name: '地板',
    …
},{
…
}],
}

下面咱们逐一来看这些3D对象是怎么进行美化的,过程可能稍显啰嗦,跬步千里,此次的基础打好了,之后的项目就手到擒来了。

地板和斜坡

第一个要作的,也是应该比较简单的,就是地板对象。3D中,地板应该是一个有些厚度、带上格子贴图的薄薄立方体平面。所以我对通过封装的立方体对象,用一段json对象定义以下:

{
    name: '地板',
    type: 'cube',
    width: 1600,
    height: 10,
    depth: 1300,
        
    style: {
        'm.color': '#BEC9BE',
        'm.ambient': '#BEC9BE',
    }
}

经过定义,建立了一个13米*16米的地板块,这也是客户小型机房的实际尺寸:
图片描述

看起来有那么点意思,就是颜色还不够,须要找一个地板砖纹理图。须要注意的是,纹理图的尺寸都须要是宽和高都是2的幂,例如128x12八、256*256等,这样出来效果才会好。这也是3D软件通常所要求的。另外纹理要能连续拼接不露破绽,这样才好。例以下面我google出来的图:
图片描述

在style里面添加:

'top.m.texture.image': 'images/floor.png',
   'top.m.texture.repeat': new mono.Vec2(10,10),

效果以下:
图片描述

有图片材质纹理,效果果真好多了。忽然想到客户说,他们机房底面有一个方便运送设备的斜坡,必需要画出来。这……(╯-_-)╯

后来想到twaver里面的对象能够支持运算,好比能够定义一个斜的立方体,让地板剪掉立方体,就能够作到。因而继续定义json:

{
    name: '地板切坡',
    type: 'cube',
    width: 200,
    height: 20,
    depth: 260,
    translate: [-348,0,530],
    rotate: [Math.PI/180*3, 0, 0],
    op: '-',
    style: {
        …,
    }
}

这里定义的一个倾斜的立方体,经过translate定义位置,rotate定义旋转角度,而后再经过op定义运算符,这里是“减去”,就用“-”表示。被剪掉的立方体也能够设置材质、纹理、贴图、颜色…等等,和地板同样。看看效果:
图片描述

第一步总算是有惊无险地搞定了。

走廊桌

下一步找了个简单的对象,按要求走廊要放一个接待桌。为了简单,我决定就偷懒作一个立方体表示。

{
    name: '走廊板凳',
    type: 'cube',
    width: 300,
    height: 50,
    depth: 100,
    translate: [350, 0, -500],
}

效果以下:
图片描述

这里偷懒实际上是有缘由的。在3D里,最重视的就是效率,千万不要放一些很复杂的模型,尤为是这类非业务对象。就像这个桌子,尽管只是个简单的立方体,但只要和总体风格协调一致,再增长一点配色并启动阴影效果后,看着就好多了:
图片描述

墙体

墙体是机房里很重要的一个部分,有好的光照、阴影的效果才能看起来更加逼真。因为墙体是不规则的路径,一段一段去生成还真挺麻烦的,还好引擎支持这种物体,甚至曲线路径均可以。这里只要在json里面定义一组数字的坐标,让这些数字依次链接,组成一个墙体,最后生成3D对象放入场景中就行啦。

json定义以下:

{
    name: '主墙体',
    type: 'path',
    width: 20,
    height: 200,
    translate: [-500, 0, -500],
    data:[
        [0, 0],
        [1000, 0],
        [1000, 500],
        [500, 500],
        [500, 1000],
        [0, 1000],
        [0,0],
    ],
}

注意这里的类型变成了pathdata中定义了一个二维坐标数组来描述墙体。因为墙都是从底面开始的,因此只定义它的平面的x、y坐标就好了。看看效果:

图片描述

不过如前文所说,仍是须要上色、上阴影,才能有更好的效果。这里咱们启用阴影并咨询设计师美眉几个颜色值,加上去后再看下效果:
图片描述

以及一些细节:
图片描述

看着雪白的墙,是否是以为少了点什么?对,就是门。在3D机房的监控系统里,门禁是很重要的一块,客户要求门应该与实际位置相对应,而且要有开门关门的动画效果。这样,实际的门禁信息采集上来后,就能在界面实时看到门的状态了。

这里,考虑到门若是直接放上去,会被墙盖住;若是比墙厚,又难看不符合实际。仍是应该先定义一个门洞立方体,把门所在的位置挖掉:

{
    name: '门洞',
    type: 'cube',
    width: 195,
    height: 170,
    depth: 30,
    op: '-',
    translate:[-350,2,500],
}

恰好挖在斜坡的位置,这样设备进屋就方便了:

图片描述

不过这门没有一个门框,感受不太生动。多一个门框会感受立体感强一些。门框能够是一个比门洞略大的立方体,在挖门洞以前添加:

{
    name: '门框',
    type: 'cube',
    width: 205,
    height: 180,
    depth: 26,
    translate: [-350, 0, 500],
    op: '+',
}

加上阴影和光线等综合效果后,还不错,挺有档次的。

图片描述

来张全景图看看:
图片描述

接着,只要把门安上去就好了。门的定义比较简单,就是一个薄的立方体。不过为了作到玻璃效果,须要设置透明度,让它看上去更像一个玻璃,再让设计师美眉弄一张好看一点的门的图,贴上去。尽管有了webGL,复杂的建模工做能够省略了,不过设计师美眉的配合仍然很重要。
先作左边的门:

{
    name: '左门',
    type: 'cube',
    width: 93,
    height: 165,
    depth: 2,
    translate:[-397,4,500],
    style:{
        'm.transparent': true,
        'm.texture.image': 'images/door_left.png',                    
    }

上面增长的style主要透明和贴图两项。看看效果:

图片描述

一样的方法,再把右侧门贴上就搞定了。为了增长体验,也是用户的要求,门上面设置了动画:双击能够自动打开,再双击能够直接关闭。动画功能引擎作好了封装,在json中直接指定动画类型就好了。不过要注意左右门的动画旋转方向要相反,要否则一个向里开一个向外开感受比较怪异。

图片描述

项目中,窗自己不须要有任何业务属性,可是美观度的要求可一点都不能少。方法和门相似,先放窗框后挖窗体。不过为了有点变化,这里不作窗框了,作一个窗台,方法和道理与门相同。

{
    name: '主窗户洞',
    type: 'cube',
    width: 420,
    height: 150,
    depth: 50, 
    translate: [200, 30, 500],
    op: '-',
},{
    name: '主窗户台',
    type: 'cube',
    width: 420,
    height: 10,
    depth: 40, 
    translate: [200, 30, 510],
    op: '+',
}

定义了一个窗洞(挖掉)、一个窗台(添加)。一个大窗户就作好了:

图片描述

再添加一个略带颜色的透明玻璃。玻璃设置点高光和反射,增长“玻璃”感受:

{
    name: '主窗户玻璃',
    type: 'cube',
    width: 420,
    height: 150,
    depth: 2,
    translate: [200, 30, 500],
    op: '+',
    style: {
        'm.transparent': true,
        'm.opacity':0.4,
        'm.color':'#58ACFA',
    },            
}

json中玻璃设置了透明度和颜色。这样一个半透明的茶色玻璃就行了:
图片描述

到这里忽然在想:盖房子若是像写程序同样简单就行了,全部的程序猿就不会是无房一族单身狗了。固然写程序和盖房子同样:该封装好的要封装好,最后就是搭积木组装就好了。若是盖房子都是从挖土活泥巴开始,那就杯具了。写程序也是同样,若是从webGL的main开始写……这3D机房的系统要几个月甚至几年才能作出来呢?

外侧墙

按照项目实际要求,继续增长更多建筑物墙体。主要是房间外侧有两道走廊隔墙。这是一个中间有大片透明玻璃的走廊隔墙,须要作的好看一点。因为是直线墙,没有复杂走向,直接用立方体定义:

{
    name: '左外墙',
    type: 'cube',
    width: 20,
    height: 200,
    depth: 1300,
    translate: [-790, 0, 0],
    op: '+',
}

效果以下:

图片描述

再继续挖掉中间的窗户部分:

{
    name: '左外墙洞',
    type: 'cube',
    width: 30,
    height: 110,
    depth: 1300,
    translate: [-790, 60, 0],
    op: '-',
}

图片描述

空白显得很奇怪,加上玻璃试试:

{
    name: '左外墙玻璃',
    type: 'cube',
    width: 4,
    height: 110,
    depth: 1300,
    translate: [-790, 60, 0],
    op: '+',
    style: {
        'm.transparent': true,
        'm.opacity':0.6,
    },
}

图片描述

有了半透明和高光的效果,看起来就有质感了,右边也如法炮制:

图片描述

这样,整个建筑的外观就基本完成了。最后,放一些绿植,增长些生气吧。

植物

作一盆植物,须要有一个空的花盆,花盆里面有泥土,上面有一株植物。这些东西用3D作起来都有点啰嗦。不过也不难。花盆用一个大圆柱剪掉中间的小圆柱,作成空心花盆;植物用贴图+透明模拟一下就行,不用真的去作植物的3D模型,不然要累死了。

根据上面的思路,在项目中经过仔细调整,把建立花盆的代码封装好,而后在json中定义花盆位置就好了。下面定义一个:

{
    name: '花1',
    type: 'plant',
    translate: [560, 0, 400],
}

程序中解析若是type是plant则建立植物对象并添加场景。

图片描述

在房间、走廊、甚至窗台上均可以放几盆,窗台上的能够经过设置scale缩小一些,并提高其高度到窗台位置便可。
图片描述

看看下总体效果,还不赖吧。
图片描述

机柜和设备

写了那么一大篇,才终于把3D机房的外观装修完成,咱也算是个设计师程序员的混合型人才了呢。其实机房最核心的资源——机柜,还没找落呢,没办法,形象工程也是项目建设的一大亮点。

机柜

机柜,以及其中的服务器设备。这才是3D机房里面最终要管理的内容。在咱们的实际项目中,这些资产都是在数据库中存储,并经过json接口加载到浏览器中显示。这里为了演示方便,直接写几个机柜的片断,看一下显示效果。
图片描述

机柜对象在项目中是这样封装的:用一个立方体来表示机柜,并加上贴图。项目中,为了提升显示速度,机柜一开始并不加载内部服务器内容,而是只显示自身一个立方体。当用户双击后,会触发一个延迟加载器,从服务器端加载机柜内部服务器,并加载到对应的位置上。此时,机柜会被挖空成一个空心的立方体,以便视觉上更像一个机柜。

定义机柜的json以下:

{
    name: '机柜',
    type: 'rack',
    lazy: true,
    width: 70,
    depth: 100,
    height: 220,
    translate: [-370, 0, -250],
    severity: CRITICAL,
}

上面的机柜定义中,有一个lazy标记,标记它是否延迟加载其内容。若是延迟加载,则双击触发,不然程序显示时直接加载其内容。Severity是定义了机柜的告警信息,它是否有业务告警。若是有告警,会用一个气泡显示在机柜的上方,同时机柜也会被染色成告警对应的颜色。

加入更多的机柜看看效果:

图片描述

设备

简单起见,这里管理的设备假设都是机架设备,尺寸规格比较规整,所以比较容易在机柜中组织。一个设备的外观肯定后,在数据库中定义好模板,加载时根据其所在机柜的位置放置便可。

图片描述

这里只是随机生成了几个服务器设备,并按位置摆放。在实际应用中,能够经过手工录入或者智能机架报送的信息来肯定服务器的类型和位置。

图片描述

若是须要监控到端口级别,还能够在服务器弹出后,再进一步延迟加载设备商的板卡、端口对象,并点击后进一步进行配置、监控等操做。固然加载的数据越细,对3D引擎和浏览器的压力会越大。能够经过动态延迟加载/卸载策略,获取一些平衡折中。

电视机

纯属无聊,再作一个电视机挂在墙上。依旧,定义一个立方体、挖空屏幕,放上透明玻璃,再贴上咱们喜欢的电视节目画面,就ok了。

{
    name: '电视机体',
    type: 'cube',
    width: 150,
    height: 80,
    depth: 5,
    translate: [80, 100, 13],
    op: '+',        
},{
    name: '电视机挖空',
    type: 'cube',
    width: 130,
    height: 75,
    depth: 5,
    translate: [80, 102.5, 17],
    op: '-',
},{
    name: '电视机屏幕',
    type: 'cube',
    width: 130,
    height: 75,
    depth: 1,
    translate: [80, 102.5, 14.6],
    op: '+',
    style: {
        'front.m.texture.image': 'images/screen.jpg',
    },
}

固然,实际项目中,能够换上监控大屏幕的效果:
图片描述

总结

整个场景写到最后,我也已经脑洞大开游刃有余了。3D场景,尤为是这类业务系统,并不必定要死抠模型的仿真度,才能作到“好看”的效果。先来一张全景看一下:
图片描述

怎么样,还算精美吧?基本不输前面看到的广告公司的效果图。但和效果图一张死图片不同,咱们这是一个能操做、能漫游、能缩放、有动画、显示流畅、浏览器无需插件就能直接打开的3D机房小程序,就一个json文件和一百多行代码和一天的时间就搞定了,仍是让人有点惊讶的。

图片描述

不用插件、不用3Dmax,不用模型库,干干净净纯粹的小程序,手机和平板也能用哦,并且还很流畅!上一张个人Nexus5截图瞅瞅:

图片描述

通过优化,场景加载已经控制在600毫秒之内,缩放漫游也很流畅。固然,技术和美化永无止境,用户的需求也变幻无穷精益求精。但只要咱们选择好了技术和工具,就能事半功倍。Html5就是极佳的一个选择。

Html5,也许它还不是银弹,但它确实是很好的一个炮弹。本文这一弹,你还喜欢吗?欢迎来信留言索取代码、技术交流:tw-service@servasoft.com

相关文章
相关标签/搜索