黃丙湖 王 濤 徐幫樹 張家寶 何亞文
1(中國石油大學(華東)海洋與空間信息學院 山東 青島 266580)
2(山東大學齊魯交通學院 山東 濟南 250061)
3(山東科技大學土木工程與建筑學院 山東 青島 266590)
BIM(Building Information Modeling)技術在AECO/FM(Architecture,Engineering,Construction,Operations and Facility Management)行業(yè)的廣泛運用[1]和Web 3D技術日漸成熟,掀起了一股WebBIM研究與應用熱潮。由于BIM中包含建筑全生命周期的幾何信息和語義信息,通過BIM服務器,可將信息實時更新和最大范圍共享,提高各個運營商之間的溝通效率,減少運營成本。
在WebBIM的研究中,魏國富等[2]基于OBJ與SVG的ID映射,實現(xiàn)模型與平面圖紙的二三維聯(lián)動。Wei[3]通過將Autodesk Forge View、Dynamo與Flux的集成,開發(fā)了一款BIM參數(shù)化設計系統(tǒng),允許多人協(xié)同設計。Scully等[4]利用3D Repo云服務設計了基于X3DOM的3D BIM版本控制系統(tǒng)。劉小軍等[5]提出了一套面向手機網(wǎng)頁瀏覽大規(guī)模三維場景的漫游算法。Chen等[6]提出基于Bigtable和MapReduce的分布式系統(tǒng)框架用于存儲、瀏覽和計算大規(guī)模BIM數(shù)據(jù)。
然而BIM有眾多的數(shù)據(jù)源,各數(shù)據(jù)依賴于軟件系統(tǒng)環(huán)境而無法直接被WebGL讀取和渲染,IFC(Industry Foundation Classes)標準的發(fā)布,有助于BIM數(shù)據(jù)在不同軟件平臺之間實現(xiàn)共享和交換。在這里,BIM模型可以劃分為IFC標準模型和專業(yè)軟件模型[7],對于這兩類模型的數(shù)據(jù)轉換,有眾多的學者做了相關研究。Xu等[8-9]利用IFCOpenShell工具實現(xiàn)對IFC數(shù)據(jù)的提取與格式轉換。針對專業(yè)軟件模型,除了眾多軟件生產(chǎn)商提供的解決方案如Autodesk Forge View、FME、BimAngle Engine和SimLab等,也同樣引起了相關從業(yè)者和學者的關注。Jeremy Tammik開源了RvtVa3c項目,對Revit數(shù)據(jù)的自定義導出具有很好的指導意義。陳志楊等[10]借助Revit API完成BIM屬性信息和幾何信息的提取。
現(xiàn)今,隨著數(shù)據(jù)量激增,對本已經(jīng)包含大量信息的BIM數(shù)據(jù)而言,有限的存儲資源和計算能力成為技術發(fā)展的瓶頸,BIM輕量化成為關鍵技術[11-12]。Zhou等[13]基于IFC數(shù)據(jù),利用Delaunay三角剖分算法對B-rep(Boundary Representation)模型進行重構并通過實例復用實現(xiàn)BIM輕量化存儲。Zhou等[14]提出S-LPM框架,通過對Mesh分割和重復體素去除操作,實現(xiàn)模型輕量化,Liu等[15]將其運用至智慧城市可視化管理中。
綜上所述,由于IFC作為一種開放的數(shù)據(jù)標準,有較多的學者對其進行深入的研究。但由于IFC涉及廣泛的應用領域和模型參數(shù)化設計給幾何數(shù)據(jù)重構與數(shù)據(jù)輕量化帶來一定的困難。作為商業(yè)模型數(shù)據(jù),往往有軟件廠商提供相應的解決方案和軟件接口服務。轉換的數(shù)據(jù)會用于特定的平臺,轉換的細節(jié)對于用戶來說是“黑箱操作”。借助IFC、IndoorGML、FBX、OBJ等一些中間數(shù)據(jù)進行交換會產(chǎn)生一定的數(shù)據(jù)冗余和數(shù)據(jù)損失,隨著轉換鏈的增長,這些風險發(fā)生的概率會增加。本文從應用的角度出發(fā),借鑒RvtVa3c開源項目,通過Revit API,設計RVT轉GLB數(shù)據(jù)的程序接口,實現(xiàn)BIM數(shù)據(jù)的輕量化存儲,在一定意義上減少信息在轉換過程中發(fā)生丟失的現(xiàn)象。
Revit是一個記錄與設計的平臺,一份Revit數(shù)據(jù)中不僅包含模型的幾何信息,同時包含設計所需的明細表、設計圖紙與二維和三維的視圖信息等。在數(shù)據(jù)提取與轉換過程中,首先需要了解Revit坐標系和幾何數(shù)據(jù)結構。
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右手坐標系的過程,其中當模型需要整體偏移或姿態(tài)調整時,可在GLTF的根節(jié)點Node中指定偏轉矩陣。
圖1 坐標轉換
Revit建模是基于對象的,族(或稱為圖元)是一類相同構件的抽象,如單扇窗、雙扇窗、百葉窗等,族的參數(shù)定義了構件的行為。族類別是對族集合的分類,如窗、柱、墻等,而族類型是對族的細分,它定義了某一族的不同尺寸與材料等。在三維視圖中所看到的每個構件,都是某一族類型的實例,對于尺寸大小固定的族類型可以通過Transform矩陣來構建不同位置的構件。
在BIM輕量化中需要獲得每個構件的圖形信息,如圖2所示,每個構件可以由任意一個圖形元素構成。在數(shù)據(jù)轉化過程中,需要獲取組成這些圖形元素的點坐標、索引和法向量等幾何信息以及變換矩陣信息。
圖2 Revit圖形元素
一個好的數(shù)據(jù)結構影響著傳輸、渲染和功能實現(xiàn)。GLTF(GL Transmission Format)作為面向圖形實時快速渲染,可擴展的數(shù)據(jù)傳輸格式。它因直接傳輸給圖形API,不需要二次轉換,格式開源而得到業(yè)界的廣泛認可。因此本文選用GLB作為BIM模型信息的存儲格式。
通常,一個GLTF文件包含以JSON格式存儲的場景信息文件和一個存儲幾何信息的二進制文件,gltf文件中buffers數(shù)組的每個元素通過URI引用bin文件。如圖3所示,gltf文件中包含場景、相機、節(jié)點樹、材料信息、緩沖區(qū)信息等,各個鍵值元素之間通過索引進而描述整個場景需要繪制的信息,bin文件主要包含頂點坐標、頂點索引、法向量、關鍵幀、綁定姿勢的逆矩陣等。而紋理信息可以在gltf中的images元素通過URI引用外部的圖片文件,也可以同幾何信息一樣寫入bin文件中或者以base64編碼寫入gltf的buffers中。
在gltf場景文件中,scene指定scenes數(shù)組中需要渲染的node節(jié)點,nodes數(shù)組中的每個node元素既可以指向一個mesh元素,也可以有子節(jié)點。多個node可以指定同一個mesh元素,實現(xiàn)幾何數(shù)據(jù)的復用,減少數(shù)據(jù)冗余。圖4顯示從gltf和bin文件中獲取信息繪制線段的過程。圖中indices和POSITION分別指向頂點索引和頂點坐標的accessor存取器元素,accessor描述從bufferView中獲取數(shù)據(jù)方式和數(shù)據(jù)類型。同樣,兩個accessors中的bufferView各自指向bufferViews中對應頂點索引和頂點坐標的bufferView元素,bufferView描述其在整個二進制緩沖區(qū)的位置,字節(jié)長度以及數(shù)據(jù)存儲的間隔等信息。meshes中mode指示獲取數(shù)據(jù)后的繪制方式,如點、線、三角扇等。其中componentType、type、mode和target屬性值均是常量枚舉值。
圖4 GLTF數(shù)據(jù)解析
每個node還可以指定該節(jié)點的4×4矩陣用于調整姿態(tài),在渲染時,所有的子節(jié)點都必須經(jīng)過父節(jié)點矩陣左乘。一般的,node中的矩陣還可以分解為T×R×S,T與S分別表示偏移和縮放,均為32位浮點值類型、長度為3的數(shù)組,而R表示四元數(shù)旋轉,為32位浮點值類型、長度為4的數(shù)組。
相比于歐拉變換容易產(chǎn)生萬向節(jié)死鎖問題以及矩陣變換至少需要存儲9個參數(shù)參與計算,四元數(shù)變換只需存儲4個參數(shù)就可以完成復雜的旋轉。令旋轉單位四元數(shù)q=[w,x,y,z],向量p=[0,vx,vy,vz],則經(jīng)過q變換后的向量為:
p′=qpq-1
(2)
p′=[wxyz]×[0vxvyvz]×
[w-x-y-z]
(3)
(4)
因此,四元數(shù)(右手性)轉換成3×3矩陣為:
(5)
根據(jù)式(5),可以求得旋轉矩陣對應的四元數(shù)。
如前所述,通常GLTF文件主要包含gltf和bin文件,就意味著至少要向服務器發(fā)送兩次Http請求,而將bin數(shù)據(jù)以base64編碼寫入gltf文件中則在渲染時需要額外的解碼時間。在考慮后期工作需要頻繁調度數(shù)據(jù),本文最終采用GLB數(shù)據(jù)格式。
如圖5所示,GLB文件是將gltf和bin文件整合在一起以小端字節(jié)序存儲的二進制文件。它開始包含12字節(jié)頭,分別為magic、version和length,用于描述文件的GLTF ASCII碼、版本信息和整個文件所占的字節(jié)長度。Chunk 0與Chunk 1分別為JSON存儲區(qū)和bin存儲區(qū),length和type均占四個字節(jié),用于描述JSON和bin的字節(jié)長度與識別JSON和BIN字符的ASCII碼。Chunk 0和Chunk 1各存儲的字節(jié)長度缺省為4的倍數(shù),否則在Chunk 0和Chunk 1后分別用0x20和0x00占位以滿足規(guī)則。
圖5 GLB數(shù)據(jù)結構
如下所示,為通用的GLTF數(shù)據(jù)結構,將buffer中的uri屬性設置為null,借助Newtonsoft將GLFT對象序列化并壓縮成不含空格、換行符的JSON字符串,并將該字符串轉換為UTF-8編碼的字節(jié)數(shù)組。根據(jù)2.2節(jié)GLB的數(shù)據(jù)結構,用對應的數(shù)據(jù)類型依次寫入0x46546C67、2(GLTF版本為2)、總字節(jié)長度值、JSON字節(jié)長度值、0x4E4F534A、JSON字節(jié)數(shù)組、BIN字節(jié)長度值、0x003E4942,以及每個BinaryData的幾何數(shù)據(jù)。其中在JSON區(qū)與BIN區(qū)用0x20和0x00所占位數(shù)計入總字節(jié)長度和各區(qū)的字節(jié)長度。
public struct GLTF
{
public Asset asset {get;set;}
public List
public List
public List
public List
public List
public List
public List
public List
public List
public List
}
public struct BinaryData
{
public List
public List
public List
public List
}
在BIM輕量化的工作中,用于數(shù)據(jù)轉換所設計的功能主要封裝在以下幾個類中:
GLTF:包含GLTF的數(shù)據(jù)結構以及常量枚舉。
Map
GltfMath:用于坐標轉換、四元數(shù)、包圍盒、最值、向量和矩陣等計算。
GltfCheck:對GLTF數(shù)據(jù)的檢查,剔除不合格數(shù)據(jù),維護索引。
GltfExportContext:繼承Revit IExportContext接口,實現(xiàn)數(shù)據(jù)的讀取與寫入操作。
其中,Revit提供IExportContext接口以支持BIM數(shù)據(jù)的提取,基本流程如圖6所示。通過遍歷每個構件,實現(xiàn)坐標、法向量、材質等信息的提取。
圖6 IExportContext遍歷數(shù)據(jù)流程
根據(jù)接口函數(shù)遍歷的流程,本文在每個函數(shù)中設計了不同的功能:
OnViewBegin:獲取并計算模型相對測量點的旋轉四元數(shù)R和偏移矩陣T并賦給RootNode。
OnElementBegin:創(chuàng)建Node節(jié)點,計算構件在三維視圖中的包圍盒,提取屬性信息。
OnInstanceBegin:對含有非Instance的幾何信息,創(chuàng)建子節(jié)點、Mesh、Accessor、BufferView、Buffer對象,并維護之間的索引關系;實例化Instance子節(jié)點,添加父節(jié)點對Instance子節(jié)點的索引;計算偏轉矩陣并將矩陣入棧。
OnMaterial:在幾何表面的呈現(xiàn)上,GLTF是基于物理的渲染,即通過金屬度和粗糙度來計算表面的反射效果。該函數(shù)負責將Revit的材質信息轉換為GLTF的材質信息,并提取材料屬性;對已存在相同的Material,記錄該Material的索引,將賦給要創(chuàng)建的Mesh.Primitive中的Material屬性。
OnPolymesh:坐標轉換,借助RvtVa3c中的VertexLookupInt類實現(xiàn)頂點去冗。對于存儲單個Mesh數(shù)據(jù),需要一定的頂點冗余,如圖7所示,Face1、Face2、Face3共用v1頂點,但v1點可能對應多個法向量或紋理坐標,因此頂點去冗范圍被限制于繪制單個面的幾何數(shù)據(jù)。提取坐標、法向量,并生成在當前Mesh的頂點索引。
圖7 面幾何數(shù)據(jù)去冗
OnInstanceEnd:每個Instance對應一個Mesh,并賦予一個由InstanceNode.NodeName與InstanceNode.getSymbolId().IntegerValue組成的ID。如圖8所示,①和②是具有相同ID、不同位置的構件,對已存在相同ID的Mesh,添加Node對Mesh的索引;否則創(chuàng)建Mesh、Accessor、BufferView和Buffer對象,維護之間索引。計算該Instance的四元數(shù)R和偏移矩陣T,并賦給Node節(jié)點,矩陣出棧。
圖8 族實例幾何數(shù)據(jù)的復用
另外,族的結構影響數(shù)據(jù)讀取的行為,對于同一個族實例,也可以實現(xiàn)內(nèi)部幾何元素的復用,如圖9所示,欄桿構件中包含①實例,①實例嵌套著②和③子實例。
圖9 復合族實例
OnElementEnd:對含有非Instance的幾何信息,創(chuàng)建子節(jié)點、Mesh、Accessor、BufferView和Buffer對象,維護索引。
OnLinkBegin:Revit建模過程中,通常會將項目文件拆分成多個子文件,目的在于方便管理和減少系統(tǒng)運行負擔。通過OnLinkBegin函數(shù),將鏈接文件的坐標系轉到當前項目文件的模型坐標系中,切換當前document對象,矩陣入棧,將遍歷鏈接文件中的構件。
OnLinkEnd:矩陣出棧。
Finish:文件寫入前進行數(shù)據(jù)清洗,并檢查GLTF中各個屬性內(nèi)部的枚舉值、字節(jié)統(tǒng)計值、數(shù)據(jù)類型、字節(jié)偏移以及屬性內(nèi)部和屬性之間索引的正確性。文件寫入時動態(tài)分配內(nèi)存,例如索引一般不會超過兩個字節(jié)。
在數(shù)據(jù)導出過程中,容易產(chǎn)生空節(jié)點,造成數(shù)據(jù)不夠整潔、數(shù)據(jù)量增大的情況,甚至會在讀取時發(fā)生解析錯誤。增加條件判斷以應對發(fā)生空節(jié)點的情況往往會因為條件判斷不當而導致數(shù)據(jù)損失,索引錯位而難以維護,并且也很難預防各種出現(xiàn)空節(jié)點的情況。因此本文不再關注對發(fā)生不合格節(jié)點情況的判斷,而是最后將每個構件所對應的節(jié)點從數(shù)據(jù)集中單獨提取出來進行維護。圖10所示為從數(shù)據(jù)集中提取并維護索引的雙扇窗節(jié)點及其子節(jié)點,其中Node1、Node6為空節(jié)點,需要被識別和清除。任何一個空節(jié)點的清除將會影響其他節(jié)點位置的變化、潛在空節(jié)點的產(chǎn)生以及節(jié)點在父節(jié)點中索引的變化。
圖10 節(jié)點清洗
對每個節(jié)點進行檢查,算法流程如下所示。
1) 初始化,獲得Nodes數(shù)組中的根節(jié)點RootNode,根據(jù)RootNode中的children數(shù)組遞歸循環(huán)整個Nodes數(shù)組,在遞歸循環(huán)中實例化Segment,每個Segment中包含當前Node、Node在數(shù)組中的索引Index、Node的父節(jié)點索引ParentIndex以及在父節(jié)點的children數(shù)組中的索引DeleteIndex,返回包含Segment的數(shù)組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//節(jié)點不合格
5: Index←Seg.Index;
//該節(jié)點的刪除會導致后面節(jié)點位置的變化
6: For I←Index+1 to Segments.Count
7: Do TemSeg←Segments[I];
8: TemSeg.Index←TemSeg.Index-1;
9: ParentIndex←TemSeg.ParentIndex;
//對不是根節(jié)點的父節(jié)點children數(shù)組進行維護
10: If ParentIndex is not -1 Then
11: ParentNode←Segments[ParentIndex].Node;
12: DeleteIndex←TemSeg.DeleteIndex;
13: ParentNode.Children[DeleteIndex]=TemSeg.Index;
//對父節(jié)點在待刪節(jié)點之后,對父節(jié)點索引減1
14: If ParentIndex>Index Then
15: ParentIndex←ParentIndex-1;
16: Delete Segments[Index];//節(jié)點刪除
17: PIndex←Seg.ParentIndex;
18: DIndex←Seg.DeleteIndex;
//不合格節(jié)點刪除對其父節(jié)產(chǎn)生影響
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];
//遞歸,對父節(jié)點進行檢查
24: Seg←Segments[PIndex] Goto(1);
END
3) 遍歷Segments,提取Node,返回Nodes數(shù)組。
本文采用C#語言和Visual Studio 2012工具對Autodesk Revit 2018進行二次開發(fā)。將教學樓、住宅小區(qū)和某施工場地BIM模型作為實驗數(shù)據(jù),使用插件分別將其導出為未執(zhí)行輕量化操作的GLB數(shù)據(jù)、執(zhí)行輕量化操作的GLB數(shù)據(jù)和屬性信息文件,并用Draco對輕量化后的GLB數(shù)據(jù)進行壓縮,處理結果如圖11所示。
圖11 Revit文件、未輕量化、輕量化與壓縮文件大小對比
在調試過程中分別統(tǒng)計了各GLB數(shù)據(jù)中Mesh的數(shù)量,如表1所示。Mesh數(shù)量在一定程度上體現(xiàn)數(shù)據(jù)輕量化的效果,每多一個Mesh,在GLB中的bin區(qū)至少多包含一份幾何數(shù)據(jù),與之對應,在JSON區(qū)多包含一份獲取該幾何數(shù)據(jù)的描述信息。另外,輕量化的結果因模型而異,對于富含相同構件的BIM模型,輕量化的結果較好。其中恒大場布模型包含214個Mesh,原因在于該模型大部分所用的是自定義的族,細分的粒度不如Revit內(nèi)建的族,例如,在塔吊的模型解析過程中,幾何數(shù)據(jù)作為一個整體被提取。
表1 GLB中Mesh數(shù)量統(tǒng)計
同時,將住宅小區(qū)模型與恒大場布模型的輕量化并經(jīng)過Draco壓縮處理的結果上傳至阿里云服務器,輕量化未經(jīng)過壓縮處理的結果上傳至Cesium Ion平臺進行測試,如圖12所示,左側為Three.js渲染結果,右側為Cesium的渲染結果。其中,渲染被Draco壓縮的GLB模型之前需要解碼,解碼時間內(nèi)會阻塞前端頁面響應,HTML5引入了WebWorker工作線程可以很好地解決此問題,并且Three.js內(nèi)置了子線程解碼模型并將解碼后的數(shù)據(jù)發(fā)送給主線程進行渲染的功能。
圖12 模型在Three.js與Cesium引擎中的渲染效果
在對屬性信息提取的工作中,基于RvtVa3c對構件工程信息提取工作的基礎上,進一步提取材料屬性、物理屬性,并將屬性信息以JSON格式寫入info文件中,屬性ID與GLB中node.name一一對應,教學樓模型的屬性信息如圖13所示。
對數(shù)據(jù)損失進行評估時,發(fā)現(xiàn)住宅小區(qū)模型構件總數(shù)為7 489個,而渲染結果顯示7 480個,損失9個構件,如圖14所示,在轉換過程中會有較小的數(shù)據(jù)損失。
圖14 住宅小區(qū)模型數(shù)據(jù)轉換損失評估
BIM模型作為建筑參數(shù)化的載體,具有空間不均勻、高度復雜、語義豐富和數(shù)據(jù)量大等特性。將BIM與互聯(lián)網(wǎng)技術相結合,需要從數(shù)據(jù)結構與算法、數(shù)據(jù)傳輸以及計算機圖形學等方向做相應的研究。但是BIM有眾多的數(shù)據(jù)源,增加了數(shù)據(jù)使用成本,給數(shù)據(jù)融合造成了一定的難度。而IFC作為BIM的數(shù)據(jù)標準,借助其進行數(shù)據(jù)交換,很大程度上受限于各個軟件平臺對標準的實現(xiàn)程度以及模型輕量化帶來的難度。本文借助Revit API實現(xiàn)BIM輕量化,仍有很大的不足:(1) 該轉換方法僅僅適用于Revit平臺,不具有普適性。(2) 數(shù)據(jù)在轉換過程中仍有少量幾何數(shù)據(jù)損失,需要進一步完善。(3) 需對數(shù)據(jù)的加載以及渲染策略進行優(yōu)化。因此這些不足也是以后需要研究方向。