都說 “一流企業定標準,二流企業賣品牌,三流企業賣產品,四流企業做專案”,在面向類 WebGL 技術的三維瀏覽器端渲染的大規模流式資料載入技術中,等到了 MapGIS 主導的 m3d 標準。
1 門派
這一份濃濃的武漢味似乎是想在繼 Cesium 3d-Tiles
、Esri i3s
、超圖 S3M
後再在三維市場分一杯羹。
在前言中,吳老爺子帶路,洋洋灑灑的一隊人。
2 幾個術語簡析
- m3d:
Model of 3D
,在原文第 4 節有指出,但是翻譯過來不太對的樣子。 - glbx:
glTF
資料規範中,對於 glb 格式的一種變種檔案。原文指的是 “gltf資料的擴充套件格式”,我不清楚 m3d 標準對 gltf 擴充套件了什麼頂層屬性,或者是沒有好好研究glTF
規範,因為glTF
規範本身在幾乎所有的屬性中都有extensions
和extras
的預留屬性,用於擴充套件各種不同邏輯的業務功能或渲染特徵。
3 結構簡析
結構的設計與 Esri i3s
略相類似,使用 Node
充當空間剖分的術語。
M3DDataInfo.mcj
:一種 JSON 文字檔案,字尾名是 mcj,且此檔案的檔名可任意設定,用於描述整份 m3d 資料RootNodeInfo.json
、NodeInfo<i>.json
:對 node 的描述檔案,檔名可以自定義*.m3d
:m3d 檔案,一種壓縮檔案,可選壓縮格式有:,字尾名是m3d
,檔名可以自定義
每份 m3d 資料,其根目錄下有
- 一個
mcj
檔案描述整份資料 - 一個
Shared
目錄存放Shared.m3d
檔案 - 一個 根節點(RootNode)json 描述檔案
- 一個
Data
目錄用於存放子一級的節點目錄- 每個節點目錄下仍能擁有更下一級的節點目錄,可遞迴
- 每個節點目錄下有一個對當前 node 的 json 描述檔案
- 每個節點目錄下可擁有 n 個 m3d 檔案,這些被稱作 “瓦片”,用於管理不同行業的資料(點雲.m3d、傾斜攝影模型.m3d、bim.m3d、地質體.m3d)
- 每個 m3d 檔案下壓縮了三個目錄:
Geometry
、Texture
、Attribute
,分別存放*.glb/glbx
、*.jpg/png/webp
、*.json/bin
檔案用於儲存幾何、紋理、屬性資料
- 每個 m3d 檔案下壓縮了三個目錄:
3.1 空間剖分方式
規範中的術語是 “資料樹形結構”,個人認為使用 空間剖分方式 更好,直觀。
使用了三種常規三維資料結構,即空間八叉樹、四叉樹、KD樹。
3.2 空間範圍表示方式
BoundingBox
BoundingSphere
以上兩種常見空間範圍體二選一。
其中,BoundingBox
使用的定義是 6 元素的 AABB 包圍盒,即經緯高三軸的最值。
4 M3DDataInfo.mcj
類定義
描述整個 m3d 檔案的 json 檔案,它擁有如下頂層屬性:
- asset: string,基本資訊,簡單的字串
- version: string,這個令我十分無語,UML 圖中是
string
,在文下是float
,我認為string
更合適。 - dataName: string,資料名
- guid: string,資料唯一識別符號
- compressType: string,壓縮型別,可選
"zip"
、"7z"
、"rar"
- spatialReference: string,空間參考,可選
"WGS84"
、"CGCS2000"
- treeType: string,空間剖分結構,可選
"QuadTree"
、"OCTree"
、"K-DTree"
、"RTree"
,這點我也有點無語,在前文中並未提及 R樹,雖然 R樹在空間搜尋中還是很常見的。 - lodType: string,層次細節型別,可選
"ADD"
、"REPLACE"
- boundingVolume: BoundingVolume
- position: Point
- rootNode: Uri
- fieldInfo: Array<Field>
其中,BoundingVolume
在上文已提及,連同 Point
、Field
,在此簡單使用 Rust
結構體定義:
struct BoundingVolume {
boundingBox: BoundingBox,
boundingSphere: BoundingSphere,
}
struct BoundingBox {
left: f64,
top: f64,
right: f64,
bottom: f64,
minHeight: f64,
maxHeight: f64,
}
struct BoundingSphere {
center: Point,
radius: f64,
}
struct Point {
x: f64,
y: f64,
z: f64,
}
struct Field {
name: String,
type: String,
alias: String,
size: i32,
}
其中,Field
的 type 欄位可選值為 "bool"
、"int16"
、"uint16"
、"int32"
、"uint32"
、"int64"
、"uint64"
、"float"
、"double"
、"wchar"
、"text"
、"date"
、"time"
、"timestamp"
。
5 NodeInfo.json
類定義
每個節點(node)的描述檔案是一個 json 檔案,它的頂層屬性有:
- name: string
- lodLevel: string,用字串是一個留餘量的設計,因為不一定 level 必須是數字
- boundingVolume: BoundingVolume
- lodMode: string,可選值
"distance"
、"pixel"
- lodType: string,可選值
"ADD"
、"REPLACE"
- lodError: string,切換誤差值,單位根據
lodMode
決定 - transform: float[16],轉換矩陣
- parentNode: NodeInfo
- childrenNode: Array<NodeInfo>
- uri: string
- shared: Uri
- tileDataInfoIndex: int,M3D 瓦片索引
- tileDataInfoList: Array<TileDataInfo>,瓦片資料列表
其中,TileDataInfo
的類定義用 rust 表示可為:
struct TileDataInfo {
tileData: Uri,
geometry: Geometry,
attribute: Attribute,
texture: Uri,
dataType: string, // 可選值 "Vector"、"TiltPhotography"、"Model"、"BIM"、"PointCloud"、"PipeLine"、"GeoModel"、"GeoGrid"、"GeoDrill"、"GeoSection",分別表示:向量、傾斜、模型、BIM、點雲、管線、地質體、地質體網格、地址鑽孔、地質剖面
}
struct Geometry {
blobType: string, // 可選值 "glb"、"glbx"
url: string,
geoCompressType: string, // 只能是 "draco"
geometryType: string, // 可選值 "Point"、"Line"、"Polygon"、"Surface"、"Entity"
}
struct Attribute {
attType: string, // 可選值 "json"、"bin"
uri: string,
}
6 *.m3d
檔案
文中對 m3d 的介紹在 7.4 節,就不復述了,主要提一點:
- glbx:基於 glb 資料擴充套件了單體化資訊及地質體資料資訊的幾何要素檔案,字尾名為.glbx,檔名可自定義。
我覺得這個格式的提出是多餘的,槽點最後再談。
7. 地質模型幾何結構定義
由於本部分(原文位於7.4.3節)在原文中較為詳細,只撿幾個點提一提。
7.1 鑽孔模型幾何結構定義
略。
7.2 地質剖面模型幾何結構定義
剖面使用的是一個點列表表示的簡單封閉三維線,這是有缺點的,因為不能表達多剖面的情況。
7.3 地質體模型幾何結構定義
地質體在此處使用了多個索引三角面來定義,其實可以完全使用 glTF 來定義,只不過這裡簡化成了索引+頂點的形式。
7.4 網格模型幾何結構
這部分的設計略顯冗雜,有重複設計的嫌疑,沒有優化。
8 屬性檔案的設計
屬性檔案的型別在 M3DDataInfo 物件中定義,見本文第 4 部分。
它使用 “屬性記錄(Record)” 來描述一個屬性,又分了下列兩個類定義:
struct Record {
oid: long,
rcdValues: Vec<RcdValue>,
}
struct RcdValue<T> {
fldName: String,
rcdValue: T
}
關於此部分的吐槽留到最後。
9 單體化的定義
m3d 標準使用一個叫 oidTable
的表,記錄每個 “物件” 的單體資訊。
具體做法是,對每個頂點進行設定值,例如房屋A設定每個頂點的值是1,那麼就記錄在 oidTable 中即可。
並由此擴充套件 glb 檔案,構成 glbx 檔案。
單開一小節吐槽
在 Cesium 提出的 glTF 擴充套件中,有一個更為接近此設計的擴充:glTF 中 Primitive 的定義增加一個 _BATCHID
,使得頂點屬性新增一個,與 POSITION
、COLOR
等同級別,使用此 _BATCHID
來區分頂點歸屬於哪個 batch。
利用 glTF 強大的擴充套件能力完全沒必要 “擴充套件 glb 檔案成 glbx”。
另外,單體化也是一個偽命題。因為傾斜攝影模型僅僅是有外觀的三角網模型,不具備精細模型和 GIS 要素的獨立性,所以才提出 “單體化” 這種詞。
在 GIS 資料、BIM 資料中就很少聽說過這詞,因為這兩種資料本身就有著完備的物件獨立資訊。
如果模型建模時,有完整的地理要素的定義,其實就具備了單體化的資訊,使用 GIS 中的 “要素” 完全可以區分開不同的物體。
10 Shared
資料夾
關於此資料夾沒有過多的描述,只有不到 1/4 頁紙。
它似乎是設計來存放公共資料的,用來提供 instance
能力。
11 RESTful 介面設計
11.1 資料資訊獲取服務:M3DData
url模板:<base-url>/services/<service-name>/M3dServer
例:
http://igserver.mapgis.com/igs/rest/services/wuhan-3d/M3dServer
調取方法是 HTTP GET
,返回型別是 application/json
11.2 公共資源獲取服務:M3DSharedResources
url模板:<m3d-data-url>/shared-resources
例:
http://igserver.mapgis.com/igs/rest/services/wuhan-3d/M3dServer/shared-resource
調取方法是 HTTP GET
,返回型別是 application/octet-stream
11.3 根節點資訊獲取服務:M3DRootNodeInfo
略
11.4 其他服務
為什麼寫兩個就不寫了?
因為原文定義已經很詳細了,無需複述。
12 優點
- 幾何部分使用
glTF
定義 - 能使用
webp
作為紋理貼圖 - 容納了各行各與的業務資料
- 規範定義較為完備,文件廢話不多,但是不失詳盡性
- 參考了i3s的結構定義,設計上把幾何、紋理、屬性資料解耦
- 在幾何部分能重視 draco 壓縮演算法
13 缺點
① 對 glTF 規範認知不全
沒有充分閱讀 glTF 規範
- glTF 本身就含有紋理貼圖、取樣器、材質的定義,此處再將紋理貼圖單獨定義,但未指出究竟是幾何部分的 glb/glbx 獨立儲存幾何 + 紋理單獨存放在紋理目錄,亦或者是混用,這一點十分疑惑。
沒有充分利用 glTF 強大的擴充套件能力
- glTF 本身就帶了十幾種世界各大組織提供的擴充套件能力,包括但不限於紋理壓縮、幾何壓縮、材質擴充套件
如無必要,勿增實體。glbx 是一種多餘的設計。
② 文件定義缺陷
定義歧義
對於路徑的定義,在原文見過 Uri
、url
、string
三種寫法。
對於空間剖分的定義,在檔案組織上,使用 Node
資料夾來組織,但是其下的各部分資料又使用 Tile
來定義,在原文第 3.2 節還專門說明了瓦片資料,卻不見 Node
的詳細定義;
在圖1和圖2中,對 Node 和 m3d 檔案的組織十分困惑,Node<i>
目錄應該是一個 Node
,下面能掛載 N 個 m3d 檔案;但是在原文 3.3 節中,每個瓦片下面掛 0 或 1 個 m3d 檔案,卻不見瓦片的定義,只見 tile data(瓦片資料)
的定義。
asset
屬性按理說可以囊括 name
、version
、guid
、dataName
等屬性的,卻將他們分開,不知道設計上是否經過足夠的考慮。
型別錯誤
在 M3DDataInfo 的類定義中,對於 version
欄位的型別,表格裡是 float
,表格上面的 UML 類圖又是 string
,這種低階錯誤應該在校對的時候修正。
UML 描述不夠完整
屬性的預設值、屬性的可選性未指出。
屬性拼寫不規範
例如 geoCompressType
,此屬性是 Geometry
類下的,按理說就不需要 geo
字首,只需保留 compressType
即可。
還有 attType
,該簡寫的地方簡寫,此處就不該簡寫,它是 Attribute
物件的一個屬性,所以它應該是 type
。
RcdValue
物件應該完整的命名為 RecordValue
,且其 rcdValue
應簡單命名為 value
,它的型別還出現了模糊不清的定義,因為沒有人知道 value
是什麼值型別。
駝峰命名法、下劃線命名法混用就不說了。
③ 標準裡太多 “專有” 詞彙
- 單體化:這個就不適用於全體行業資料,在本文第 9 節已詳盡提及。
- 其他見 本文 14.②
④ 對一些屬性未完全解釋
lodType
:對"ADD"
、"REPLACE"
未完全解釋lodError
:未解釋其詳細的值含義
14 槽點
① ArcGIS Server REST介面風格味道太重
在原文的第 8 部分體現的十分明顯,RESTful
風格其實完全沒有必要設計如此冗雜的 URL 模板。
② 對資料的行業層級和結構層級混淆
資料的結構層級是與行業無關的,例如 “向量” 是一種概念,向量資料可以囊括二維圖形、三維圖形資料,完全可以描述幾何部分。
行業層級必須基於結構層級去定義,才有物質基礎,這一點馬克思老爺子早就總結好了。如果一個行業的資料對其底層的結構不清楚,例如單提 “BIM資料”,不提是什麼格式,不提它的結構,那也只能是談判桌上的詞,落實不下來,談不了什麼自主創新。
③ 使用商業壓縮格式 rar,使用過多的壓縮格式
若為開放標準,而使用半封閉的 rar 格式,則必須在服務端多準備一個 rar 解壓的程式。
zip、7z 作為儲存時能有效減少體積,但是文章中並未提及這兩種壓縮方式的壓縮等級、壓縮與解壓縮的效能開銷,如果因為這些延長了檔案 IO 的時間,那是得不償失的。
這一點是 i3s 的資源 gzip 法則佔優,因為瀏覽器天生支援 gzip,並且開銷不算很大。
④ 擴充套件性不佳
若將來要新增氣象資料或時態資料,沒有留有冗餘的設計。
15 個人總結
定義這種型別的資料規範,不僅要有足夠充足的行業一線實踐經歷,還要在 Web 視覺化領域有足夠的底層技術積累。
從技術和資料的視角做定義,才具備完整的可實施性和一般適配性。
M3D 的提出豐富了我國對三維資料規範的標準庫,但是現在缺實現,生態不足,推廣幾乎沒有,如何讓各行各業買賬,還需要走相當長的路,務必腳踏實地,方可行百里路。