序:
又是很久沒出隨筆文章了,一篇文章有時候整理一天,實在是抽不出來時間。
最近在回顧幾年前的專案時,發現這個智慧三維消防視覺化專案很有回顧價值,索性就拿出來講講。
首先,我們要知道消防裡的知識,不是簡簡單單的幾個滅火器,煙感報警器這麼簡單的,消防是自有一套完整體系的,光是消防相關的產業年產值就有幾千個億。而我們普通非專業人士常見的消防裝置只是消防產業中的皮毛。
單是消防系統就可以分為很多類,常見的有消防給水系統、消火栓系統、自動噴水滅火系統、氣體滅火系統、防煙排煙系統、火災自動報警系統等等。這些系統內部的組成結構又各有不同。每個系統裡就有幾十個甚至上百個不同的消防裝置。比如我們常見的消防噴頭就有好幾種,各自用於不同的建築場景。
還是閒話少序,切入正題。
前言:
前面的課程裡,有一篇文章《使用webgl(three.js)搭建一個3D智慧園區、3D建築,3D消防模擬,web版3D,bim管理系統——第四課》是介紹實現消防模擬的。本文以及後續的篇幅將系統的介紹消防視覺化方案。
這篇文章由於篇幅原因,我專門這一篇先介紹一下常見的消防系統,以及程式碼框架,在後續的篇幅裡我們再各個擊破,詳細介紹每個消防系統的3D實現方案。
我們是技術類文章,這裡只能做一個簡單的常見的消防系統定義介紹:
消防給水系統:以水為滅火劑消防撲救火災的供水系統。由水源、消防給水管網、消防水池、消防水泵及消火栓、自動噴水滅火設施等組成。
消火栓系統:消火栓系統一般都由主泵和備用泵組成。一般按鈕啟動後,先啟動1#泵,1#泵啟動失靈,自動轉啟2#泵,只有當兩臺泵都不能啟動時,控制盤上才顯示故障。消防水泵的故障,一般是指水泵電機斷電、過載及短路等
自動噴水滅火系統:自動噴水滅火系統由灑水噴頭、報警閥組、水流報警裝置等元件,以及管道、供水設施組成,並能在發生火災時噴水的自動滅火系統。
氣體滅火系統:氣體滅火系統主要用在不適於設定水滅火系統等其他滅火系統的環境中
防煙排煙系統:防排煙系統,都是由送排風管道、管井、防火閥、門開關裝置、送、排風機等裝置組成
火災自動報警系統:火災自動報警系統是由觸發裝置、火災報警裝置、聯動輸出裝置以及具有其它輔助功能裝置組成的
上述系統,在我們實現3D軟體模擬過程中,程式設計師需要詳細知道各系統的工作原理,作用,才不會出現重大的業務性bug。(這就是程式設計師為啥會掉頭髮,基本在做一個系統體系時,就需要學習瞭解一遍)
言歸正傳,我們下面對各系統架構做一些概括性講解。
一、效果展示
1.1、消防給水系統效果展示
系統涉及各部件展示,邏輯結構展示,透過剖面視角、管網視角,全方位,多視角展示改系統的結構組成。
其功能實現的主要虛擬碼如下:
首先建立系統物件,用於各系統之間的切換
$(function () { indexPage = new IndexPage(); indexPage.init(); for (var i = 1; i <= 6; i++) { if (window["System0" + i]) { window["system0" + i] = new window["System0" + i](); window["system0" + i].init(); } } });
切換系統事件繫結
$(".res .sys").click(function () { $("#sysMainNav").hide(); $("#sysNav1").show(); $("#sysNav2").show(); var systemindex = $(this).attr("data-systemIndex"); console.log(systemindex); if (window["system0" + systemindex]) { window["system0" + systemindex].show(); } });
主功能切換
//功能ui IndexPage.prototype.showSystemMainNav1 = function (nav1) { layer.closeAll(); $("#backToMainNav").nextAll().remove(); if (nav1 && nav1.length > 0) { var sysNav1_detailhtml = ""; $.each(nav1, function (_index, _obj) { sysNav1_detailhtml += '<div id="' + _obj.id + '" class="boxbg ' + _obj.defaultState + '" onclick="if(indexPage.clickme){return false;};indexPage.clickme=true;setTimeout(function(){indexPage.clickme=false},500);' + _obj.actionStr + ';">\ <img src= "../img/' + (_obj.defaultState == "noselect" ? "dot_unselect.png" : "dot_selected.png") + '" class="s1icontime" />\ <p class="timeP">' + _obj.name + '</p>\ </div >'; }); $("#backToMainNav").after(sysNav1_detailhtml); } }
1.2、消火栓系統
消火栓系統與消防給水系統功能類似,只是其組成部件的側重點不一樣
例如消火栓注重分室外、室內、乾式、溼式、水鶴等等
這裡我們是展示模型的視角不一樣
modelBussiness.hideAllPLSystemDevs(200, function () { layer.msg("loading...", { time: 1000 }); if (param.greatePosition) { var greatePosition = param.greatePosition[_this.nav1State]; var camera = { x: 0, y: 0, z: 0 }; var target = { x: 0, y: 0, z: 0 }; var abloutModelNames = null; var abloutModelObjs = null; if (greatePosition) { camera = greatePosition.camera; target = greatePosition.target; abloutModelNames = greatePosition.abloutModelNames; } if (abloutModelNames == "All") { modelBussiness.showAllDevModels(1); } else if (abloutModelNames && abloutModelNames.length > 0) { abloutModelObjs = WT3DObj.commonFunc.findObjectsByNames(abloutModelNames); if (abloutModelObjs && abloutModelObjs.length > 0) { $.each(abloutModelObjs, function (_index, _obj) { _obj.visible = true; }); } } WT3DObj.commonFunc.changeCameraPosition(camera, target, 1000, function () { if (id == "s02_03_ssshs" || id == "s02_03_gsshs") { if (_objs) { $.each(_objs, function (_index, _obj) { if (_obj.name == "pldev_t10_1_7") { WT3DObj.commonFunc.changeObjsOpacity([_obj], 1, 0.2, 50, function () { }); } if (_obj.name == "pldev_t10_1_7_inner" && id == "s02_03_gsshs") { _obj.visible = false; } if (_obj.name == "pldev_t10_1_7_inner" && id == "s02_03_ssshs") { _obj.visible = true; } }); } } }); } else { console.log("資料初始化異常!沒有設定最佳位置"); return; } });
1.3、自動噴水滅火系統
該系統注重整體運作原理,在部件中特意加了原理動畫講解
【系統部件原理動畫舉例】
動畫實現虛擬碼:
//執行動畫 遞迴呼叫 System02.prototype.doAnimation = function () { modelBussiness.showAllPLSystemDevs(50, function () { modelBussiness.hideAllBuildModels(); modelBussiness.opcityDevs(function () { modelBussiness.changeDevsToSSMaterial(); WT3DObj.commonFunc.changeCameraPosition({ x: -34, y: -331, z: -546 }, { x: -412, y: -260, z: 135 }, 1000, function () { }); var actions = system02.nav2[2].children; if (actions && actions.length > 0) { function doaction(action_nub) { $("#" + actions[action_nub].id).attr("class", "nav2res navsys"); if (action_nub > 0) { $("#" + actions[action_nub - 1].id).attr("class", "nav2res navsys noseleced"); } actions[action_nub].action(function () { if (actions[action_nub + 1] && actions[action_nub + 1].action) { doaction(action_nub + 1); } }); } doaction(0); } }); }); }
var animationChildren=[ { name: "發生火情", id: "s01_step01", greatePosition: { camera: { x: -1388, y: -781, z: -309 }, target: { x: -2119, y: -1106, z: 873 } }, actionStr: "", action: function (callBack) { modelBussiness.addFire(function () { setTimeout(function () { callBack(); }, 2000); }); } }, { name: "噴淋動作", id: "s01_step02", greatePosition: { camera: { x: -1388, y: -781, z: -309 }, target: { x: -2119, y: -1106, z: 873 } }, actionStr: "", action: function (callBack) { console.log("執行2"); //找到噴淋 var pls = WT3DObj.commonFunc.findObjectsByNames(["pldev_penling_1_1_28", "pldev_penling_1_1_28_sp_1", "pldev_penling_1_1_28_sp_2", "pldev_penling_1_1_28_sp_3"]); WT3DObj.commonFunc.flashObjs(pls, "flashPL", 0xff0000, 10, 200, 0); setTimeout(function () { var pl = pls[0]; pl.children[1].visible = false; pl.children[3].visible = false; //噴淋裂開 var pls1 = pls[1]; var p1x = pls1.position.x; var p1z = pls1.position.z; var pls2 = pls[2]; var pls3 = pls[3]; pls1.oldpostion = { x: pls1.position.x, y: pls1.position.y, z: pls1.position.z }; new TWEEN.Tween(pls1.position).to({ x: p1x + 100 * (Math.random() < 0.5 ? -5 * Math.random() : 3 * Math.random()), y: -2000, z: p1z + 100 * (Math.random() < 0.5 ? -5 * Math.random() : 3 * Math.random()) }, 8000).start(); new TWEEN.Tween(pls2.position).to({ x: p1x + 100 * (Math.random() < 0.5 ? -5 * Math.random() : 3 * Math.random()), y: -2000, z: p1z + 100 * (Math.random() < 0.5 ? -5 * Math.random() : 3 * Math.random()) }, 8000).start(); new TWEEN.Tween(pls3.position).to({ x: p1x + 100 * (Math.random() < 0.5 ? -5 * Math.random() : 3 * Math.random()), y: -2000, z: p1z + 100 * (Math.random() < 0.5 ? -5 * Math.random() : 3 * Math.random()) }, 8000).start(); //開始噴水 modelBussiness.addWater( function () { setTimeout(function () { callBack(); }, 1000); } ); }, 2000); } }, ......]
1.4、氣體滅火系統
在氣體系統中,實現方式又有點不一樣,前面幾個系統都是程式碼模型,該系統使用了大量的載入模型,如座椅板凳等
該系統也是主要展現系統部件跟工作動畫原理
動畫中採用了大量的定時器,閉包,回撥,遞迴等等,這裡特別注意記憶體有效回收,否者瀏覽器可能會隨時崩潰
例如如下程式碼:
var a_messagePanel_1126 = WT3DObj.commonFunc.findObject("a_messagePanel_1126"); a_messagePanel_1126.position.x=1499.804; a_messagePanel_1126.position.y = 474.389; a_messagePanel_1126.position.z = -74.822; moveXH(a_messagePanel_1126, { x: 2008.767, y: 474.389, z: -74.822, t: 0 }, 2000); setTimeout(function () { moveXH(a_messagePanel_1126, { x: 2007.926, y: 478.648, z: -451.129, t: 2000 }, 2000); setTimeout(function () { moveXH(a_messagePanel_1126, { x: -657.755, y: 478.648, z: -451.129, t: 2000 }, 2000); WT3DObj.commonFunc.changeCameraPosition({ x: -295.23352627790484, y: 445.15353495337854, z: -140.38158326269246 }, { x: -798.2079071244784, y: 270.3977749099737, z: -511.7589163393606 }, 10, function () { }); setTimeout(function () { moveXH(a_messagePanel_1126, { x: -657.755, y: 478.648, z: -303.566, t: 2000 }, 2000); setTimeout(function () { moveXH(a_messagePanel_1126, { x: -657.755, y: 339.858, z: -303.566, t: 2000 }, 2000); setTimeout(function () { a_messagePanel_1126.visible = false; moveXH(a_messagePanel_1126, { x: -662.270, y: 315.038, z: -339.977, t: 2000 }, 2000); setTimeout(function () { a_messagePanel_1126.visible = true; moveXH(a_messagePanel_1126, { x: -662.270, y: 465.038, z: -339.977, t: 2000 }, 2000); setTimeout(function () { moveXH(a_messagePanel_1126, { x: -662.270, y: 465.038, z: -719.977, t: 2000 }, 2000); setTimeout(function () { WT3DObj.commonFunc.changeCameraPosition({ x: 1672.1492964146757, y: 437.22502365828495, z: -946.6467804045902 }, { x: 1393.4110369255911, y: 391.9499762093484, z: -843.1414359356829 }, 1000, function () { }); moveXH(a_messagePanel_1126, { x: 1433, y: 465.038, z: -719.847, t: 2000 }, 2000); setTimeout(function () { moveXH(a_messagePanel_1126, { x: 1433, y: 465.038, z: -739.847, t: 2000 }, 2000); setTimeout(function () { moveXH(a_messagePanel_1126, { x: 1429.452, y: 382.109, z: -739.847, t: 2000 }, 2000); setTimeout(function () { sgbjq2(callBack); }, 2000); }, 2000); }, 2000); }, 2000); }, 2000); }, 2000); }, 2000); }, 2000); }, 2000); }, 2000); }, 2000);
/* 關閉送(排)風機及送(排)風閥門 停止通風和空調系統及關閉該防護區的電動防火閥 關閉防護區的門窗 */ /* 向驅動氣瓶電磁閥傳送開啟訊號,可設≤30s 的延遲噴射 */ function djsdz(callBack) { var dev = WT3DObj.commonFunc.findObjectsByNames([ "dev_ledFont_1", ])[0]; for (var i = 30; i >=0; i--) { (function (a) { setTimeout(function () { if (a <10) { a = "0"+a; } dev.freshData(a); },1000 * (30 - a)); })(i); } setTimeout(function () { callBack(); },31 * 1000); }
1.5、防煙排煙系統
防排煙系統也是加了動畫的形式,充分展現了其工作原理與組成部件
action: function (callBack) { //剖面圖 $.each(system07.allModels, function (_index, _obj) { if (_obj.hasoldPosition) { _obj.position.y = _obj.hasoldPosition.y ; } _obj.visible = true; }); $.each(system07.foreModels, function (_index, _obj) { if (_obj.hasoldPosition) { _obj.position.y = _obj.hasoldPosition.y + 10000; } else { _obj.hasoldPosition = { y: _obj.position.y }; _obj.position.y = _obj.hasoldPosition.y + 10000; } _obj.visible = false; }); //發生火情 system07.stepName = "發生火情!"; layer.msg("</br><font style='color:#ffffff;font-size:20px;'>發生火情!</font></br>"); WT3DObj.commonFunc.changeCameraPosition({ x: 6120.260855819656, y: 1344.6126089802272, z: 10903.874792293966 }, { x: 6292.0698848787415, y: 106.7257770257646, z: 4388.448120618271 }, 1000, function () { addLines(); addFire(); addFYSFK(); setTimeout(function () { WT3DObj.commonFunc.changeCameraPosition({ x: 5416.2974093433795, y: 1500.4126878089987, z: 7749.928368473556 }, { x: 5474.770344242846, y: 899.4381166888209, z: 4216.286318511336 }, 2000, function () { callBack(); }); }, 2000); }); } },
System07.prototype.doAnimationFlag = false; System07.prototype.showNav2Action = function (index, id) { var _this = this; modelBussiness.removeSingleShowDevs(); console.log(id); if ((_this.nav1State == "s07_05" || _this.nav1State == "s07_06") && _this.doAnimationFlag) { layer.log("正在執行動畫"); return; } $("#" + _this.nav2State).attr("class", "nav2res navsys noseleced"); $("#" + id).attr("class", "nav2res navsys"); _this.nav2State = id; var param = _this.getNav2Param(index, id); if (!param) { console.log("資料初始化異常!"); return; } layer.closeAll(); this.playVoice(index, id); if (param.dataId && id != "s04_02_gsgd") { modelBussiness.showDevList(param.dataId); } function flashFunc() { if (param && param.flashNames && param.flashNames.length > 0) { var fnames = []; $.each(param.flashNames, function (_findex, _fobj) { var _n = _fobj; if (_fobj.indexOf("_children_") > 0) { _n = _fobj.split("_children_")[0]; } fnames.push(_n); }); _objs = WT3DObj.commonFunc.findObjectsByNames(fnames); if (param.flashNames[0] == "All") { _objs = modelBussiness.getAllPLSystemDevs(); } setTimeout(function () { WT3DObj.commonFunc.flashObjs(_objs, "flashPL", 0x00ff00, 8, 150, 0); }, 1000); } } flashFunc(); switch (_this.nav1State) { //全景 case "s07_01": //剖面 case "s07_02": //管網 case "s07_04": case "s07_03": if (param.greatePosition) { var greatePosition = param.greatePosition[_this.nav1State]; var camera = { x: 0, y: 0, z: 0 }; var target = { x: 0, y: 0, z: 0 }; if (greatePosition) { camera = greatePosition.camera; target = greatePosition.target; } WT3DObj.commonFunc.changeCameraPosition(camera, target, 1000, function () { }); } else { console.log("資料初始化異常!沒有設定最佳位置"); return; } break; //動畫 case "s07_06": case "s07_05": { //param.action(function () { // system07.stepName = null; //}); } break; }
1.6、火災自動報警系統
1.6.1、地上部分排煙動畫演練 部分錄屏
1.6.2、地下部分自動報警動畫演練 部分錄屏
部分程式碼如下:
function move(id) { var dv = document.getElementById(id); var x = 0; var y = 0; var l = 0; var t = 0; var isDown = false; //滑鼠按下事件 dv.onmousedown = function (e) { //獲取x座標和y座標 x = e.clientX; y = e.clientY; //獲取左部和頂部的偏移量 l = dv.offsetLeft; t = dv.offsetTop; //開關開啟 isDown = true; //設定樣式 dv.style.cursor = 'move'; } //滑鼠移動 window.onmousemove = function (e) { if (isDown == false) { return; } //獲取x和y var nx = e.clientX; var ny = e.clientY; //計算移動後的左偏移量和頂部的偏移量 var nl = nx - (x - l); var nt = ny - (y - t); dv.style.left = nl + 'px'; dv.style.top = nt + 'px'; layer.closeAll(); } //滑鼠抬起事件 dv.onmouseup = function () { //開關關閉 isDown = false; dv.style.cursor = 'default'; } } move("ccAnimationgif");
二、實現邏輯
2.1、模型建立
模型建立講究的是充分理解業務需求,以及把控效能跟網路的資源情況,採用程式碼模型與載入模型靈活配合。
程式碼模型,更好的節約了頻寬與記憶體資源,提升了使用者體驗。載入模型,降低了開發門檻,提升了效率,但其沒有程式碼模型靈活可控
各自案例如下:
程式碼模型:
[{"show":true,"uuid":"","name":"cube2_6","objType":"cube2","length":200,"width":200,"height":200,"x":0,"y":200,"z":0,"style":{"skinColor":16777215,"skin":{"skin_up":{"skinColor":16777215,"imgurl":"../../img/3dImg/rack_inside.jpg","materialType":"basic","side":1,"opacity":1},"skin_down":{"skinColor":16777215},"skin_fore":{"skinColor":16777215},"skin_behind":{"skinColor":16777215},"skin_left":{"skinColor":16777215},"skin_right":{"skinColor":16777215}}},"showSortNub":6}]
載入模型:
{"name":"twaver_idc_jiazi_7","objType":"objmodel","position":{"x":0,"y":0,"z":0},"scale":{"x":1,"y":1,"z":1},"visible":true,"rotation":[{"direction":"x","degree":0}],"filePath":"../../js/msj3D/sourse/models/jiazi/","mtlFileName":"jiazi.mtl","objFileName":"jiazi.obj","mtlIsPublic":false,"showSortNub":7}
2.2、場景建立
場景搭建透過把各個模型組合而成業務所需要的場景
搭建場景時需要考慮業務的邏輯關係,什麼時候要用,什麼時候需要釋放,哪些模型屬於一個場景,哪些模型屬於邏輯開啟的場景
例如在邏輯控制中,如何有效的隱藏顯示模型:
//隱藏所有裝置 ModelBussiness.prototype.hideAllDevModels = function (timelong, callBackFunc) { var _this = this; var devModels = _this.getAllDevModels(); if (devModels && devModels.length > 0) { WT3DObj.commonFunc.changeObjsOpacity(devModels, 1, 0.01, timelong ? timelong : 1000, function () { $.each(devModels, function (_index, _obj) { _obj.visible = false; }); WT3DObj.commonFunc.changeObjsOpacity(devModels, 0.9, 1, 1, function () { if (callBackFunc) { callBackFunc(); } }); }); } } ModelBussiness.prototype.showAllDevModels = function (timelong, callBackFunc) { var _this = this; var devModels = _this.getAllDevModels(); if (devModels && devModels.length > 0) { $.each(devModels, function (_index, _obj) { _obj.visible = true; }); WT3DObj.commonFunc.changeObjsOpacity(devModels, 0.5,1, timelong ? timelong : 1000, function () { if (callBackFunc) { callBackFunc(); } }); } }
2.3、場景切換
場景切換,除了在場景內部透過事件切換的方式,還有就是大場景切換
對於大場景切換,通常採用兩種方式,一種時改變路由的方式,一種是釋放當前資源,載入新資源
這裡我們採用物件化載入的方式
初始化物件:
$(function () { indexPage = new IndexPage(); indexPage.init(); for (var i = 1; i <= 6; i++) { if (window["System0" + i]) { window["system0" + i] = new window["System0" + i](); window["system0" + i].init(); } } });
//系統1:室內外消防給水系統 function System01() { } //初始化 System01.prototype.init = function () { } //顯示 System01.prototype.show = function () { console.log("顯示室內外消防給水系統"); this.loadVoice(); this.initUI(); modelBussiness.loadDevModels(1, function () { modelBussiness.hideAllInsideBoxs(); }); } System01.prototype.initUI = function () { //主功能 this.nav1 = [ { defaultState: "", name: "全景視角", id: "s01_01", actionStr: "system01.showNavSystem('s01_01')" }, { defaultState: "noselect", name: "剖面視角", id: "s01_02", actionStr: "system01.showNavSystem('s01_02')" }, { defaultState: "noselect", name: "管網視角", id: "s01_03", actionStr: "system01.showNavSystem('s01_03')" }, { defaultState: "noselect", name: "系統部件", id: "s01_04", actionStr: "system01.showNavSystem('s01_04')" } ] //子功能 .... /* 消防水泵 消防供水管道 */ indexPage.showSystemMainNav1(this.nav1); this.nav1State = "s01_01"; indexPage.showSystemMainNav2(this.nav2[0]); this.nav2State = ""; }
2.4、動畫模擬
動畫模擬,這裡採用了配置載入的方式,不用每一個動畫去寫邏輯程式碼,因為涉及到動畫比較多,但動畫都是基於時間線的,所以我們把需要執行的步驟放到配置裡面,再透過統一的方法去呼叫
例如動畫列表配置如下:
{ name: "排煙動畫", children: [ { name: "發生火情", id: "s07_step01", greatePosition: { camera: { x: 6120.260855819656, y: 1344.6126089802272, z: 10903.874792293966 }, target: { x: 743.2076296596372, y: 901.5537889282617, z: -467.5814262976444 } }, actionStr: "system07.showNav2Action(2,'s07_step01')", action: function (callBack) { //剖面圖 $.each(system07.allModels, function (_index, _obj) { if (_obj.hasoldPosition) { _obj.position.y = _obj.hasoldPosition.y ; } _obj.visible = true; }); $.each(system07.foreModels, function (_index, _obj) { if (_obj.hasoldPosition) { _obj.position.y = _obj.hasoldPosition.y + 10000; } else { _obj.hasoldPosition = { y: _obj.position.y }; _obj.position.y = _obj.hasoldPosition.y + 10000; } _obj.visible = false; }); //發生火情 //do something... } }, { name: "感煙探測器", id: "s07_step02_1", greatePosition: { camera: { x: -1388, y: -781, z: -309 }, target: { x: -2119, y: -1106, z: 873 } }, actionStr: "system07.showNav2Action(2,'s07_step02_1')", action: function (callBack) { //do something... } }, { name: "煙感訊號傳送", id: "s07_step02_2", greatePosition: { camera: { x: -1388, y: -781, z: -309 }, target: { x: -2119, y: -1106, z: 873 } }, actionStr: "system07.showNav2Action(2,'s07_step02_2')", action: function (callBack) { //do something... } }, .... { name: "動畫結束", id: "s07_step11", greatePosition: { camera: { x: 1737.3999068753242, y: 2415.4782632988126, z: -333.6159257900231 }, target: { x: 1239.420815260611, y: 1011.0884298164777, z: 2597.9725494779173 } }, actionStr: "system07.showNav2Action(2,'s07_step11')", action: function (callBack) { //刪除船船 //刪除所有ani開頭的模型 //停止旋轉 //縮小擋煙垂壁 } } ] },
執行動畫如下:
//執行動畫 System07.prototype.doAnimation = function (index) { var _this = this; this.doAnimationFlag = true; var actions = system07.nav2[index].children; if (actions && actions.length > 0) { function doaction(action_nub) { $("#" + actions[action_nub].id).attr("class", "nav2res navsys"); if (action_nub > 0) { $("#" + actions[action_nub - 1].id).attr("class", "nav2res navsys noseleced"); } actions[action_nub].action(function () { if (actions[action_nub + 1] && actions[action_nub + 1].action) { doaction(action_nub + 1); } else { _this.doAnimationFlag = false; } }); } doaction(0); } }
由於篇幅原因,我們本節課先到這裡,
下節課主要介紹3D實現配電站、變電所
技術交流 1203193731@qq.com
交流微信:
如果你有什麼要交流的心得 可郵件我
其它相關文章:
webgl(three.js)3D光伏,3D太陽能能源,3D智慧光伏、光伏發電、清潔能源三維視覺化解決方案——第十六課
如何用webgl(three.js)搭建一個3D庫房,3D倉庫3D碼頭,3D集裝箱,車輛定位,叉車定位視覺化孿生系統——第十五課
webgl(three.js)實現室內三維定位,3D定位,3D樓宇bim、實時定位三維視覺化解決方案——第十四課(定位升級版)
使用three.js(webgl)搭建智慧樓宇、裝置檢測、數字孿生——第十三課
如何用three.js(webgl)搭建3D糧倉、3D倉庫、3D物聯網裝置監控-第十二課
如何用webgl(three.js)搭建處理3D隧道、3D橋樑、3D物聯網裝置、3D高速公路、三維隧道橋樑裝置監控-第十一課
如何用three.js實現數字孿生、3D工廠、3D工業園區、智慧製造、智慧工業、智慧工廠-第十課
使用webgl(three.js)建立3D機房,3D機房微模組詳細介紹(升級版二)
如何用webgl(three.js)搭建一個3D庫房-第一課
如何用webgl(three.js)搭建一個3D庫房,3D密集架,3D檔案室,-第二課
使用webgl(three.js)搭建一個3D建築,3D消防模擬——第三課
使用webgl(three.js)搭建一個3D智慧園區、3D建築,3D消防模擬,web版3D,bim管理系統——第四課
如何用webgl(three.js)搭建不規則建築模型,客流量熱力圖模擬
使用webgl(three.js)搭建一個3D智慧園區、3D建築,3D消防模擬,web版3D,bim管理系統——第四課(炫酷版一)
使用webgl(three.js)搭建3D智慧園區、3D大屏,3D樓宇,智慧燈杆三維展示,3D燈杆,web版3D,bim管理系統——第六課
如何用webgl(three.js)搭建處理3D園區、3D樓層、3D機房管線問題(機房升級版)-第九課(一)