油田系統(tǒng)三維布局可視化解決方案

最近和一家公司在談一個項(xiàng)目合作,他們公司主要是做油田相關(guān)設(shè)備的渐裸,比如油罐車、壓力車装悲、泵車等昏鹃。

我的印象中只要和石油相關(guān)的企業(yè),就感覺和錢挨得好近诀诊,?? 洞渤。

他們老板看了我們公司的三維產(chǎn)品后,大為贊嘆属瓣。 驚呼载迄,我們油田的管理最好也能上一套這樣的三維系統(tǒng)。

油田行業(yè)的三維可視化項(xiàng)目抡蛙,我們之前沒有做過相關(guān)的行業(yè)护昧,但是在三維可視化方面,我們經(jīng)驗(yàn)還是挺多的溜畅,比如數(shù)據(jù)中心捏卓、醫(yī)院、學(xué)校等三維可視化項(xiàng)目慈格,還包括智慧園區(qū)怠晴、智慧城市、智慧小鎮(zhèn)的方向的等三維可視化浴捆。

下面先上幾張三維可視化的圖瞅瞅:

園區(qū)
數(shù)據(jù)中心
智慧園區(qū)

雖然我們沒有直接做過油田的三維可視化蒜田,但是有了以上三維方案的技術(shù)積累,這事做起來就不會太難选泻。

其實(shí)客戶的需求冲粤,并不是就某個油田場景進(jìn)行三維可視化的場景搭建美莫。而是要做一個油田三維的布局工具,通過布局工具梯捕,可以自由搭建不同的油田場景厢呵。

這比直接搭建一個三維的場景要難許多。

所謂萬事開頭難傀顾,難在不開頭襟铭。 天下事有難易乎,干就完了短曾。

在商務(wù)人員和客戶確立合同寒砖,正式立項(xiàng)后, 我們的設(shè)計小姐姐嫉拐,開發(fā)小哥哥哩都,都各司其職,下邊就講一下項(xiàng)目的大概內(nèi)容。

搭建模型庫

第一步要做的就是建模婉徘,設(shè)計組使用3D建模工具 3d max或者c4d 進(jìn)行油田設(shè)備模型的建模漠嵌。建模后,導(dǎo)出后綴為obj或者gltf格式文件判哥,這兩種格式是我們?nèi)S渲染引擎支持的最好的文件格式献雅。

建模后的所有模型文件碉考,最終會放到后端的模型庫塌计,模型庫的管理目錄如下圖所示:

模型列表

加載模型

加載模型可使用引擎模型的加載函數(shù)進(jìn)行模型加載,比如obj模型加載侯谁,示例代碼如下:

new mono.OBJMTLLoader().load( 'yaliche.obj', 'yaliche.mtl', '',  (node)=> {
    node.type = 'obj';
    box.addByDescendant(node);
  },
);

上面加載了一個壓力車的模型锌仅,加載模型是一個異步的過程,所以會有一個回調(diào)函數(shù)墙贱,加載完成之后热芹,在回調(diào)函數(shù)中,把模型文件生成的三維對象加入到場景容器box之中惨撇,加入之后伊脓,場景中就會顯示我們的三維對象,如下圖所示:

壓力車

搭建編輯器框架

在和設(shè)計組极颓、開發(fā)組一起探討之后喜庞,我們編輯器的框架和視圖初步設(shè)計出來了偎谁,大致樣子如下:

編輯器框架

視圖左上角是我們的logo,上方是工具欄纯蛾。左側(cè)分為場景區(qū)和組件區(qū),場景區(qū)是創(chuàng)建三維場景的列表纵隔,組件區(qū)主要是模型列表翻诉,同時還有些echarts圖表組件炮姨。

中間部分是三維場景呈現(xiàn)區(qū)。

對于這個頁面布局碰煌,我想不用做太多技術(shù)上的闡述舒岸,基本上會一點(diǎn)前端開發(fā)的人員都可以實(shí)現(xiàn)類似的效果。

<div class="layui-layout layui-layout-admin">
      <div class="layui-side layui-bg-black" id="leftTreeWrap">
        <div class="layui-side-scroll">
          <div class="layui-collapse" id="leftTree">
            <div class="sceneTreeWrap">
              <div class="groupTitle">
                場景
              </div>
              
            </div>
            <div class="groupTitle">
              組件
            </div>

            <div id="modelGroupWrap">
              <!-- <div class="layui-colla-item modelGroup not-select" id="groundWrap">
                <h2 class="layui-colla-title"><span>場景模型</span></h2>
                <div class="layui-colla-content" id="groundTree">
                  <div class="tree-wrap"></div>
                </div>
              </div> -->
            </div>
          </div>
        </div>
      </div>
      <div class="layui-body">
        <div class="toolbar">
          <div class="temporaryTool"></div>
        </div>
        <div class="app" tabindex="0">
          <canvas id="monoCanvas"></canvas>
        </div>
      </div>

