?

基于WebGL的BIM輕量化關鍵技術研究

2023-11-02 12:33黃丙湖徐幫樹張家寶何亞文
計算機應用與軟件 2023年10期
關鍵詞:字節輕量化坐標系

黃丙湖 王 濤 徐幫樹 張家寶 何亞文

1(中國石油大學(華東)海洋與空間信息學院 山東 青島 266580)

2(山東大學齊魯交通學院 山東 濟南 250061)

3(山東科技大學土木工程與建筑學院 山東 青島 266590)

0 引 言

BIM(Building Information Modeling)技術在AECO/FM(Architecture,Engineering,Construction,Operations and Facility Management)行業的廣泛運用[1]和Web 3D技術日漸成熟,掀起了一股WebBIM研究與應用熱潮。由于BIM中包含建筑全生命周期的幾何信息和語義信息,通過BIM服務器,可將信息實時更新和最大范圍共享,提高各個運營商之間的溝通效率,減少運營成本。

在WebBIM的研究中,魏國富等[2]基于OBJ與SVG的ID映射,實現模型與平面圖紙的二三維聯動。Wei[3]通過將Autodesk Forge View、Dynamo與Flux的集成,開發了一款BIM參數化設計系統,允許多人協同設計。Scully等[4]利用3D Repo云服務設計了基于X3DOM的3D BIM版本控制系統。劉小軍等[5]提出了一套面向手機網頁瀏覽大規模三維場景的漫游算法。Chen等[6]提出基于Bigtable和MapReduce的分布式系統框架用于存儲、瀏覽和計算大規模BIM數據。

然而BIM有眾多的數據源,各數據依賴于軟件系統環境而無法直接被WebGL讀取和渲染,IFC(Industry Foundation Classes)標準的發布,有助于BIM數據在不同軟件平臺之間實現共享和交換。在這里,BIM模型可以劃分為IFC標準模型和專業軟件模型[7],對于這兩類模型的數據轉換,有眾多的學者做了相關研究。Xu等[8-9]利用IFCOpenShell工具實現對IFC數據的提取與格式轉換。針對專業軟件模型,除了眾多軟件生產商提供的解決方案如Autodesk Forge View、FME、BimAngle Engine和SimLab等,也同樣引起了相關從業者和學者的關注。Jeremy Tammik開源了RvtVa3c項目,對Revit數據的自定義導出具有很好的指導意義。陳志楊等[10]借助Revit API完成BIM屬性信息和幾何信息的提取。

現今,隨著數據量激增,對本已經包含大量信息的BIM數據而言,有限的存儲資源和計算能力成為技術發展的瓶頸,BIM輕量化成為關鍵技術[11-12]。Zhou等[13]基于IFC數據,利用Delaunay三角剖分算法對B-rep(Boundary Representation)模型進行重構并通過實例復用實現BIM輕量化存儲。Zhou等[14]提出S-LPM框架,通過對Mesh分割和重復體素去除操作,實現模型輕量化,Liu等[15]將其運用至智慧城市可視化管理中。

綜上所述,由于IFC作為一種開放的數據標準,有較多的學者對其進行深入的研究。但由于IFC涉及廣泛的應用領域和模型參數化設計給幾何數據重構與數據輕量化帶來一定的困難。作為商業模型數據,往往有軟件廠商提供相應的解決方案和軟件接口服務。轉換的數據會用于特定的平臺,轉換的細節對于用戶來說是“黑箱操作”。借助IFC、IndoorGML、FBX、OBJ等一些中間數據進行交換會產生一定的數據冗余和數據損失,隨著轉換鏈的增長,這些風險發生的概率會增加。本文從應用的角度出發,借鑒RvtVa3c開源項目,通過Revit API,設計RVT轉GLB數據的程序接口,實現BIM數據的輕量化存儲,在一定意義上減少信息在轉換過程中發生丟失的現象。

1 Revit幾何信息描述

Revit是一個記錄與設計的平臺,一份Revit數據中不僅包含模型的幾何信息,同時包含設計所需的明細表、設計圖紙與二維和三維的視圖信息等。在數據提取與轉換過程中,首先需要了解Revit坐標系和幾何數據結構。

1.1 Revit坐標系

Revit使用三種坐標原點,分別為測量點、項目基點和圖形原點。以測量點為原點的坐標系為測量坐標系,用于描述項目基點在真實世界中的位置;以項目基點為原點的坐標系為局部坐標系,用于描述建筑間的相對位置關系;而以圖形原點為坐標原點的坐標系為模型坐標系,用于描述三維視圖中各個構件的幾何位置,原點為(0,0,0)。在三維視圖中,族實例可用Transform表示為:

(1)

式中:O為距離圖形原點的位移;(a1,a2,a3)T、(b1,b2,b3)T、(c1,c2,c3)T為族實例本地坐標系的坐標軸在模型坐標系中的向量表示。

其次,Revit在三維視圖中使用左手坐標系,以屏幕向右為X軸正方向,豎直向上為Z軸正方向,垂直屏幕向里為Y軸正方向;而WebGL多使用右手坐標系,即水平向右為X軸正方向,豎直向上為Y軸正方向,垂直屏幕向外為Z軸正方向,圖1表示Revit坐標系轉向WebGL右手坐標系的過程,其中當模型需要整體偏移或姿態調整時,可在GLTF的根節點Node中指定偏轉矩陣。

圖1 坐標轉換

1.2 Revit模型信息組織

Revit建模是基于對象的,族(或稱為圖元)是一類相同構件的抽象,如單扇窗、雙扇窗、百葉窗等,族的參數定義了構件的行為。族類別是對族集合的分類,如窗、柱、墻等,而族類型是對族的細分,它定義了某一族的不同尺寸與材料等。在三維視圖中所看到的每個構件,都是某一族類型的實例,對于尺寸大小固定的族類型可以通過Transform矩陣來構建不同位置的構件。

在BIM輕量化中需要獲得每個構件的圖形信息,如圖2所示,每個構件可以由任意一個圖形元素構成。在數據轉化過程中,需要獲取組成這些圖形元素的點坐標、索引和法向量等幾何信息以及變換矩陣信息。

圖2 Revit圖形元素

2 GLTF信息描述

一個好的數據結構影響著傳輸、渲染和功能實現。GLTF(GL Transmission Format)作為面向圖形實時快速渲染,可擴展的數據傳輸格式。它因直接傳輸給圖形API,不需要二次轉換,格式開源而得到業界的廣泛認可。因此本文選用GLB作為BIM模型信息的存儲格式。

2.1 GLTF數據結構

通常,一個GLTF文件包含以JSON格式存儲的場景信息文件和一個存儲幾何信息的二進制文件,gltf文件中buffers數組的每個元素通過URI引用bin文件。如圖3所示,gltf文件中包含場景、相機、節點樹、材料信息、緩沖區信息等,各個鍵值元素之間通過索引進而描述整個場景需要繪制的信息,bin文件主要包含頂點坐標、頂點索引、法向量、關鍵幀、綁定姿勢的逆矩陣等。而紋理信息可以在gltf中的images元素通過URI引用外部的圖片文件,也可以同幾何信息一樣寫入bin文件中或者以base64編碼寫入gltf的buffers中。

在gltf場景文件中,scene指定scenes數組中需要渲染的node節點,nodes數組中的每個node元素既可以指向一個mesh元素,也可以有子節點。多個node可以指定同一個mesh元素,實現幾何數據的復用,減少數據冗余。圖4顯示從gltf和bin文件中獲取信息繪制線段的過程。圖中indices和POSITION分別指向頂點索引和頂點坐標的accessor存取器元素,accessor描述從bufferView中獲取數據方式和數據類型。同樣,兩個accessors中的bufferView各自指向bufferViews中對應頂點索引和頂點坐標的bufferView元素,bufferView描述其在整個二進制緩沖區的位置,字節長度以及數據存儲的間隔等信息。meshes中mode指示獲取數據后的繪制方式,如點、線、三角扇等。其中componentType、type、mode和target屬性值均是常量枚舉值。

圖4 GLTF數據解析

每個node還可以指定該節點的4×4矩陣用于調整姿態,在渲染時,所有的子節點都必須經過父節點矩陣左乘。一般的,node中的矩陣還可以分解為T×R×S,T與S分別表示偏移和縮放,均為32位浮點值類型、長度為3的數組,而R表示四元數旋轉,為32位浮點值類型、長度為4的數組。

相比于歐拉變換容易產生萬向節死鎖問題以及矩陣變換至少需要存儲9個參數參與計算,四元數變換只需存儲4個參數就可以完成復雜的旋轉。令旋轉單位四元數q=[w,x,y,z],向量p=[0,vx,vy,vz],則經過q變換后的向量為:

p′=qpq-1

(2)

p′=[wxyz]×[0vxvyvz]×

[w-x-y-z]

(3)

(4)

因此,四元數(右手性)轉換成3×3矩陣為:

(5)

根據式(5),可以求得旋轉矩陣對應的四元數。

2.2 GLB數據結構

如前所述,通常GLTF文件主要包含gltf和bin文件,就意味著至少要向服務器發送兩次Http請求,而將bin數據以base64編碼寫入gltf文件中則在渲染時需要額外的解碼時間。在考慮后期工作需要頻繁調度數據,本文最終采用GLB數據格式。

如圖5所示,GLB文件是將gltf和bin文件整合在一起以小端字節序存儲的二進制文件。它開始包含12字節頭,分別為magic、version和length,用于描述文件的GLTF ASCII碼、版本信息和整個文件所占的字節長度。Chunk 0與Chunk 1分別為JSON存儲區和bin存儲區,length和type均占四個字節,用于描述JSON和bin的字節長度與識別JSON和BIN字符的ASCII碼。Chunk 0和Chunk 1各存儲的字節長度缺省為4的倍數,否則在Chunk 0和Chunk 1后分別用0x20和0x00占位以滿足規則。

圖5 GLB數據結構

2.3 通用GLTF數據轉GLB數據

如下所示,為通用的GLTF數據結構,將buffer中的uri屬性設置為null,借助Newtonsoft將GLFT對象序列化并壓縮成不含空格、換行符的JSON字符串,并將該字符串轉換為UTF-8編碼的字節數組。根據2.2節GLB的數據結構,用對應的數據類型依次寫入0x46546C67、2(GLTF版本為2)、總字節長度值、JSON字節長度值、0x4E4F534A、JSON字節數組、BIN字節長度值、0x003E4942,以及每個BinaryData的幾何數據。其中在JSON區與BIN區用0x20和0x00所占位數計入總字節長度和各區的字節長度。

public struct GLTF

{

public Asset asset {get;set;}

public List scenes {get;set;}

public List nodes {get;set;}

public List meshes {get;set;}

public List buffers {get;set;}

public List bufferViews {get;set;}

public List accessors {get;set;}

public List materials {get;set;}

public List textures {get;set;}

public List images {get;set;}

public List samplers {get;set;}

}

public struct BinaryData

{

public List vertexes=new List();

public List normals=new List();

public List uvs=new List();

public List indexes=new List();

}

3 RVT數據轉換

3.1 數據轉換

在BIM輕量化的工作中,用于數據轉換所設計的功能主要封裝在以下幾個類中:

GLTF:包含GLTF的數據結構以及常量枚舉。

Map:GLTF中Node、Material、Mesh等數據的容器,用于索引的維護和數據的提取與復用。

GltfMath:用于坐標轉換、四元數、包圍盒、最值、向量和矩陣等計算。

GltfCheck:對GLTF數據的檢查,剔除不合格數據,維護索引。

GltfExportContext:繼承Revit IExportContext接口,實現數據的讀取與寫入操作。

其中,Revit提供IExportContext接口以支持BIM數據的提取,基本流程如圖6所示。通過遍歷每個構件,實現坐標、法向量、材質等信息的提取。

圖6 IExportContext遍歷數據流程

根據接口函數遍歷的流程,本文在每個函數中設計了不同的功能:

OnViewBegin:獲取并計算模型相對測量點的旋轉四元數R和偏移矩陣T并賦給RootNode。

OnElementBegin:創建Node節點,計算構件在三維視圖中的包圍盒,提取屬性信息。

OnInstanceBegin:對含有非Instance的幾何信息,創建子節點、Mesh、Accessor、BufferView、Buffer對象,并維護之間的索引關系;實例化Instance子節點,添加父節點對Instance子節點的索引;計算偏轉矩陣并將矩陣入棧。

OnMaterial:在幾何表面的呈現上,GLTF是基于物理的渲染,即通過金屬度和粗糙度來計算表面的反射效果。該函數負責將Revit的材質信息轉換為GLTF的材質信息,并提取材料屬性;對已存在相同的Material,記錄該Material的索引,將賦給要創建的Mesh.Primitive中的Material屬性。

