基於 HTML5 WebGL 的加油站 3D 可視化監控

前言html

隨着數字化,工業互聯網,物聯網的發展,我國加油站正向有人值守,無人操做,遠程控制的方向發展,傳統的人工巡查方式逐漸轉變爲以自動化控制爲主的在線監控方式,即採用數據採集與監控系統 SCADA。SCADA 系統的推廣使用,大大提升了我國加油站的監控效率,本文所講的則是經過對加油站的可視化建模,結合 HT 的 3D 可視化以及 2D 監控面板來實現對加油站的可視化監控。三維可視化監控系統是將三維的可視化技術和數據採集與監控技術融合,充分發揮了兩種技術的核心優點,並經過數據庫進行數據共享,共同構成一種全新的 SCADA 系統。該系統中也結合了海康的攝像頭監控,經過調用海康提供的攝像頭地址,實時的將視頻流傳輸到前臺,而且展現在 2d 頁面上。在真實的系統中,每一個加油機以及加油罐都有本身對應須要展現的數據,這個能夠根據本身須要展現的內容來設計 2d 面板,以後根據後臺傳來的數據進行展現。數據採集與監控系統經過各種的傳感器實時採集監控對象的各種數據,上傳數據庫並實時共享給三維可視化技術搭建的監控對象的三維可視化模型及場景,最後經過監控系統直觀的展現出來,極大的提升了監控對象數據的表達能力和工做人員的工做效率。node

該系統中實現了對加油機,油罐的監控,以及對加油站內的攝像頭進行調取並顯示,本文會講解使用 HT 來搭建該系統的步驟,以及對場景中使用到的部分關鍵代碼進行說明。ajax

預覽地址:基於 HTML5 WebGL 的加油站 3D 可視化監控 www.hightopo.com/demo/gas-st…數據庫

界面效果預覽api

視頻監控效果緩存

加油機監控效果bash

油罐監控效果app

加油站切換效果dom

由於系統中對許多的加油站進行建模,因此係統中能夠根據 url 地址的 stationCode 來區分不一樣的加油站,即 stationCode 爲該加油站的惟一標識,固然該系統能夠嵌入到任何第三方的系統中,HT 只須要第三方頁面給一個 dom,就能夠將該頁面放到該 dom 中,例如上圖 3d 場景,ht 能夠經過 g3d.addToDOM(el) 來將 3d 場景的 dom append 到 el 這個 dom 下,g3d 爲 ht 中 ht.graph3d.Graph3dView 的實例,具體可查看 3D 手冊socket

HT 搭建系統步驟

1.製做模型

在 ht 的 3D 場景中部分簡單的建模能夠根據 ht 的 api 來進行搭建,例如牆面,管道,六面體,地板等等基本 3d 模型,例如若是想製做一個三維的球體模型,則能夠經過如下代碼:

1 var node = new ht.Node();
2 node.s({
3     "shape3d": "sphere" // 此處指定該 node style 的 shape3d 爲 sphere 即球體的意思
4 });複製代碼

若是須要使用代碼來進行較爲複雜些的建模,則能夠經過指定模型的頂點信息來進行搭建,大致可理解爲 3d 中的模型都是由三角面進行拼接而成的,因此指定該模型的全部三角面就能夠構造出該模型,三角面又是由三個頂點信息構成,因此指定模型的頂點信息也能夠構建模型,具體能夠參考 建模手冊

可是在咱們這個加油站可視化監控系統中,咱們的加油機模型以及油罐和加油站外景的模型都是十分複雜的模型,若是採用上述兩種方法:

  1. 經過第一種簡單的牆面,球體,六面體等模型拼接出加油站是不現實的,由於模型沒有那麼全面,並且貼圖部分也很差分開貼,因此不可行。
  2. 經過指定頂點信息來構造加油站的全部模型,這部分雖然在理論上是可行的,可是計算頂點信息須要大量的工做,可想而知代碼部分的工做量是不小的,因此不可行。

目前 ht 能夠支持 obj 模型的導入,因此設計師能夠根據加油站拍攝的外景圖片對加油站場景以及加油機,油罐等的模型進行建模,obj 模型可使用主流的 3dMAX 等的建模工具進行搭建,以後導入到 ht 中進行顯示。對於系統中須要交互的模型則要分開進行建模,例如加油機模型不可和加油站場景的 obj 模型在同一個 obj 中,例以下圖分開方式:

2.搭建場景

