無插件純Web 3D機房,HTML5+WebGL傾力打造


前言

最近項目開發任務告一段落,剛好有時間整理這大半年的一些成果。使用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',
	width: 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',
	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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM