現在,3D 模型已經用于各種不同的領域。在醫療行業使用它們制作器官的精確模型;電影行業將它們用于活動的人物、物體以及現實電影;視頻游戲產業將它們作為計算機與視頻游戲中的資源;在科學領域將它們作為化合物的精確模型;建筑業將它們用來展示提議的建筑物或者風景表現;工程界將它們用于設計新設備、交通工具、結構以及其它應用領域;在最近幾十年,地球科學領域開始構建三維地質模型,而且 3D 模型經常做成動畫,例如,在故事片電影以及計算機與視頻游戲中大量地應用三維模型。它們可以在三維建模工具中使用或者單獨使用。為了容易形成動畫,通常在模型中加入一些額外的數據,例如,一些人類或者動物的三維模型中有完整的骨骼系統,這樣運動時看起來會更加真實,并且可以通過關節與骨骼控制運動。
這些種種都讓我們前端開發者覺得如果我們可以不用學習 unity3d 或者其他游戲開發工具就能實現 3D 效果,而且能夠精準的靠代碼來控制移動或者方向就好了。。。于是我利用 HT For Web 中的 3D組件 來實現了一個小例子,用了 HT 中 3D組件 的大部分功能,做這個例子就是想把 3D 組件好好的掌握,盡量放進一個例子中,到時候別人有需要就可以參考了。
先來看看整體實現的效果圖:

用 HT for Web,現有的 3d 模板創建三層底板不是問題,問題是要如何將圖中第一層的“電腦”和“機柜組件”放上去?我是在網上 down 下來的 obj 格式的文件,然后我利用 HT 中的 ht.Default.loadObj(objUrl, mtlUrl, params) 函數將模型加載進去,其中的 params 部分可以參考 http://www.hightopo.com/guide...,代碼如下:
ht.Default.loadObj( obj/機柜組件1.obj , obj/機柜組件1.mtl , { //加載 obj 文件 cube: true, //是否將模型縮放到單位1的尺寸范圍內,默認為false center: true, //模型是否居中,默認為false,設置為true則會移動模型位置使其內容居中 shape3d: box , //如果指定了shape3d名稱,則HT將自動將加載解析后的所有材質模型構建成數組的方式,以該名稱進行注冊 finishFunc: function(modelMap, array, 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); });其中 finishiFunc 函數中的三個參數定義如下:
modelMap:調用 ht.Default.parseObj 解析后的返回值,若加載或解析失敗則返回值為空
array:所有材質模型組成的數組
rawS3:包含所有模型的原始尺寸
一般在實際應用中我們都會將圖元的大小設置為模型的原始尺寸。
“電腦”上方有個紅色的立體能旋轉的“警告”,是依靠 ht.Default.setShape3dModel 函數(HT for Web 建模手冊 http://www.hightopo.com/guide... 3d 模型,在 ht 中,封裝好的建模函數有很多,比較基礎的就是球體,圓柱,立方體等等,這邊我用的是構造環形的方法 createRingModel 來生成“警告”最外面的環,感嘆號的上部分就是用的 createSmoothSphereModel 構造的球體,感嘆號的下部分就是用 createSmoothCylinderModel 來構造的圓柱。我一開始直接使用了 3d 模型中封裝好的函數,導致后來根本不知道函數中使用的參數是做什么用的,而且也不明白 3d 模型是怎么構成的,然后自己又重新看了前面的“模型基礎”,才知道原來 3d 模型采用的一個面,最基礎的是三角面,之后復雜的面也是由多個三角面來形成的,然后繞著一根特定的軸旋轉之后形成的,當然,這個軸是你來決定的,不同的軸可以生成不同的形狀,對于顏色等風格方面的設置可以參考 HT for Web 風格手冊(http://www.hightopo.com/guide...。至于如何讓這個 3d 模型旋轉起來,ht 中封裝了 addScheduleTask(Task) 方法,我在第三層 Task 中調用了 ht 封裝的一個旋轉函數 setRotation 來設置旋轉的順序和方向,并且指定了旋轉的對象。以下是自定義“警告”的 3d 模型的方法(注意:因為本例的模型是自定義組合的,如果要設置整體模型的顏色要用 “all.blend” style 屬性):
function createAlarm(device, formPane) { var ringModel = ht.Default.createRingModel([ 8, 1, 10, 1, 10, -1, 8, -1, 8, 1 ], null, null, false, false, 100);//根據xy平面的曲線,環繞一周形成3D模型。 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 alarmArr = [//組合模型 由三個模型ringModel、sphereModel、cylinderModel組合而成 shape3d: ringModel,//定義模型類型 r3: [Math.PI/2, 0, 0],//設置旋轉角度 color: {//設置模型顏色 func: style@all.blend ,//數據綁定style樣式中的all.blend屬性,可通過data.s()獲取和設置這個屬性 shape3d: sphereModel, t3: [0, 4, 0], color: { func: style@all.blend , shape3d: cylinderModel, t3: [0, -3, 0], color: { func: style@all.blend , ht.Default.setShape3dModel( alarm , {//注冊自定義3D模型 shape3d: alarmArr var alarmTip = createNode( alarm , device);//創建shape3d為alarm的節點 alarmTip.s3([2, 2, 2]);//設置節點大小 alarmTip.p3(device.p3()[0], device.p3()[1]+60, device.p3()[2]); alarmTip.s( all.blend , red //改變此屬性可改變模型的顏色,因為模型創建的時候已經數據綁定了 return alarmTip;}接下來看看怎么讓這個“告警”節點“閃爍”,我是直接將這個動畫跟節點綁定,這樣可以直接通過節點來控制動畫。所以在上面我們創建 alarm 的模型時就可以直接將動畫綁在節點上:
if(formPane){ alarmNode.scaleFunc = function() {//設置大小變化動畫 var size = alarmNode.s3();//獲取節點的大小 if (size[0] === 2 size[1] === 2 size[2] === 2) alarmNode.s3([1, 1, 1]); else alarmNode.s3([2, 2, 2]); alarmNode.scaleTimer = setTimeout(alarmNode.scaleFunc, formPane.v( scaleInterval //設置動畫 alarmNode.blinkFunc = function(){//設置閃爍的動畫 var color = alarmNode.s( all.blend //獲取節點的style樣式 if (color === red ) alarmNode.s({ all.blend : yellow //如果節點顏色為紅色,那么設置為黃色 else alarmNode.s({ all.blend : red  alarmNode.blinkTimer = setTimeout(alarmNode.blinkFunc, formPane.v( blinkInterval  alarmNode.rotateFunc = function() {//設置旋轉動畫 alarmNode.setRotation(alarmNode.getRotation() + Math.PI/20);//獲取節點當前的旋轉角度,在這個旋轉角度之上添加 Math.PI/20 個角度 alarmNode.rotateTimer = setTimeout(alarmNode.rotateFunc, formPane.v( rotInterval }上面的動畫我設置了可以通過 form 表單面板上的屬性來控制節點閃爍的速度,以及閃爍節點的動畫等等,主要說一下這個功能在 form 表單上的實現:
formPane.addRow([//向form表單面板上添加一行元素 checkBox: {//復選框 label: Enable Blink ,//復選框對應的文本內容 selected: true,//設置選中復選框 onValueChanged: function(){//復選框值變化時回調的函數 var data = dataModel.getDataByTag( colorAlarm //通過tag標簽獲取節點 if (this.getValue()) {//獲取復選框當前值true/false data.blinkTimer = setTimeout(data.blinkFunc, formPane.v( blinkInterval //直接通過設置節點的blinkTimer來設置動畫 else { clearTimeout(data.blinkTimer);//清除動畫 id: blinkInterval ,//form可以通過getValue(簡寫為v)來獲取這個item的值 slider: {//設置了該屬性后HT將根據屬性值自動構建ht.widget.Slider對象,并保存在element屬性上 min: 0,//滑動條最小值 max: 1000,//滑動條最大值 step: 50,//滑動條步進 html' target='_blank'>value: 500,//當前滑動條的值], [0.1, 0.1]);//設置這行的兩個item元素的寬度小于1的值為比例最后來說說 3D 管線上的小球流動的部分,這個功能確實非常實用,而且做出來的效果也確實不錯,跟大家分享~
首先,創建一條連線連接起始節點和結束節點并設置這個連線的樣式,用 ht.Edge 可以將連線吸附在起始節點和結束節點上,這樣移動這兩個節點中的任意一個節點連線都會跟著節點移動的位置變化,非常方便:
var polyline = new ht.Edge(source, target);//創建連線dataModel.add(polyline);//將連線添加進數據容器中polyline.s({ edge.width : 5,//連線寬度 edge.type : points ,//連線類型 為points時連線走向將由edge.points屬性決定,用于繪制折線 edge.points : [//可設置類型為ht.List的{x:100, y:100}格式的點對象數組,當edge.type為points時起作用 {x: source.getPosition3d()[0]+200, y: source.getPosition3d()[2], e: source.getPosition3d()[1]}, {x: target.getPosition3d()[0]+400, y: target.getPosition3d()[2], e: target.getPosition3d()[1]} edge.segments : [1, 4],//用于描述點連接樣式,數組元素為整型值 shape3d : cylinder ,//圓柱 shape3d.color : rgba(242, 200, 40, 0.4) , shape3d.resolution : 30,//微分段數,可以決定曲線的平滑度 edge.source.t3 : [20, 0, 0],//連線source端偏移,[tx, ty, tz]格式,默認為空 edge.target.t3 : [20, 0, 0]//連線target端偏移,[tx, ty, tz]格式,默認為空});因為我們在創建連線的時候設置的 points 僅為曲線上的兩個點,所以如果要獲取曲線目前形成的點,是缺少 source 和 target 兩個點的,我們重新設置一個數組,將這兩個點添加進去,后面獲取曲線上所有點時會用上:
var list = new ht.List();list.push({x: source.getPosition3d()[0], y: source.getPosition3d()[2], e: source.getPosition3d()[1]});//向數組中添加source點polyline.s( edge.points ).each(function(item){//添加style屬性中已設置的兩個點 list.push(item);list.push({x: target.getPosition3d()[0], y: target.getPosition3d()[2], e: target.getPosition3d()[1]});//添加target點然后創建一個在管線上滑動的小球節點,這是僅是設置節點,真正添加進數據容器 dataModel 中需要設置完小球的坐標時再添加,如果沒有給節點設置位置就將節點添加進數據容器中,節點的初始位置就是 3D 場景的正中心 [0, 0, 0] 的位置。小球滑動的動畫代碼如下:
var ball = new ht.Node();//創建小球節點ball.s({//設置小球節點的樣式 shape3d : sphere ,//設置小球的3d模型為球形 shape3d.color : rgba(40, 90, 240, 0.4) //設置3d模型的顏色var delta = 10, flag = 0;setInterval(function(){ flag++; var length = (polyline.a( total ) || 0) % polyline.a( length ) + delta;//小球當前走過的曲線長度 var cache = ht.Default.getLineCacheInfo(list, polyline.s( edge.segments //獲取曲線上的點的信息 var lineLength = ht.Default.getLineLength(cache);//獲取曲線的總長度 polyline.a( length , lineLength - 50);//因為我設置了edge的t3(相當于2d中的offset),所以線段長度實際沒有那么長 var offset = ht.Default.getLineOffset(cache, length);//曲線根據曲線上點的信息的偏移量 ball.setPosition3d(offset.point.x + 10, offset.point.y, offset.point.z);//設置節點的坐標 polyline.a( total , length); if(flag === 1) dataModel.add(ball);//這時候節點已經有了坐標了,可以添加進數據容器中了}, 10);我們還可以看到第二層上有兩個特殊的多邊形“平行四邊形”和“梯形”,平行四邊形是靠 createParallelogramModel 模型函數,這個函數比較簡單,createExtrusionModel(array, segments, top, bottom, resolution, repeatUVLength, tall, elevation),array 是你要形成的圖形的坐標點,這邊只是針對于 xz 軸上畫的平面圖形,segments 指的是如何連接這幾個坐標點,可參考 HT for Web 形狀手冊(http://hightopo.com/guide/gui...),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); });相關推薦:
HTML5 網絡拓撲圖應用實例講解
有向圖之任務調度拓撲圖介紹
關于網絡拓撲的10篇文章推薦
以上就是HTML5 WebG 的3D網絡拓撲結構圖的詳細內容,其它編程語言
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播更多信息之目的,如作者信息標記有誤,請第一時間聯系我們修改或刪除,多謝。
新聞熱點
疑難解答