zoukankan      html  css  js  c++  java
  • HTML5,不仅仅是看上去非常美(第二弹:打造最美3D机房)

    前言

    近期项目开发任务告一段落,刚好有时间整理这大半年的一些成果。使用html5时间还不久,对js的认识还不够深入。没办法,曾经一直搞java,对js的一些语言特性和概念一时还转换只是来。

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

    目标效果图

    下图是客户给找的一张的效果參考图,希望机房至少能达到以下的3D效果。


    这里写图片描写叙述

    懂的人都知道,这但是一张设计公司出的装修效果图啊,就算是用max建模。也须要大量的工作,何况咱但是程序猿在做数据中心的可视化项目啊。。。

    强忍心中奔腾的万千头**马,静下心来思考。那就先从搭建一个webGL的场景開始吧。

    WebGL基本场景搭建

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

    要检測你的浏览器是否支持webGL,可直接訪问网页http://get.webgl.org/ 看能否看到一个旋转的立方体。假设能看到,说明你的浏览器支持webgGL。否则,能够下一个最新的chrome试试吧。相对来说chrome对webGL的支持最好,效率也非常优秀。

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

    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上下文:

    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',
         1600,
        height: 10,
        depth: 1300,
    
        style: {
            'm.color': '#BEC9BE',
            'm.ambient': '#BEC9BE',
        }
    }
    

    通过定义,创建了一个13米*16米的地板块。这也是客户小型机房的实际尺寸:

    这里写图片描写叙述

    看起来有那么点意思,就是颜色还不够,须要找一个地板砖纹理图。

    须要注意的是。纹理图的尺寸都须要是宽和高都是2的幂,比如128x128、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',
         200,
        height: 20,
        depth: 260,
        translate: [-348,0,530],
        rotate: [Math.PI/180*3, 0, 0],
        op: '-',
        style: {
            …,
        }
    }
    

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

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

    走廊桌

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

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

    效果例如以下:
    这里写图片描写叙述

    这里偷懒事实上是有原因的。在3D里,最重视的就是效率。千万不要放一些非常复杂的模型,尤其是这类非业务对象。就像这个桌子。虽然仅仅是个简单的立方体,但仅仅要和总体风格协调一致,再添加一点配色并启动阴影效果后。看着就好多了:
    这里写图片描写叙述

    墙体

    墙体是机房里非常重要的一个部分,有好的光照、阴影的效果才干看起来更加逼真。

    因为墙体是不规则的路径,一段一段去生成还真挺麻烦的,还好引擎支持这样的物体,甚至曲线路径都能够。这里仅仅要在json里面定义一组数字的坐标,让这些数字依次连接,组成一个墙体,最后生成3D对象放入场景中即可啦。

    json定义例如以下:

    {
        name: '主墙体',
        type: 'path',
         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',
         195,
        height: 170,
        depth: 30,
        op: '-',
        translate:[-350,2,500],
    }
    

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

    这里写图片描写叙述

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

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

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

    这里写图片描写叙述

    来张全景图看看:
    这里写图片描写叙述

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

    {
        name: '左门',
        type: 'cube',
         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',
         420,
        height: 150,
        depth: 50, 
        translate: [200, 30, 500],
        op: '-',
    },{
        name: '主窗户台',
        type: 'cube',
         420,
        height: 10,
        depth: 40, 
        translate: [200, 30, 510],
        op: '+',
    }
    

    定义了一个窗洞(挖掉)、一个窗台(加入)。

    一个大窗户就做好了:

    这里写图片描写叙述

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

    {
        name: '主窗户玻璃',
        type: 'cube',
         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',
         20,
        height: 200,
        depth: 1300,
        translate: [-790, 0, 0],
        op: '+',
    }
    

    效果例如以下:

    这里写图片描写叙述

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

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

    这里写图片描写叙述

    空白显得非常奇怪。加上玻璃试试:

    {
        name: '左外墙玻璃',
        type: 'cube',
         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机房的外观装修完毕,咱也算是个设计师程序猿的混合型人才了呢。

    事实上机房最核心的资源——机柜。还没找落呢,没办法。形象project也是项目建设的一大亮点。

    机柜

    机柜。以及当中的server设备。这才是3D机房里面最终要管理的内容。

    在我们的实际项目中,这些资产都是在数据库中存储,并通过json接口载入到浏览器中显示。这里为了演示方便,直接写几个机柜的片段,看一下显示效果。


    这里写图片描写叙述

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

    定义机柜的json例如以下:

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

    上面的机柜定义中。有一个lazy标记,标记它是否延迟载入其内容。假设延迟载入,则双击触发,否则程序显示时直接载入其内容。

    Severity是定义了机柜的告警信息,它是否有业务告警。假设有告警。会用一个气泡显示在机柜的上方,同一时候机柜也会被染色成告警相应的颜色。

    加入很多其它的机柜看看效果:

    这里写图片描写叙述

    设备

    简单起见,这里管理的设备假设都是机架设备。尺寸规格比較规整,因此比較easy在机柜中组织。一个设备的外观确定后,在数据库中定义好模板,载入时依据其所在机柜的位置放置即可。

    这里写图片描写叙述

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

    这里写图片描写叙述

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

    电视机

    纯属无聊,再做一个电视机挂在墙上。

    依然。定义一个立方体、挖空屏幕,放上透明玻璃,再贴上我们喜欢的电视节目画面,就ok了。

    {
        name: '电视机体',
        type: 'cube',
         150,
        height: 80,
        depth: 5,
        translate: [80, 100, 13],
        op: '+',        
    },{
        name: '电视机挖空',
        type: 'cube',
         130,
        height: 75,
        depth: 5,
        translate: [80, 102.5, 17],
        op: '-',
    },{
        name: '电视机屏幕',
        type: 'cube',
         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

  • 相关阅读:
    c#冒泡排序
    C# 虚方法(virtual)覆盖(override) 隐藏(new) 重载
    Javascript 大括号
    C# const.static.readonly.
    热点链接(img map area)
    WeiBo返回错误码的二种方式
    Cookie跨域操作
    synchronized(this)与synchronized(class)
    线程安全场景备忘
    git新建一个分支setupstream
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/7245427.html
Copyright © 2011-2022 走看看