上一步中咱們已經獲得了場景所須要的全部模型,在 ht 中能夠經過 ht.Default.loadObj(objUrl, mtlUrl, params) 來加載 obj 的模型,以後經過 ht.Default.setShape3dModel(name, model) 來註冊模型,loadObj 用來讀取模型的頂點信息以及貼圖部分的信息,就是上一步中所指的第二點經過頂點信息來構造模型,此時頂點信息已經由 obj 模型提供,因此拿到頂點信息,貼圖等信息以後,能夠經過 setShape3dModel 來註冊模型,具體使用方法請參考 OBJ 手冊,以後能夠經過 ht 的 node 圖元來使用該模型,具體使用方法以下:

1 var node = new ht.Node();
2 node.s({
3     "shape3d": name
4 });複製代碼

上面的 name 就是經過 ht.Default.setShape3dModel(name, model) 中的 name 獲得的,表示此圖元使用該模型來展現。

構成該監控系統的還有用來展現加油機,油罐模型的具體監控參數的面板,ht 中全部的 2d 都爲矢量,因此放大不會失真,2d 面板也是經過一個個圖元進行擺放展現,經過調整每一個圖元的樣式來美化圖元,具體的樣式可參考 風格手冊

油罐 2d 面板展現以下:

3.對接數據

上一步中咱們已經把須要展現的模型以及須要展現的監控數據進行了設計,而且在場景中進行了擺放,因此該步驟中則須要對數據進行對接,目前對接部分包括:

  1. 2d 面板兩側的數據對接
  2. 視頻監控的對接

第一條的對接能夠經過 socket 或者 ajax 來進行,將後臺數據傳輸到前臺以後動態綁定到界面上顯示便可,ht 中經過數據綁定來驅動界面上內容的動態刷新,具體的綁定操做能夠查看 數據綁定手冊

系統中攝像頭監控部分主要是經過將第三方的視頻 dom 嵌入到 ht 的圖紙中,ht 中能夠經過 renderHTML 來嵌入 dom,嵌入 dom 的原理其實也是在圖紙的對應位置加入一個 node 圖元,根據圖紙的縮放值(zoom),以及橫向偏移值(tx),縱向偏移值(ty) 的圖紙信息以及該圖元的 position, width, height 的圖元信息來動態的計算 dom 的寬高和 dom 的位置,具體代碼能夠參考以下:

1 let rect = node.getRect(), // 獲取該 node 的包圍矩形信息
 2 zoom = graphView.getZoom(), // 獲取圖紙的縮放值
 3 tx = graphView.tx(), // 獲取圖紙的橫向偏移值
 4 ty = graphView.ty(); // 獲取圖紙的縱向偏移值
 5 // 下面操做爲對 node 的包圍矩形進行縮放
 6 rect.x *= zoom;
 7 rect.y *= zoom;
 8 rect.width *= zoom;
 9 rect.height *= zoom;
10 
11 // div 的 left 即爲下面的 x 座標, top 即爲下面的 y 座標
12 let x = tx + rect.x;
13 let y = ty + rect.y;
14 
15 div.style.position = 'absolute';
16 div.style.width = rect.width + 'px';
17 div.style.height = rect.height + 'px';
18 div.style.left = x + 'px';
19 div.style.top = y + 'px';複製代碼

上面代碼展現了動態擺放 dom 到 ht 圖紙的原理,因此用戶能夠根據本身的需求將 dom 元素放到 2d 圖紙中去,該系統中的監控模塊 dom 就是經過該方式的原理進行動態擺放,從下圖能夠看出 dom 疊加的效果。

4.製做動畫效果

該系統中動畫效果比較簡單,主要就是點擊加油機或者油罐時,將視角飛向該物體,而且二維面板上顯示對應的監控數據,視角的切換主要是修改 3D 場景的 eye 以及 center 的數據,可是 ht 中提供了更爲方便的操做函數 flyTo,因此主要代碼即爲下面一行:

1 // node 即爲要飛向的節點 例如加油機
2 // 第二參數爲配置參數
3 g3d.flyTo(node, { animation: true, direction: [-16, 6, 8], distance: 600 });複製代碼

