1. 程式人生 > >基於HTML5和WebGL的3D網路拓撲結構圖

基於HTML5和WebGL的3D網路拓撲結構圖

現在,3D模型已經用於各種不同的領域。在醫療行業使用它們製作器官的精確模型;電影行業將它們用於活動的人物、物體以及現實電影;視訊遊戲產業將它們作為計算機與視訊遊戲中的資源;在科學領域將它們作為化合物的精確模型;建築業將它們用來展示提議的建築物或者風景表現;工程界將它們用於設計新裝置、交通工具、結構以及其它應用領域;在最近幾十年,地球科學領域開始構建三維地質模型,而且3D模型經常做成動畫,例如,在故事片電影以及計算機與視訊遊戲中大量地應用三維模型。它們可以在三維建模工具中使用或者單獨使用。為了容易形成動畫,通常在模型中加入一些額外的資料,例如,一些人類或者動物的三維模型中有完整的骨骼系統,這樣運動時看起來會更加真實,並且可以通過關節與骨骼控制運動。

這些種種都讓我們前端開發者覺得如果我們可以不用學習unity3d或者其他遊戲開發工具就能實現3D效果,而且能夠精準的靠程式碼來控制移動或者方向就好了。。。於是我利用HT For Web中的3D元件來實現了一個小例子,用了HT3D元件的大部分功能,做這個例子就是想把3D元件好好的掌握,儘量放進一個例子中,到時候別人有需要就可以參考了,但是因為之前從來沒有實現過3D的效果,再加上現在手冊沒有很完整,所以這個例子對我來說還是有點難度的。

先來看看整體實現的效果圖:


HT for Web,現有的3d模板建立三層底板不是問題,問題是要如何將圖中第一層的“電腦”和“機櫃元件”放上去?我是在網上down下來的obj格式的檔案,然後我利用

HT

ht.Default.loadObj('obj/機櫃元件1.obj', 'obj/機櫃元件1.mtl', {
     cube: true,
     center: true,
     shape3d: 'box',
     finishFunc: function(modelMap, array, rawS3){
       window.rawS3 = rawS3;
       if(modelMap){
      device2 = createNode('box', floor1);
      device2.p3([x1-120, y1+13, z1+60]);
      device2.s3(rawS3);
      createEdge(device1, device2);
      device3 = createNode('box', floor1);
      device3.s3(rawS3);
      device3.p3([x1+120, y1+13, z1+60]);
      createEdge(device1, device3);
       }
     }
 });    
“電腦”上方有個紅色的立體能旋轉的“警告”,是依靠ht.Default.setShape3dModel函式(HT for Web 建模手冊)註冊的一個3d模型,在ht中,封裝好的建模函式有很多,比較基礎的就是球體,圓柱,立方體等等,這邊我用的是構造環形的方法createRingModel來生成“警告”最外面的環,感嘆號的上部分就是用的createSmoothSphereModel構造的球體,感嘆號的下部分就是用createSmoothCylinderModel來構造的圓柱。我一開始直接使用了3d模型中封裝好的函式,導致後來根本不知道函式中使用的引數是做什麼用的,而且也不明白3d模型是怎麼構成的,然後自己又重新看了前面的“模型基礎”,才知道原來3d模型採用的一個面,最基礎的是三角面,之後複雜的面也是由多個三角面來形成的,然後繞著一根特定的軸旋轉之後形成的,當然,這個軸是你來決定的,不同的軸可以生成不同的形狀,對於顏色等風格方面的設定可以參考HT for Web 風格手冊。至於如何讓這個3d模型旋轉起來,ht中封裝了addScheduleTask(Task)方法,我在第三層Task中呼叫了ht封裝的一個旋轉函式setRotation來設定旋轉的順序和方向,並且指定了旋轉的物件。以下是自定義“警告”的3d模型的方法(注意:因為本例的模型是自定義組合的,如果要設定整體模型的顏色要用“all.blend”style屬性):
var ringModel = ht.Default.createRingModel([8, 1, 10, 1, 10, -1, 8, -1, 8, 1], null, null, false, false, 100);  
var sphereModel = ht.Default.createSmoothSphereModel(8, 8, 0, Math.PI*2, 0, Math.PI, 2);  
var cylinderModel = ht.Default.createSmoothCylinderModel(8, true, true, 1, 2, 0, Math.PI*2, 8);  
var arr = [  
    {  
        r3: [Math.PI/2, 0, 0],  
        color: 'red'  
    },{  
        shape3d: sphereModel,  
        t3: [0, 4, 0],  
        color: 'red'  
    },{  
        shape3d: cylinderModel,  
        t3: [0, -3, 0],  
        color: 'red'  
    }  
];  
ht.Default.setShape3dModel('alarm', {  
    shape3d: arr  
}); 

要實現3D介面上展現2d圖片,只要按照平常的路走就行,因為ht中的Graph3dView和其他的元件的根部都是div,在div上生成圖片用的就是原生js,new Image(),再將image的src和大小賦值,並且加到3d面板上就行了,注意這裡是加到3d的底層div上,要用g3d.getView().appendChild來新增,我們還可以看到管線上有虛線流動的痕跡,這是通過不斷改變“shape3d.uv.offset”引數實現管道流動的特殊效果,詳情請參考HT for Web 形狀手冊

想讓2d圖片在3d管線上移動則是使用g3d.toViewPosition(position)來獲取3d模型的二維座標,這個函式中的引數就是三維模型的3d座標,我們可以直接將polyline管線上的點傳入toViewPosition函式中,這邊獲取管線上的點在ht中已經封裝好三個函式getLineCacheInfo、getLineLength、getLineOffset,這樣就可以直接獲取到二維座標,然後將img的座標設定上去即可,以下是img圖片在管道上移動的程式碼:

var delta = 10;  
params = {  
    frames: Infinity,  
    interval: 50,  
    action: function(v, t){  
        var length = (polyline.a('total') || 0) % polyline.a('length') + delta;  
        var cache = ht.Default.getLineCacheInfo(polyline.getPoints(), polyline.getSegments());  
        var lineLength = ht.Default.getLineLength(cache);  
        var offset = ht.Default.getLineOffset(cache, length);  
        arr = [offset.point.x, offset.point.y, offset.point.z];  
        var position = g3d.toViewPosition(arr);  
            img.style.left = (position.x - 5) + 'px';  
            img.style.top = (position.y - 5) + 'px';  
            polyline.a('total', length);  
    }  
};  
anim = ht.Default.startAnim(params);

可以看到圖中第二層中的立方體上有“SDH”的字樣,我是通過設定shape3d.top.img: imgURL來實現的,這邊的imgURL可以是圖片的相對路徑,也可以是ht中用ht.Default.setImage宣告的img的名稱,還可以是json格式構造的圖片。在ht中,2D文字顯現在3D上,則字型周圍會出現“鋸齒”,這個時候只要設定“label.transparent: true”即可。

我們還可以看到第二層上有兩個特殊的多邊形“平行四邊形”和“梯形”,因為之前有客戶說不知道如何使用createExtrusionModel這個模型函式(HT for Web 建模手冊),我索性就寫了一下,平行四邊形是靠createParallelogramModel模型函式,這個函式比較簡單,createExtrusionModel(array, segments, top, bottom, resolution, repeatUVLength, tall, elevation),array是你要形成的圖形的座標點,這邊只是針對於xz軸上畫的平面圖形,segments指的是如何連線這幾個座標點,可參考HT for Web 形狀手冊,top和bottom就是讓你選擇是否有頂部或者底部,resolution微分段數,我們描繪一段曲線的時候可能只要確認幾個個別的點然後在每兩個點之間的連線上把它分成多個段,這樣這條線段就會變得平滑,ht為了使用者能夠輕鬆操作這些線段,就封裝了這一個引數,repeatUVLength預設為空,設定值後頂部和底部的貼圖將根據制定長度值進行重複,tall模型的高度,預設為5,elevation模型中心的y軸位置,預設值為0,設定這個值可以使xz上的平面繞著y軸旋轉。

底層的一個環形的效果是通過一個演算法來實現的,環形得確認這個環形上有多少個元素,然後算每兩個之間的角度,在通過sin、cos來計算每一個元素的位置,得出瞭如下程式碼:

names = ['裝置2', '裝置3', '裝置4', '裝置5', '裝置6', '裝置7', '裝置8', '裝置9'];  
names.forEach(function(name, index) {  
    x = 400, y = 200, angle = 45, r = 120;  
    x = x3 + Math.sin((2 * Math.PI / 360) * angle * index) * r;  
    y = z3 + Math.cos((2 * Math.PI / 360) * angle * index) * r;  
    device = createRect([x, y3 + 15, y], [w * 0.1, 15, h * 0.1], '', '', floor3);  
    createEdge(device5, device);  
});