使用three.js(webgl)搭建智慧樓宇、設備檢測、數字孿生——第十三課

来源:https://www.cnblogs.com/yeyunfei/archive/2022/08/16/15566365.html
-Advertisement-
Play Games

使用three.js(webgl)搭建智慧樓宇、設備檢測、數字孿生、物聯網3D、物業3D監控、物業基礎設施可視化運維、3D定位、三維室內定位、3d建築,3d消防,消防演習模擬,3d庫房,webGL,threejs,3d機房,bim管理系統 ...


  老子雲:有道無術,術尚可求,有術無道,止於術。

  咱開篇引用老子的話術,也沒其它意思,只是最近學習中忽有感悟,索性就寫了上來。

這句話用現代辯證思維理解,這裡的”道“ 大抵是指方法論,解決大部分問題的一般發展規律,例如學習的方法,解決問題的方法,獲取知識的方法。而這裡的”術“就可以理解為解決具體問題的技術,例如,一門手藝,一項專業,一個技能等。老子的意思是要掌握一般事物的發展規律...

學習技術,也是一樣,比如咱最近專註的3D技術,往行而上了說,道在於實踐中求知的方法論,術在於熟練並應用技術的能力。而往行而下了講,道在於3D具體執行的原理(瞭解掌握webgl),術則在於封裝好的庫的應用(瞭解掌握three.js)

不過現在靜下心,看文字的很少了,上面說教了這麼一堆廢話,我也全當一說,你如讀了,也權當一樂。要是有那麼一點贊同,姑且也就這麼滴吧。

序:

  最近也很長時間沒有記一些博文了,翻了一下之前的項目,重新以現在的角度審度之前的代碼,看看有沒有啥可以提煉,可以改進的點。溫故而知新嗎。

  看自己之前寫的代碼,有些地方能發現一些驚喜,但大部分都是驚嚇,都是寫了啥啊,咋當時就這麼寫了,大多時候都是滿臉的鄙夷。

  這個項目還是好久前的項目,具體時候,不太記得了,是給杭州的一個泵業小鎮做的智慧樓宇。當時說是智慧樓宇,但是監控的設備,並沒有那麼多。估計也是一個試點項目吧。

  智慧樓宇的項目做過好多個,可以看看我之前的一些案例課程:
    物聯網3D,物業基礎設施3D運維,使用webgl(three.js)與物聯網設備結合案例。搭建智慧樓宇,智慧園區,3D園區、3D物業設施,3D樓宇管理系統——第八課

    使用webgl(three.js)搭建3D智慧園區、3D大屏,3D樓宇,智慧燈桿三維展示,3D燈桿,web版3D,bim管理系統——第六課

  閑話少序,咱麽切入正題。

一、整體效果

  首先我們先看一下整體的建模項目效果,如下:

 二、功能展示

  功能還是比較簡單的,無非是一些多角度展示與簡單幾種設備檢測

2.1、視角切換

 視角切換比較再技術上實現比較簡單,主要是改變主攝像機camera的屬性

在場景中調整幾個固定的角度,然後提取攝像機的屬性值,再跟視角按鈕做關聯,這樣就可以簡單實現外場的視角切換了。

2.2、樓層切換

樓層切換稍微複雜一些,這裡主要使用了按需載入,建模時也要考慮到具體場景的應用

 

 樓層切換,首先考慮的是樓層再何時載入,如果一開始全部預載入好,這無疑是對性能與速度的浪費,其次是載入後是否需要銷毀。

 

 例如上圖,場景複原後,內部樓層是否再可視範圍內,對於webgl來說,在場景內的模型,都是需要進行計算繪製的,不管是否被遮擋。

 

 再如上圖,再次調用打開樓層時,如何處理動畫,如何節約資源。這些都是主要的技術點。我們後面節點著重講解方法。這裡著重介紹功能

 2.3、設備監控

智慧樓宇,數字孿生,主要核心在於採集端數據跟展示端數據的關聯控制。

 

如上圖 設備與樓層關聯,定位某種類型設備時,自動展開樓層。

 