左側(cè)邊欄包括兩個部分芦圾,一個是場景列表吁津,一個是模型列表。場景列表是樹組件堕扶,模型列表是手風(fēng)琴組件碍脏,如下圖所示:


列表

模型列表的創(chuàng)建過程是這樣的,首先從后端獲取所有的模型:

 getComponentTree({ params: { owner: user } }, '同步云端組件樹失敗').then((res) => {
      if (res) {
        const treeData = res.data.data;
        treeData.forEach(({ data }) => {
          this.appendModelBtn(data, true);
        });
        // this.renderTreeDom(res.data.data);
      }
    });

通過每個模型創(chuàng)建模型對于的button稍算,函數(shù)是appendModelBtn典尾,如下:

 appendModelBtn(modelData, isNew) {
    const domWrap = this.groupDom[modelData.group];
    if (!domWrap) {
      console.log('缺少該類型對應(yīng)的組', modelData.group);
      if (modelData.category === 'skyBox') {
        modelData.isNew = true;
        skyData.push({ modelData });
      }
    } else {
      domWrap.querySelector('.tree-wrap').appendChild(this.createModelBtnDom(modelData, isNew));
    }
  }

需要注意的,每個模型按鈕都需要有drag and drop的功能糊探。在模型按鈕上需要監(jiān)聽drag 或者dragstart事件钾埂,這個被封裝到一個獨(dú)立的類Dragger.js里面,在該類中專門處理了dragstart事件:

 addDragger(parent, subClass, option) {
    parent.addEventListener('dragstart', (e) => {
      let target = null;
      //  拿到冒泡的所有元素
      const path = eventPath(e);
      for (let i = 0; i < path.length; i += 1) {
        if (path[i].classList && path[i].classList.contains(subClass)) {
          target = path[i];
          break;
        }
      }
...
}

中間區(qū)域是三維呈現(xiàn)區(qū)域科平。 首先創(chuàng)建一個Network3D對象褥紫,Network3D對象是封裝的三維呈現(xiàn)頁面,其底層是由canvas組成的瞪慧,并使用webgl技術(shù)進(jìn)行三維渲染髓考。下面是創(chuàng)建Network3D的代碼:

 const network = new mono.Network3D(box, null, 'monoCanvas');
    network.mode = 'editor';
    window.network = network; // todo
    this.network = network;
    network.bindApp(this);
    network.setRenderSelectFunction(() => false);
    make.Default.path = './static/myModellib/';

    network.setClearColor(0, 0, 0);
    network.setClearAlpha(0);

創(chuàng)建對象之后,讓network可以和中間區(qū)域的大小自適應(yīng):

 mono.Utils.autoAdjustNetworkBounds(
      network,
      document.querySelector('.app'),
      'clientWidth',
      'clientHeight',
    );

其中network上的box對象用于管理要加載的三維對象模型弃酌。前面說過在模型列表上增加了drag事件氨菇,模型列表上的模型,通過拖拽可以添加到network對象上去妓湘,因此在network上面也需要添加對應(yīng)的事件來添加對象:

 onup: (e) => {
        if (!this.sceneTree.senceId && !window.debug) {
          layui.layer.msg('請先創(chuàng)建或選擇場景', {
            time: 2000,
          });
          return;
        }
        //  鼠標(biāo)不在畫布內(nèi)的時候不創(chuàng)建
        if (isPosInCanvas(network, e)) {
          network.createElement({
            e,
            configString,
            senceId: this.sceneTree.senceId,
          });
        }
      },

當(dāng)模型從左側(cè)模型列表拖拽到network對象后查蓉,鼠標(biāo)mouseup事件后,創(chuàng)建模型實(shí)例:

 network.createElement({
            e,
            configString,
            senceId: this.sceneTree.senceId,
          });

到目前為止榜贴,已經(jīng)完成了整個模型列表加載豌研,模型拖拽創(chuàng)建模型實(shí)例的過程。 比如最終通過拖拽的油田場景如下所示:

拖拽的油田場景

在3d場景中唬党,需要調(diào)整三維模型的位置鹃共、旋轉(zhuǎn)角度和縮放比例,可以通過屬性面板來調(diào)整:


屬性面板

也可以通過三維編輯功能直接在三維場景中對模型進(jìn)行調(diào)整標(biāo)記初嘹,要使用調(diào)整編輯功能及汉,只需要加入如下這行代碼即可:

 const editInteraction = new mono.EditInteraction(network);
    editInteraction.setScaleable(false);
    editInteraction.setRotateable(false);
    editInteraction.setTranslateable(true);
    editInteraction.setDefaultMode('');

    network.setInteractions([...network.getInteractions(), editInteraction]);

EditInteraction類 用于調(diào)整模型的位置、旋轉(zhuǎn)角度和縮放比例屯烦。 通過鍵盤可以調(diào)整EditInteraction當(dāng)前要調(diào)整的是那個屬性:

case 82: // r 在有選中element時坷随,切換操作為旋轉(zhuǎn)
          if (this.network.getIsMonoElement(this.network.currComponent)) {
            const editInteraction = this.network.getInteractions()[2];
            editInteraction.setScaleable(false);
            editInteraction.setRotateable(true);
            editInteraction.setTranslateable(false);
          }
          break;
        case 84: // t 在有選中element時房铭,切換操作為移動
          if (this.network.getIsMonoElement(this.network.currComponent)) {
            const editInteraction = this.network.getInteractions()[2];
            editInteraction.setScaleable(false);
            editInteraction.setRotateable(false);
            editInteraction.setTranslateable(true);
          }
          break;
        case 89: // y 在有選中element時,切換操作為縮放
          if (this.network.getIsMonoElement(this.network.currComponent)) {
            const editInteraction = this.network.getInteractions()[2];
            editInteraction.setScaleable(true);
            editInteraction.setRotateable(false);
            editInteraction.setTranslateable(false);
          }
          break;

r鍵切換為旋轉(zhuǎn)角度的調(diào)整:


旋轉(zhuǎn)

t鍵切換為位置的調(diào)整:


平移

y鍵切換為縮放的調(diào)整:


縮放

拖拽創(chuàng)造場景之后温眉,每個對象還可以進(jìn)行實(shí)時數(shù)據(jù)的對接缸匪,對接后呈現(xiàn)的效果如下:


實(shí)時數(shù)據(jù)

在完成場景的創(chuàng)建和數(shù)據(jù)的對接之后,便可以發(fā)布場景类溢,點(diǎn)擊工具欄的預(yù)覽按鈕凌蔬,即可以完成場景的發(fā)布和預(yù)覽。上一張最終發(fā)布的效果圖如下:

最終效果

有興趣獲取編輯器的闯冷,請發(fā)郵件到:
terry.tan@servasoft.com

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末砂心,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子蛇耀,更是在濱河造成了極大的恐慌辩诞,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纺涤,死亡現(xiàn)場離奇詭異译暂,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)撩炊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進(jìn)店門外永,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人拧咳,你說我怎么就攤上這事伯顶。” “怎么了呛踊?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵砾淌,是天一觀的道長。 經(jīng)常有香客問我谭网,道長,這世上最難降的妖魔是什么赃春? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任愉择,我火速辦了婚禮,結(jié)果婚禮上织中,老公的妹妹穿的比我還像新娘锥涕。我一直安慰自己,他們只是感情好狭吼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布层坠。 她就那樣靜靜地躺著,像睡著了一般刁笙。 火紅的嫁衣襯著肌膚如雪破花。 梳的紋絲不亂的頭發(fā)上谦趣,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天,我揣著相機(jī)與錄音座每,去河邊找鬼前鹅。 笑死,一個胖子當(dāng)著我的面吹牛峭梳,可吹牛的內(nèi)容都是我干的舰绘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼葱椭,長吁一口氣:“原來是場噩夢啊……” “哼捂寿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起孵运,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤者蠕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后掐松,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體踱侣,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年大磺,在試婚紗的時候發(fā)現(xiàn)自己被綠了抡句。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡杠愧,死狀恐怖待榔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情流济,我是刑警寧澤锐锣,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站绳瘟,受9級特大地震影響雕憔,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜糖声,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一斤彼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蘸泻,春花似錦琉苇、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抡诞,卻和暖如春穷蛹,著一層夾襖步出監(jiān)牢的瞬間土陪,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工俩莽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留旺坠,地道東北人。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓扮超,卻偏偏與公主長得像取刃,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子出刷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評論 2 354

推薦閱讀更多精彩內(nèi)容