基於 HTML5 WebGL 的 3D 風機 Web 組態工業網際網路應用

圖撲軟體發表於2020-04-06

前言

在目前大資料時代背景之下,資料視覺化的需求也變得越來越龐大,在資料視覺化的背景之下,通過智慧機器間的連結並最終將人機連結,結合軟體和大資料分析的工業網際網路也將變得越來越容易實現!

國家也敏銳意識到時代特性並及時把握時機,培育新的經濟增長點,推動“中國製造”升級,實現工業大國到工業強國的質變,而諸多的業內人士也正在努力完成對自己的“升級”與“改造”,而大資料的資料視覺化與工業的結合,實現了工控的視覺化,大大地提高工控管理效率,風險把控能力,產業流程有效監督等等。

如今得益於基於 HTML5 WebGL 的出現,從技術上實現工控數字化管理模式變得簡單易行,核心提高對工控裝置資訊的視覺化與管理效率,可以實時掌握裝置每個引數的狀態,對資源的實時管理,對整體執行穩定性風險度有極高的可控性。

如下所示,便是一個基於 HTML5 WebGL 的 3D 風機 Web 組態工業網際網路應用中的風機專案:

此專案連結:基於 HTML5 WebGL 的 3D 風機 Web 組態工業網際網路應用(http://www.hightopo.com/demo/FanDevice/)

從上面設計圖中可以看到頁面佈局主要四部分組成:table 表格,錶盤,echarts 圖表,3d 風機模型。

在這個頁面中非常具體而又全面的展示了風機裝置的相關裝置資訊,比如風機裝置名稱,風機引數,發電量資料,機艙溫度以及功率風速折線圖表等等,這對於管理員而言是一種享受!

在 3d 風機模型出可以對風機進行拉近拉遠等互動,實現風機外殼透明化、隱藏、顯示效果,如圖所示:

 

在拉近風機隱藏風機外殼顯示內部部件時候可以點選部件獲取點選部件詳細資訊:

 

在如上整個風機專案中技術核心同時也是難點的是對 3d 風機模型的互動操作實現上,在此我把 3d 風機模型單獨拿出來做講解,其完整風機互動效果如下動圖所示:

 

在如上的專案中使用的風機模型是通過 MAYA 和 MODO 建模製作而成,這兩個工具匯出的 obj 和 mtl 檔案。

在開始操作之前先確認需求,從上面效果圖中分析可以看到主要有三個功能需求:

1、滾輪滾動時風機外殼透明化到隱藏再到顯示效果;

2、點選風機內部部件時有對應的彈窗出現以及點選彈窗隱藏;

3、風機葉片旋轉效果;

在明確所需要的互動功能需求後,我們就可以一步一步來實現它。

實現功能

1,滾輪滾動時風機外殼透明化到隱藏效果

由於該風機場景是由多個子模型拼裝形成,所以在載入場景時候存在子模型載入的非同步問題,存在的非同步問題會導致在獲取子模型並對其繫結事件時候發生錯誤,比如提示該子模型 undefined,所以要先解決這個問題。

ht.Default.handleModelLoaded = function (data) {
    //模型載入完成時回撥
}

通過 handleModelLoaded 解決模型載入非同步問題後,就可以在函式內針對模型進行事件繫結操作。

首先宣告一個陣列,是三個模型的 tag 名,通過後面的 for 迴圈獲取這三個模型:

//風機三個外殼
var fanArr = ['風機_葉片', '風機_機箱外殼2', '風機_輪轂外殼'];

然後在 handleModelLoaded 方法的函式內對風機外殼模型進行操作:

for (var i = 0; i < fanArr.length; i++) { //滾輪控制拉遠拉近時風機部件透明化
    if (data == 'models/機械裝置/風力發電機/' + fanArr[i] + '.json') {
        var model = ht.Default.getShape3dModel('models/機械裝置/風力發電機/' + fanArr[i] + '.json');
        //通過tag標籤名獲取模型
        var tags = g3d.dm().getDataByTag(fanArr[i]);
        //繫結滾輪事件
        g3d.getView().addEventListener('mousewheel', function (e) {
            //獲取eye到center距離
            //通過distance判斷顯示隱藏的滾輪距離
            var distance = ht.Default.getDistance(g3d.getEye(), [0, 9500, 0]);
            if (distance < 2700 && distance > 2100) {
                //拉近機箱外殼透明化
                tags.setStyle('shape3d.transparent', true);
                tags.setStyle('shape3d.opacity', 0.5);
                tags.setStyle('shape3d.visible', true);
                //拉遠隱藏顯示框
                for (var j2 = 0; j2 < eightArr.length; j2++) {
                    var textViews = g3d.dm().getDataByTag(eightArr[j2] + 'show');
                    textViews.setStyle('3d.visible', false);
                }
            }
            else if (distance > 2700) {
                //拉遠恢復原狀
                tags.setStyle('shape3d.transparent', false);
                tags.setStyle('shape3d.opacity', 1);
            }
            else if (distance < 2100) {
                //拉近隱藏機箱外殼
                tags.setStyle('shape3d.visible', false);
            }
        })
    }
}

如此就實現了第一個目標,成功實現滾輪滾動時風機外殼透明化到隱藏效果。

然後接著第二個目標。

2,點選風機內部部件時有對應的彈窗出現

實現該效果無非就是兩步走,獲取部件模型,然後給模型繫結點選事件(點選顯示彈窗,點選彈窗隱藏彈窗)

首先宣告一個部件陣列:

//風機內部九大部件
var parts = ['風機_控制櫃', '風機_發電機', '風機_風冷裝置', '風機_制動聯結裝置', '風機_油冷裝置', '風機_齒輪箱', '風機_主軸', '風機_轉子齒輪', '風機_變槳系統'];

然後程式碼實現,也是放在 handleModelLoaded 方法的函式內:

//九大部件與彈窗繫結點選事件
g3d.mi(function (e) { //互動事件監聽器
    //繫結點選事件
    if (e.kind === 'clickData') {
        for (var j = 0; j < parts.length; j++) {
            if (e.data.getTag() === parts[j]) {
                for (var j2 = 0; j2 < parts.length; j2++) {
                    //通過tag標籤名獲取模型圖元
                    var textViews = g3d.dm().getDataByTag(eightArr[j2] + 'show');
                    textViews.setStyle('3d.visible', false);
                }
                //通過tag標籤名獲取彈窗圖元
                var textView = g3d.dm().getDataByTag(eightArr[j] + 'show');
                textView.setStyle('3d.visible', true);
            }
            //彈窗點選事件
            if (e.data.getTag() === parts[j] + 'show') {
                var textView2 = g3d.dm().getDataByTag(parts[j] + 'show');
                textView2.setStyle('3d.visible', false);
            }
        }
    }
})

在實現部件點選顯示彈窗和點選彈窗隱藏效果後,就差最後一步,完成風機葉片旋轉效果。

3,風機葉片旋轉效果

風機葉片旋轉原理非常簡單,本質就是控制 rotation 的引數,通過 startAnim 方法遞增引數值實現葉片旋轉動態效果。

還是老路子,先獲取風機葉片模型,然後再修改和賦予 rotation 引數值,程式碼實現也是放在 handleModelLoaded 方法的函式內。

//風機葉片旋轉
if (data == 'models/機械裝置/風力發電機/風機_輪轂外殼.json') {
    var rotation = '';
    var deg = Math.PI / 180;
    var speed = 2;
    function animation() {
        //獲取風機模型
        var modelWheel = g3d.dm().getDataByTag('風機_輪轂外殼');
        ht.Default.startAnim({
            duration: 5500, // 動畫週期毫秒數,預設採用
            action: function (v, t) {
                rotation = [0, 0, deg * (speed--)];
                modelWheel.setRotation3d(rotation);
            },
            finishFunc: function () { //動畫結束後呼叫
                animation();
            }
        })
    }
    animation();
}

4,完整程式碼

完成三個功能需求後完整核心程式碼如下所示:

//風機三個外殼
var fanArr = ['風機_葉片', '風機_機箱外殼2', '風機_輪轂外殼'];
//風機內部九大部件
var parts = ['風機_控制櫃', '風機_發電機', '風機_風冷裝置', '風機_制動聯結裝置', '風機_油冷裝置', '風機_齒輪箱', '風機_主軸', '風機_轉子齒輪', '風機_變槳系統'];
ht.Default.handleModelLoaded = function (data) {
    //模型載入完成的回撥
    for (var i = 0; i < fanArr.length; i++) { //滾輪控制拉遠拉近時風機部件透明化
        if (data == 'models/機械裝置/風力發電機/' + fanArr[i] + '.json') {
            var model = ht.Default.getShape3dModel('models/機械裝置/風力發電機/' + fanArr[i] + '.json');
            // console.log(model);
            var tags = g3d.dm().getDataByTag(fanArr[i]);
            g3d.getView().addEventListener('mousewheel', function (e) {
                //獲取eye到center距離
                var distance = ht.Default.getDistance(g3d.getEye(), [0, 9500, 0]);
                if (distance < 2700 && distance > 2100) {
                    //拉近機箱外殼透明化
                    tags.setStyle('shape3d.transparent', true);
                    tags.setStyle('shape3d.opacity', 0.5);
                    tags.setStyle('shape3d.visible', true);
                    //拉遠隱藏顯示框
                    for (var j2 = 0; j2 < eightArr.length; j2++) {
                        var textViews = g3d.dm().getDataByTag(eightArr[j2] + 'show');
                        textViews.setStyle('3d.visible', false);
                    }
                }
                else if (distance > 2700) {
                    //拉遠恢復原狀
                    tags.setStyle('shape3d.transparent', false);
                    tags.setStyle('shape3d.opacity', 1);
                }
                else if (distance < 2100) {
                    //拉近隱藏機箱外殼
                    tags.setStyle('shape3d.visible', false);
                }
            })
        }
    }
    //九大部件與彈窗繫結點選事件
    g3d.mi(function (e) { //互動事件監聽器
        if (e.kind === 'clickData') {
            for (var j = 0; j < parts.length; j++) {
                if (e.data.getTag() === parts[j]) {
                    for (var j2 = 0; j2 < parts.length; j2++) {
                        var textViews = g3d.dm().getDataByTag(eightArr[j2] + 'show');
                        textViews.setStyle('3d.visible', false);
                    }
                    var textView = g3d.dm().getDataByTag(eightArr[j] + 'show');
                    textView.setStyle('3d.visible', true);
                }
                //彈窗點選事件
                if (e.data.getTag() === eightArr[j] + 'show') {
                    var textView2 = g3d.dm().getDataByTag(eightArr[j] + 'show');
                    textView2.setStyle('3d.visible', false);
                }
            }
        }
    })
    //風機葉片旋轉
    if (data == 'models/機械裝置/風力發電機/風機_輪轂外殼.json') {
        var rotation = '';
        var deg = Math.PI / 180;
        var speed = 2;
        function animation() {
            //獲取風機模型
            var modelWheel = g3d.dm().getDataByTag('風機_輪轂外殼');
            ht.Default.startAnim({
                duration: 5500, // 動畫週期毫秒數,預設採用
                action: function (v, t) {
                    rotation = [0, 0, deg * (speed--)];
                    modelWheel.setRotation3d(rotation);
                },
                finishFunc: function () { //動畫結束後呼叫
                    animation();
                }
            })
        }
        animation();
    }
}

結束語

這個風機 demo 功能的實現整體原理很簡單,萬變不離其宗,最終都是獲取物件然後繫結事件實現效果。再複雜的功能通過解析後發現最終也不過是一個又一個簡單小功能組合到一起最後實現大的功能。

所以在學習過程中基礎最重要,再大的專案解析到最小也還是要通過基礎程式碼一步一步實現。

相關文章