OnPolymesh:坐標轉換,借助RvtVa3c中的VertexLookupInt類實現頂點去冗。對于存儲單個Mesh數據,需要一定的頂點冗余,如圖7所示,Face1、Face2、Face3共用v1頂點,但v1點可能對應多個法向量或紋理坐標,因此頂點去冗范圍被限制于繪制單個面的幾何數據。提取坐標、法向量,并生成在當前Mesh的頂點索引。

圖7 面幾何數據去冗

OnInstanceEnd:每個Instance對應一個Mesh,并賦予一個由InstanceNode.NodeName與InstanceNode.getSymbolId().IntegerValue組成的ID。如圖8所示,①和②是具有相同ID、不同位置的構件,對已存在相同ID的Mesh,添加Node對Mesh的索引;否則創建Mesh、Accessor、BufferView和Buffer對象,維護之間索引。計算該Instance的四元數R和偏移矩陣T,并賦給Node節點,矩陣出棧。

圖8 族實例幾何數據的復用

另外,族的結構影響數據讀取的行為,對于同一個族實例,也可以實現內部幾何元素的復用,如圖9所示,欄桿構件中包含①實例,①實例嵌套著②和③子實例。

圖9 復合族實例

OnElementEnd:對含有非Instance的幾何信息,創建子節點、Mesh、Accessor、BufferView和Buffer對象,維護索引。

OnLinkBegin:Revit建模過程中,通常會將項目文件拆分成多個子文件,目的在于方便管理和減少系統運行負擔。通過OnLinkBegin函數,將鏈接文件的坐標系轉到當前項目文件的模型坐標系中,切換當前document對象,矩陣入棧,將遍歷鏈接文件中的構件。

OnLinkEnd:矩陣出棧。

Finish:文件寫入前進行數據清洗,并檢查GLTF中各個屬性內部的枚舉值、字節統計值、數據類型、字節偏移以及屬性內部和屬性之間索引的正確性。文件寫入時動態分配內存,例如索引一般不會超過兩個字節。

3.2 數據清洗

在數據導出過程中,容易產生空節點,造成數據不夠整潔、數據量增大的情況,甚至會在讀取時發生解析錯誤。增加條件判斷以應對發生空節點的情況往往會因為條件判斷不當而導致數據損失,索引錯位而難以維護,并且也很難預防各種出現空節點的情況。因此本文不再關注對發生不合格節點情況的判斷,而是最后將每個構件所對應的節點從數據集中單獨提取出來進行維護。圖10所示為從數據集中提取并維護索引的雙扇窗節點及其子節點,其中Node1、Node6為空節點,需要被識別和清除。任何一個空節點的清除將會影響其他節點位置的變化、潛在空節點的產生以及節點在父節點中索引的變化。

圖10 節點清洗

對每個節點進行檢查,算法流程如下所示。

1) 初始化,獲得Nodes數組中的根節點RootNode,根據RootNode中的children數組遞歸循環整個Nodes數組,在遞歸循環中實例化Segment,每個Segment中包含當前Node、Node在數組中的索引Index、Node的父節點索引ParentIndex以及在父節點的children數組中的索引DeleteIndex,返回包含Segment的數組Segments。

2) 遍歷Segments,對每個Segment.Node進行檢查,偽代碼如下:

輸入:Seg

輸出:none

BEGIN

1: Node←Seg.Node;

2: If(Node.Children is not null and

Node.Children.Count is 0) Then

3: Node.Children←null;

4: If(Node.Children is null and Node.Mesh is null)

Then//節點不合格

5: Index←Seg.Index;

//該節點的刪除會導致后面節點位置的變化

6: For I←Index+1 to Segments.Count

7: Do TemSeg←Segments[I];

8: TemSeg.Index←TemSeg.Index-1;

9: ParentIndex←TemSeg.ParentIndex;

//對不是根節點的父節點children數組進行維護

10: If ParentIndex is not -1 Then

11: ParentNode←Segments[ParentIndex].Node;

12: DeleteIndex←TemSeg.DeleteIndex;

13: ParentNode.Children[DeleteIndex]=TemSeg.Index;

//對父節點在待刪節點之后,對父節點索引減1

14: If ParentIndex>Index Then

15: ParentIndex←ParentIndex-1;

16: Delete Segments[Index];//節點刪除

17: PIndex←Seg.ParentIndex;