上述第二個參數具體可參考上述所提供的 3D 手冊,direction:默認undefined,眼睛處於目標的方向(相對目標,受到目標自身旋轉影響,distance :默認undefined(未定義的話則使用下面的ratio模式計算距離),浮點類型,表示眼睛跟中心的固定距離,上述所用到的兩個參數解釋即爲此。

該函數還有一個使用方法爲當第一參數傳值爲 null 空時,視角會調整看向場景內全部節點,因此利用此功能可能看到加油站的全景。

系統中還有一個效果是虛化背景,虛化背景的原理就是修改場景中全部模型的透明度,例如該系統中經過遍歷全部節點,將當前節點的透明度設置爲 0.1,則在視覺上咱們看到的場景即爲虛化的場景,具體節點的樣式屬性能夠參考上面已經給出的風格手冊,關鍵代碼以下:

1 // 遍歷場景中全部圖元 
 2 dataModel.each((d) = >{
 3     // opacityMap 用來記錄當前某個節點沒有虛化以前的透明度值
 4     if (!opacityMap[d.getId()]) {
 5         opacityMap[d.getId()] = {
 6             'shape3d.opacity': d.s('shape3d.opacity'),
 7             'shape3d.transparent': d.s('shape3d.transparent'),
 8             'all.opacity': d.s('all.opacity'),
 9             'all.transparent': d.s('all.transparent'),
10             'left.opacity': d.s('left.opacity'),
11             'left.transparent': d.s('left.transparent'),
12             'right.opacity': d.s('right.opacity'),
13             'right.transparent': d.s('right.transparent'),
14             'front.opacity': d.s('front.opacity'),
15             'front.transparent': d.s('front.transparent'),
16             'back.opacity': d.s('back.opacity'),
17             'back.transparent': d.s('back.transparent'),
18             'top.opacity': d.s('top.opacity'),
19             'top.transparent': d.s('top.transparent'),
20             'bottom.opacity': d.s('bottom.opacity'),
21             'bottom.transparent': d.s('bottom.transparent'),
22             '3d.selectable': d.s('3d.selectable')
23         };
24     }
25     // 設置當前節點的透明度 opacity 爲須要虛化至多大透明度 系統中爲 0.1
26     d.s({
27         'shape3d.opacity': opacity,
28         'shape3d.transparent': true,
29         'all.opacity': opacity,
30         'all.transparent': true,
31         'left.opacity': opacity,
32         'left.transparent': true,
33         'right.opacity': opacity,
34         'right.transparent': true,
35         'front.opacity': opacity,
36         'front.transparent': true,
37         'back.opacity': opacity,
38         'back.transparent': true,
39         'top.opacity': opacity,
40         'top.transparent': true,
41         'bottom.opacity': opacity,
42         'bottom.transparent': true,
43         '3d.selectable': false
44     });
45 });複製代碼

上面代碼執行以後場景中全部的節點就被虛化,由於每一個節點虛化所須要設置的透明度屬性不一樣,因此一共有上面十幾種樣式屬性須要判斷設置,具體的樣式名稱能夠參考上文提出的風格手冊,如下爲虛化效果:

場景中有雙擊便利店進入便利店內景的操做,具體交互以及效果以下圖:

5.優化場景

當 3d 場景中點或者面的數量較多時,3d 面板,公告板部分較多時,ht 中有幾種優化策略能夠進行優化,咱們知道 3d 場景中的全部模型都是由三角面構成的,而三角面又是由三個頂點構成的,因此若是場景中的點或者面比較多的時候場景會出現必定的卡頓,GPU 渲染會比較費時,在 ht 中能夠經過在控制檯輸入 g3d.showDebugTip() 來顯示當前場景一共有多少面和頂點,具體效果以下:

其中 Vertices 爲點的數量,Faces 爲面的數量。

因此在 ht 中能夠有如下 4 種直觀優化策略能夠優化:

  1. 減小模型的面數
  2. 使用批量處理場景中大量的相同圖元
  3. 對 3d 面板使用緩存
  4. 當場景視角距離較遠時隱藏部分細節圖元,或者當場景視角距離某個模型很近時,隱藏看不見的圖元以提升性能

第一種狀況能夠在設計建模時經過各類減面的手段來減小模型的面數,這一部分優化的空間是最大的,也是效果最明顯的。

第二種狀況可使用批量,批量能提升性能的原理在於,當圖元一個個獨立繪製模型時性能較差,而但一批圖元聚合成一個大模型進行一次性的繪製時, 則會極大提升WebGL刷新性能,具體可參考 批量手冊

第三種狀況使用 shape3d.image.cache 這個屬性來開啓面板的緩存,當咱們一個場景中若是須要使用大量的相似公告板的功能,咱們能夠利用上面的屬性對該節點設置緩存,具體使用方法能夠參考 3D手冊

第四種狀況咱們能夠在眼睛距離場景很遠的時候隱藏部分細節圖元,相似地圖縮放到很小的時候,具體的城市會隱藏掉,放大到具體模型細節時,其它看不見的圖元能夠相應設置隱藏,這樣能夠提升很多的性能。

手機端效果

相關文章
相關標籤/搜索