三、技術講解

 3.1、建模

  建模除了固有的特效模型需要處理外,其它的就需要根據業務邏輯對模型進行分解,歸類,本著不浪費新能,極致載入的原則。例如這個項目,我們模型分解如下:

  3.1.1外立面模型框架

 

 

初見的場景,只做外立面模型,不做內部模型

{ "show": true, "uuid": "", "name": "bout_f13_0", "objType": "ExtrudeGeometry", "position": { "x": 2117.824, "y": 5950.545, "z": 2309.159 }, "style": { "skinColor": 16711680, "skin": { "skin_up": { "skinColor": 3911420, "materialType": "lambert", "side": 1, "opacity": 1, "imgurl": "../img/3dImg/floor.jpg", "repeatx": true, "width": 0.005, "repeaty": true, "height": 0.005, "envMap": { "name": "skybox", "reflectivity": 0.4, "refractionRatio": 0.4, "combine": "" } }, "skin_down": { "skinColor": 16711680, "side": 1, "opacity": 1 }, "skin_side": { "skinColor": 846790, "side": 2, "opacity": 1 } } }, "scale": { "x": 1, "y": 1, "z": 1 }, "shapeParm": { "points": [{ "x": 0, "y": 0, "type": "nomal" }, { "x": 0, "y": 100, "type": "nomal" }, { "x": 100, "y": 100, "type": "nomal" }, { "x": 100, "y": 2300, "type": "nomal" }, { "x": -50, "y": 2300, "type": "nomal" }, { "x": -50, "y": 2450, "type": "nomal" }, { "x": -2500, "y": 2450, "type": "nomal" }, { "x": -2500, "y": 2300, "type": "nomal" }, { "x": -2650, "y": 2300, "type": "nomal" }, { "x": -2650, "y": 100, "type": "nomal" }, { "x": -2500, "y": 100, "type": "nomal" }, { "x": -2500, "y": 0, "type": "nomal" }], "holes": [] }, "extrudeSettings": { "amount": 1, "curveSegments": 6, "steps": 1, "bevelEnabled": false, "bevelThickness": 1, "bevelSize": 1, "bevelSegments": 1, "extrudePathPoints": [] }, "showSortNub": 5, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "rotation": [{ "direction": "x", "degree": -1.5707963267948966 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }
View Code

3.1.2、獨立樓層模型

 

 

 樓層模型按需載入,即用到時再載入,看不到時直接不載入或者隱藏,模型代碼如下:

[{"show":true,"uuid":"","name":"build_f2_4","objType":"ExtrudeGeometry","position":{"x":-994.227,"y":810,"z":-54.692},"style":{"skinColor":16711680,"skin":{"skin_up":{"skinColor":3911935,"side":0,"opacity":0},"skin_down":{"skinColor":16711680,"side":1,"opacity":1},"skin_side":{"skinColor":2279636,"side":2,"opacity":0.8,"imgurl":"../img/3dImg/dl01.png","repeatx":true,"width":0.0001,"repeaty":true,"height":0.003}}},"scale":{"x":0.35,"y":0.35,"z":1},"shapeParm":{"points":[{"x":-11200,"y":4620,"type":"nomal"},{"x":-11580,"y":4620,"type":"absarc","radius":400,"startAngle":0,"endAngle":1.3962634015954636,"Clockwise":false},{"x":-13000,"y":5380,"type":"nomal"},{"x":-13300,"y":4600,"type":"absarc","radius":810,"startAngle":1.5707963267948966,"endAngle":2.2689280275926285,"Clockwise":false},{"x":-15400,"y":3780,"type":"nomal"},{"x":-15000,"y":3260,"type":"absarc","radius":620,"startAngle":2.6179938779914944,"endAngle":3.9269908169872414,"Clockwise":false},{"x":-13700,"y":1200,"type":"nomal"},{"x":-13150,"y":1710,"type":"absarc","radius":700,"startAngle":4.363323129985823,"endAngle":5.93411945678072,"Clockwise":false},{"x":-12170,"y":2240,"type":"nomal"}],"holes":[]},"extrudeSettings":{"amount":400,"curveSegments":6,"steps":1,"bevelEnabled":false,"bevelThickness":1,"bevelSize":1,"bevelSegments":1,"extrudePathPoints":[]},"showSortNub":6,"customType1":"","customType2":"","animation":null,"dbclickEvents":null,"rotation":[{"direction":"x","degree":-1.5707963267948963},{"direction":"y","degree":0},{"direction":"z","degree":0}],"BindDevId":null,"BindDevName":null,"devInfo":null,"BindMeteId":null,"BindMeteName":null},{"show":true,"uuid":"","name":"build_f1","objType":"ExtrudeGeometry","position":{"x":7715.604,"y":30,"z":2309.159},"style":{"skinColor":16711680,"skin":{"skin_up":{"skinColor":1129349,"side":0,"opacity":0.8,"imgurl":"../img/3dImg/floor1.jpg","repeatx":true,"width":0.001,"repeaty":true,"height":0.001},"skin_down":{"skinColor":16711680,"side":1,"opacity":1},"skin_side":{"skinColor":16777215,"side":2,"opacity":0.8,"imgurl":"../img/3dImg/dl01.png","repeatx":true,"width":0.0001,"repeaty":true,"height":0.003}}},"scale":{"x":1,"y":1,"z":1},"shapeParm":{"points":[{"x":0,"y":0,"type":"nomal"},{"x":0,"y":5000,"type":"nomal"},{"x":-7500,"y":5000,"type":"nomal"},{"x":-7500,"y":4600,"type":"nomal"},peParm":{"points":[{"x":0,"y":0,"type":"nomal"},{"x":0,"y":100,"type":"nomal"},{"x":100,"y":100,"type":"nomal"},{"x":100,"y":2300,"type":"nomal"},{"x":-50,"y":2300,"type":"nomal"},{"x":-50,"y":2450,"type":"nomal"},{"x":-2500,"y":2450,"type":"nomal"},{"x":-2500,"y":2300,"type":"nomal"},{"x":-2650,"y":2300,"type":"nomal"},{"x":-2650,"y":100,"type":"nomal"},{"x":-2500,"y":100,"type":"nomal"},{"x":-2500,"y":0,"type":"nomal"}],"holes":[]},"extrudeSettings":{"amount":300,"curveSegments":6,"steps":1,"bevelEnabled":false,"bevelThickness":1,"bevelSize":1,"bevelSegments":1,"extrudePathPoints":[]},"showSortNub":5,"customType1":"","customType2":"","animation":null,"dbclickEvents":null,"rotation":[{"direction":"x","degree":-1.5707963267948963},{"direction":"y","degree":0},{"direction":"z","degree":0}],"BindDevId":null,"BindDevName":null,"devInfo":null,"BindMeteId":null,"BindMeteName":null},{"show":true,"uuid":"","name":"build_f5","objType":"ExtrudeGeometry","position":{"x":2117.824,"y":2080,"z":2309lickEvents":null,"rotation":[{"direction":"x","degree":-1.5707963267948963},{"direction":"y","degree":0},{"direction":"z","degree":0}],"BindDevId":null,"BindDevName":null,"devInfo":null,"BindMeteId":null,"BindMeteName":null},{"show":true,"uuid":"","name":"build_f13","objType":"ExtrudeGeometry","position":{"x":1557.594,"y":6080,"z":1780.258},"style":{"skinColor":16711680,"skin":{"skin_up":{"skinColor":1129349,"side":0,"opacity":0.8,"imgurl":"../img/3dImg/floor1.jpg","repeatx":true,"width":0.001,"repeaty":true,"height":0.001},"skin_down":{"skinColor":16711680,"side":1,"opacity":1},"skin_side":{"skinColor":16777215,"side":2,"opacity":0.8,"imgurl":"../img/3dImg/dl01.png","repeatx":true,"width":0.0001,"repeaty":true,"height":0.003}}},"scale":{"x":1,"y":1,"z":1},"shapeParm":{"points":[{"x":0,"y":1500,"type":"nomal"},{"x":-1500,"y":1500,"type":"nomal"},{"x":-1500,"y":0,"type":"nomal"},{"x":0,"y":0,"type":"nomal"}],"holes":[]},"extrudeSettings":{"amount":300,"curveSegments":6,"steps":1,"bevelEnabled":false,"bevelThickness":1,"bevelSize":1,"bevelSegments":1,"extrudePathPoints":[]},"showSortNub":5,"customType1":"","customType2":"","animation":null,"dbclickEvents":null,"rotation":[{"direction":"x","degree":-1.5707963267948963},{"direction":"y","degree":0},{"direction":"z","degree":0}],"BindDevId":null,"BindDevName":null,"devInfo":null,"BindMeteId":null,"BindMeteName":null}]
View Code

3.1.3、具體樓層房間模型

這部分模型主要是對樓層模型進行分隔,樓層外圍可以複製,內部不同,這樣我們既可以通過分開建模的方式,實現控制

 

 

 模型代碼如下:

[ { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_left": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_right": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" } } }, "showSortNub": 19, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "rotation": [{ "direction": "x", "degree": 0 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "thick": null, "scale": { "x": 1, "y": 1, "z": 1 }, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }, { "show": true, "uuid": "", "name": "br_f1_w_17", "objType": "cube2", "length": 900, "width": 15, "height": 300, "x": 889.653, "y": 136.966, "z": -315.791, "style": { "skinColor": 16777215, "skin": { "skin_up": { "skinColor": 50175, "side": 1, "opacity": 1 }, "skin_down": { "skinColor": 50175, "side": 1, "opacity": 1 }, "skin_fore": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_behind": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_left": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_right": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" } } }, "showSortNub": 19, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "rotation": [{ "direction": "x", "degree": 0 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "thick": null, "scale": { "x": 1, "y": 1, "z": 1 }, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteNa 1 }, " mgurl": "../img/3dImg/inside_lightmap.jpg" } } }, "showSortNub": 19, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "rotation": [{ "direction": "x", "degree": 0 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "thick": null, "scale": { "x": 1, "y": 1, "z": 1 }, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }, { "show": true, "uuid": "", "name": "br_f1_w_36", "objType": "cube2", "length": 700, "width": 15, "height": 300, "x": 5979.223, "y": 136.966, "z": -2274.46, "style": { "skinColor": 16777215, "skin": { "skin_up": { "skinColor": 50175, "side": 1, "opacity": 1 }, "skin_down": { "skinColor": 50175, "side": 1, "opacity": 1 }, "skin_fore": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_behind": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_left": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_right": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" } } }, "showSortNub": 19, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "rotation": [{ "direction": "x", "degree": 0 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "thick": null, "scale": { "x": 1, "y": 1, "z": 1 }, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }, { "show": true, "uuid": "", "name": "br_f1_w_37", "objType": "cube2", "length": 15, "width": 400, "height": 300, "x": 6328.26, "y": 136.966, "z": -2469.455, "style": { "skinColor": 16777215, "skin": { "skin_up": { "skinColor": 50175, "side": 1, "opacity": 1 }, "skin_down": { "skinColor": 50175, "side": 1, "opacity": 1 }, "skin_fore": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_behind": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.jpg" }, "skin_left": { "skinColor": 50175, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/inside_lightmap.j egree": 0 }], "thick": null, "scale": { "x": 1, "y": 1, "z": 1 }, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }, { "name": "dev_f1_wsd_2OBJCREN1", "objType": "cylinder", "radiusTop": 16, "radiusBottom": 20, "height": 100, "segmentsX": 24, "segmentsY": 0, "openEnded": false, "position": { "x": -61.251, "y": 120.45, "z": 5.971 }, "scale": { "x": 1, "y": 1, "z": 1 }, "rotation": [{ "direction": "x", "degree": 0 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "style": { "skinColor": 16776960, "skin": { "skin_up": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_3.jpg" }, "skin_down": { "skinColor": 16777215, "side": 1, "opacity": 1 }, "skin_side": { "skinColor": 16777215, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_4.jpg", "repeatx": true, "width": 3, "repeaty": true, "height": 1 } } }, "showSortNub": 7, "show": true, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }, { "show": true, "uuid": "", "name": "dev_f1_wsd_2OBJCREN2", "objType": "cube2", "length": 210, "width": 20, "height": 160, "x": 0, "y": 0, "z": -61.333, "style": { "skinColor": 16777215, "skin": { "skin_up": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_3.jpg" }, "skin_down": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_3.jpg" }, "skin_fore": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_1.jpg" }, "skin_behind": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_1.jpg" }, "skin_left": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_1.jpg" }, "skin_right": { "skinColor": 16777215, "side": 1, "opacity": 1, "imgurl": "../img/3dImg/wsd/wsd_1.jpg" } } }, "showSortNub": 6, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "rotation": [{ "direction": "x", "degree": 0 }, { "direction": "y", "degree": 0 }, { "direction": "z", "degree": 0 }], "thick": null, "scale": { "x": 1, "y": 1, "z": 1 }, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }], "showSortNub": 43, "customType1": "", "customType2": "", "animation": null, "dbclickEvents": null, "BindDevId": null, "BindDevName": null, "devInfo": null, "BindMeteId": null, "BindMeteName": null }]
View Code

3.2、邏輯代碼

 

 

 上面講過模型建模時的註意事項,下麵就是對分解好的模型進行應用。

  3.2.1、視角切換

  主要調用切換視角得方法WT3DObj.commonFunc.changeCameraPosition

   $(".floorNub").click(function () {//2D頁面按鈕事件綁定
        $(".floorNub").attr("class", "floorNub")
        $(this).attr("class", "floorNub action");
        var id= $(this).attr("id");
        if(indexpage.btn_action){
            layer.msg("動畫執行中...");
            return;
        }
        indexpage.btn_action = true;
        switch (id) {
            case "Btn_1"://視角一
                {
                    WT3DObj.commonFunc.changeCameraPosition( {x: 9487.603167348385, y: 8719.775524425808, z: 10591.130126266144},{x: 4356.640551613654, y: 4840.572823023986, z: 3600.0637528600773}, 1000,
                         function () {
                             indexpage.btn_action = false;
                         });
                }
                break;}}

});

 

  3.2.2、樓層分解

    //出發切換樓層方法

    case "Btn_5"://樓層一
                {

                    modelBussiness.backToAllBuild(function () {
                        modelBussiness.showFloor(1);
                        setTimeout(function () {
                            indexpage.btn_action = false;
                        }, 1000);
                    });
                }
                break;

  調用showFloor方法,方法具體如下

ModelBussiness.prototype.showFloor = function (floornub) {

    modelBussiness.currentState = "rooms";
    WT3DObj.IsStepFirstBackSide = true;
    //顯示樓層
    modelBussiness.clickFloorAnimation(floornub);
    layer.closeAll();
}

這裡主要調用clickFloorAnimation方法,並且記錄當前狀態

ModelBussiness.prototype.clickFloorAnimation = function (_floorNub) {
    modelBussiness.loadFloorRooms(_floorNub);//載入樓層
     modelBussiness.showFloorAnimation(_floorNub);//顯示樓層
    var floors = modelBussiness.InfloorBuildCache;
  
    var position = { y: 1}
    new showSlowly(position).to({
        y: 500,
    }, 500).onUpdate(function () {
        var _this = this;
        $.each(floors, function (_i, _o) {
            var _fnub = parseInt(_o.name.replace("build_f", ""));
            if (_fnub > _floorNub) {
            _o.position.y = _o.oldPositiony + (_fnub - _floorNub) * _this.y;
            }
        })
    }).onComplete(function () {
        var oobjs = [];
        $.each(floors, function (_i, _o) {
            var _fnub = parseInt(_o.name.replace("build_f", ""));
            if (_fnub > _floorNub) {
                oobjs.push(_o);
            }
        });
        WT3DObj.commonFunc.changeObjsOpacity(oobjs, 1, 0.01, 1000, function () {
            $.each(oobjs, function (_i, _o) {
                _o.visible = false;
                _o.position.y = 100000;
            });
        });
        if(_floorNub<=3){
            WT3DObj.commonFunc.changeCameraPosition({ x: 3873, y: 8547 + (_floorNub - 1) * 400, z: 5275 },
                  { x: 3639, y: 3780 + (_floorNub - 1) * 400, z: 2556 }, 1000, function () { });
        } else {
            WT3DObj.commonFunc.changeCameraPosition({ x: 756.8552720903069, y: 4080 + (_floorNub - 1) * 400, z: 3005.0971402300224 }, { x: 778.609209478186, y: (_floorNub - 1) * 400, z: 1208.2712831508117 }, 1000,
             function () {
             });
        }
        var position = { y: 500 }
        new showShowly(position).to({
            y: 2000,
        }, 1000).onUpdate(function () {
            var _this = this;
            $.each(floors, function (_i, _o) {
                var _fnub = parseInt(_o.name.replace("build_f", ""));
                if (_fnub > _floorNub) {
                _o.position.y = _o.oldPositiony + (_fnub - _floorNub) * _this.y;
                _o.step2Positiony = _o.oldPositiony + (_fnub - _floorNub) * _this.y;
                }
            });
        }).onComplete(function () {
            

        }).start();
    }).start();
}

按需載入得方法,對不同樓層 按需載入對應得模型

ModelBussiness.prototype.loadFloorRooms = function (nub, floor) {
    var floorname = "build_f" + nub;
    if (nub == 2) {
        floorname += "_1";
    }
    var floor = WT3DObj.commonFunc.findObject(floorname);
    if (modelBussiness.RoomModels["f" + nub]){
        $.each(modelBussiness.RoomModels["f" + nub], function (_index, _obj) {
            _obj.visible = true;
            _obj.position.y = _obj.oldPositiony;
        });
        return;
    }
    if (nub >= 5) {
        var models = getF5Rooms();
        $.each(models, function (_index, _obj) {
            _obj.name = _obj.name.replace("br_f4_", "br_f" + nub+"_");
            if (_obj.name.indexOf("text") >= 0) {
                _obj.position.y = floor.position.y + 550;
            } else {
                if (_obj.position) {
                    _obj.position.y = floor.position.y+500;
                } else {
                    _obj.y = floor.position.y+150;
                }
            }
        });
        WT3DObj.commonFunc.loadModelsByJsons(models, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0 }, true, function () {
            modelBussiness.RoomModels["f" + nub] = [];
            $.each(WT3DObj.scene.children, function (_index, _obj) {
                if (_obj.name.indexOf("br_f" + nub + "_w_") == 0 || _obj.name.indexOf("br_f" + nub + "_r_") == 0) {
                    _obj.oldPositiony = _obj.position.y;
                    modelBussiness.RoomModels["f" + nub].push(_obj);
                };
            });
        });
    } else {
        var models = window["getF"+nub+"Rooms"]();
        WT3DObj.commonFunc.loadModelsByJsons(models, { x: 0, y: 0, z: 0 }, { x: 0, y: 0, z: 0 }, true, function () {
            modelBussiness.RoomModels["f" + nub] = [];
            $.each(WT3DObj.scene.children, function (_index, _obj) {
                if (_obj.name.indexOf("br_f" + nub + "_w_") == 0 || _obj.name.indexOf("br_f" + nub + "_r_") == 0) {
                    _obj.oldPositiony = _obj.position.y;
                    modelBussiness.RoomModels["f" + nub].push(_obj);
                }
            });
        });
    }
}

樓層展開,虛化等動畫統一展示方法:

ModelBussiness.prototype.showFloorAnimation = function (floornub) {
    modelBussiness.hidemodelsCache = null;
    modelBussiness.scaleModels = null;
    var hidemodeNames = ["bout_f13_2", "bout_f13_1", "bout_f13_1", "bout_f13_0", "bout_flow2_1", "bout_flow2_2", "bout_flow2_3"];
    for (var i = 1; i <= 12; i++) {

        hidemodeNames.push("build_out"+i);
    }
        var hidemodeModels = WT3DObj.commonFunc.findObjectsByNames(hidemodeNames);
        $.each(hidemodeModels, function (_index, _obj) {
            _obj.oldPositiony = _obj.position.y;
            _obj.visible = false;
            _obj.position.y = 200000;
        });
        var scaleModelNames = ["bout_39", "bout0_11", "bout_42", "bout_38", "bout_45", "bout_40", "bout_44", "bout_41", "bout_43"];
        var scaleModels = WT3DObj.commonFunc.findObjectsByNames(scaleModelNames);
        WT3DObj.commonFunc.changeObjsOpacity(scaleModels, 1, 0.01, 1000, function () {
            $.each(scaleModels, function (_index, _obj) {
                _obj.oldScaleX = _obj.scale.x;
                _obj.oldScaleY = _obj.scale.y;
                _obj.oldScaleZ = _obj.scale.z;
                if (["bout_39", "bout_38", "bout_40", "bout_41"].indexOf(_obj.name) >= 0) {
                    _obj.scale.y = floornub / 14
                }
                if (["bout_42", "bout_45", "bout_44", "bout_43", "bout0_11"].indexOf(_obj.name) >= 0) {
                    _obj.scale.z = floornub / 14
                }
                if ("bout0_11" == _obj.name) {
                    _obj.scale.z = (floornub - 3) / 11
                }
            });
            WT3DObj.commonFunc.changeObjsOpacity(scaleModels, 0.01, 1, 10, function () {
            });
        });
        modelBussiness.hidemodelsCache = hidemodeModels;
        modelBussiness.scaleModels = scaleModels;
        
}

 

   3.2.3、設備定位

  定位具體設備,將樓層展開與主攝像機位置調整並用起來調用

      modelBussiness.backToAllBuild(function () {
                        modelBussiness.showFloor(4);//展開樓層4
                        setTimeout(function () {
                  //調整攝像機位置 WT3DObj.commonFunc.changeCameraPosition({x:
853.7726152337735, y: 3002.9928530489865, z: 2579.4120334043137},{x: 1732.9469861751966, y: 1855.692424929085, z: 1402.3507946674324}, 1000, function () { indexpage.btn_action = false; }); }, 1000); });

 

3.3、數據對接、展示

  數據對接,主要是講模型與設備數據id進行綁定,並且根據api進行調用

function W3DShowApi() { }
 
//顯示設備自定義框
W3DShowApi.prototype.showDevWin = function (modelname) {
    console.log("顯示樓層數字的自定義框");
    //這裡的showHtml可以自定義
   
    var showHtml = "<div style='font-size:32px;color:white;text-align:center;line-height:90px;'>自定義內容:" + modelname + "</div > ";
    //這裡的顯示框大小可以自定義
    var area = ['auto', "100px"];//寬 高
    return {
        html: showHtml,
        area: area
    }
}
W3DShowApi.prototype.dbclickDevWin = function (modelname) {
    console.log("顯示樓層數字的自定義框");
    //這裡的showHtml可以自定義
    layer.msg("顯示雙擊設備自定義框:" + modelname);
}

var w3DShowApi = new W3DShowApi();

我們這裡彈窗使用了layerui的插件

ModelBussiness.prototype.showRoomMsg = function (_obj) {
    var showWindow = false;
    var showHtml = "<div></div>";
    var area = ["350px", "200px"];
    if (w3DShowApi) {
        var wparam = w3DShowApi.showDevWin(_obj.name);
        if (wparam) {
            showHtml = wparam.html;
            area = wparam.area;
            showWindow = true;
        }
    }
    if (!showWindow) {
        return;
    }
    modelBussiness.hasshowRoomMessage = false;
    modelBussiness.currentShowRoomText = _obj;
    //獲取位置
    var position = {
        x: _obj.position.x,
        y: _obj.position.y,
        z: _obj.position.z,
    };
    //position.y += 150;
    var screenPostion = WT3DObj.transToScreenCoord(position);
    $("#MarkMessageHelper").remove();
    $("body").append("<div id='MarkMessageHelper' style='position:absolute;left:" + (screenPostion.x) + "px;top:" + screenPostion.y + "px;height:2px;width:2px;z-index:1000;'></div>");
    layer.closeAll();
   
    modelBussiness.currentShowRoomTipIndex = layer.tips(showHtml, '#MarkMessageHelper', {
        closeBtn: 1,
        shade: false,
        shadeClose: true,
        skin:"customskin",
        area: area,
        time: 0,//是否定時關閉,0表示不關閉
        cancel: function (index, layero) {
            modelBussiness.hasshowRoomMessage = false;
            layer.close(index);
            if (closeFunc) {
                closeFunc();
            }
        },
        success: function () {
            setTimeout(function () {
            modelBussiness.hasshowRoomMessage = true;
            }, 150);
        },
        tips: [1, "rgba(0,0,0,0.1)"] //還可配置顏色
    });
}

由於篇幅原因,這一課先介紹到這裡 

後面我將繼續講解用webgl 建立 3D隧道、3D橋梁、webgl實現三維隧道橋梁、three.js實現三維隧道橋梁、橋梁隧道三維應用炫酷效果等等

技術交流 [email protected]

交流微信:

    

如果你有什麼要交流的心得 可郵件我或者微我

 

其它相關文章:

如何用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機房管線問題(機房升級版)-第九課(一)


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Kotlin協程是學習Kotlin的重中之重,也是運用koitlin的關鍵。本篇文章主要介紹Kotlin協程的創建、協程調度與協程掛起部分內容,對相關內容進行細緻解析。 ...
  • 大家小時候在玩玩具時肯定都幻想過這樣的場景:想象著自己手上的玩具能動起來,就像《玩具總動員》里的玩具們一樣有自己的性格,能夠和自己一起玩耍。以前我也一直以為玩具總動員只是童話,讓玩具擁有靈魂,能夠動起來的想法只是幻想。但如今HMS Core 3D建模服務讓這一幻想變成了現實。 原理解釋 使用HMS ...
  • Vue組件的繼承用法 點擊打開視頻講解 vue組件的繼承適用於UI幾乎一樣,只是數據不一樣的情況下,但是這種情況通過統一封裝組件也是能實現的,小功能建議用封裝,大功能建議用組件繼承,因為大功能在結合搜參數的需要多重的判斷,這樣會導致封裝的組件比較繁雜,出現過多的判斷,用繼承可以改寫基類中的方法和數據 ...
  • 2 基本語法 2.1 JavaScript簡介 JavaScript 是一門解釋型語言,其代碼在客戶端中執行前不需經過編譯,而是直接由瀏覽器解釋執行。主要用作客戶端腳本語言,在瀏覽器中執行。但隨著Node.js的問世,JavaScript 也逐漸開始被用來編寫伺服器端程式。 JavaScript 不 ...
  • display , visibility 僅會改變元素顯示,不會改變元素種類。可以配合 js 使用使元素可以動態的顯示隱藏。 可以使用 display 或 visibility 實現html元素的隱藏功能,但是這兩種方式有不一樣的地方。display 中的 none 值隱藏,元素後不會在占據頁面空間 ...
  • 高階組件(HOC) 高階組件(Heigher Order Component)也被稱之為高階函數,容器組件,高階組件是類組件編程中的一種重要代碼邏輯復用技巧。 高階組件的語法 接收一個React組件作為入參,經過修飾,最後返回一個新的React組件,所以這個入參的React組件被稱之為“UI組件”; ...
  • 1 HTML定義 HTML(英文Hyper Text Markup Language的縮寫)中文譯為“超文本標簽語言”,主要是通過HTML標簽對網頁中的文本、圖片、聲音等內容進行描述。 <strong> 加粗字體 </strong> 2 HTML的骨架格式 <HTML> <head> <title> ...
  • 在React中上下文是一種通信方案。 上下文的特點 在組件樹中,是一種自上而下的單向數據流通信方案,數據只能從父組件註入,在子組件中訪問。 組件關係只要滿足“父組件-後代組件”這種關係時,都可以使用上下文通信。 在父組件中provide提供數據,在後代組件中註入並使用,這種通信不具有響應式,有點像v ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...