18: DIndex←Seg.DeleteIndex;

//不合格節點刪除對其父節產生影響

19: If PIndex is not -1 Then

20: PNode←Segments[PIndex].Node;

21: For J←DIndex+1 to PNode.Children.Count

22: Do

Segments[PNode.Children[J]].DeleteIndex=J-1;

23: Delete PNode.Children[DIndex];

//遞歸,對父節點進行檢查

24: Seg←Segments[PIndex] Goto(1);

END

3) 遍歷Segments,提取Node,返回Nodes數組。

4 實驗與展示

本文采用C#語言和Visual Studio 2012工具對Autodesk Revit 2018進行二次開發。將教學樓、住宅小區和某施工場地BIM模型作為實驗數據,使用插件分別將其導出為未執行輕量化操作的GLB數據、執行輕量化操作的GLB數據和屬性信息文件,并用Draco對輕量化后的GLB數據進行壓縮,處理結果如圖11所示。

圖11 Revit文件、未輕量化、輕量化與壓縮文件大小對比

在調試過程中分別統計了各GLB數據中Mesh的數量,如表1所示。Mesh數量在一定程度上體現數據輕量化的效果,每多一個Mesh,在GLB中的bin區至少多包含一份幾何數據,與之對應,在JSON區多包含一份獲取該幾何數據的描述信息。另外,輕量化的結果因模型而異,對于富含相同構件的BIM模型,輕量化的結果較好。其中恒大場布模型包含214個Mesh,原因在于該模型大部分所用的是自定義的族,細分的粒度不如Revit內建的族,例如,在塔吊的模型解析過程中,幾何數據作為一個整體被提取。

表1 GLB中Mesh數量統計

同時,將住宅小區模型與恒大場布模型的輕量化并經過Draco壓縮處理的結果上傳至阿里云服務器,輕量化未經過壓縮處理的結果上傳至Cesium Ion平臺進行測試,如圖12所示,左側為Three.js渲染結果,右側為Cesium的渲染結果。其中,渲染被Draco壓縮的GLB模型之前需要解碼,解碼時間內會阻塞前端頁面響應,HTML5引入了WebWorker工作線程可以很好地解決此問題,并且Three.js內置了子線程解碼模型并將解碼后的數據發送給主線程進行渲染的功能。

圖12 模型在Three.js與Cesium引擎中的渲染效果

在對屬性信息提取的工作中,基于RvtVa3c對構件工程信息提取工作的基礎上,進一步提取材料屬性、物理屬性,并將屬性信息以JSON格式寫入info文件中,屬性ID與GLB中node.name一一對應,教學樓模型的屬性信息如圖13所示。

對數據損失進行評估時,發現住宅小區模型構件總數為7 489個,而渲染結果顯示7 480個,損失9個構件,如圖14所示,在轉換過程中會有較小的數據損失。

圖14 住宅小區模型數據轉換損失評估

5 結 語

BIM模型作為建筑參數化的載體,具有空間不均勻、高度復雜、語義豐富和數據量大等特性。將BIM與互聯網技術相結合,需要從數據結構與算法、數據傳輸以及計算機圖形學等方向做相應的研究。但是BIM有眾多的數據源,增加了數據使用成本,給數據融合造成了一定的難度。而IFC作為BIM的數據標準,借助其進行數據交換,很大程度上受限于各個軟件平臺對標準的實現程度以及模型輕量化帶來的難度。本文借助Revit API實現BIM輕量化,仍有很大的不足:(1) 該轉換方法僅僅適用于Revit平臺,不具有普適性。(2) 數據在轉換過程中仍有少量幾何數據損失,需要進一步完善。(3) 需對數據的加載以及渲染策略進行優化。因此這些不足也是以后需要研究方向。

猜你喜歡
字節輕量化坐標系
汽車輕量化集成制造專題主編
No.8 字節跳動將推出獨立出口電商APP
No.10 “字節跳動手機”要來了?
一種輕量化自卸半掛車結構設計
一種輕量化自卸半掛車結構設計
解密坐標系中的平移變換
坐標系背后的故事
簡談MC7字節碼
基于重心坐標系的平面幾何證明的探討
瞄準掛車輕量化 鑼響掛車正式掛牌成立
91香蕉高清国产线观看免费-97夜夜澡人人爽人人喊a-99久久久无码国产精品9-国产亚洲日韩欧美综合