轉載請規范宣告,@秋意正寒 https://www.cnblogs.com/onsummer/p/13252898.html
我的git地址:github.com/onsummer
pnts,即 Points,點云的意思,
las、xyz資料等均可,
瓦片檔案二進制布局(檔案結構)
pnts不存在gltf模型,故結構如下:

1. 檔案頭:28byte
與b3dm是一樣的,
| 屬性的官方名稱 | 位元組長 | 型別 | 含義 |
|---|---|---|---|
magic |
4 | string(或char[4]) | 該瓦片檔案的型別,在pnts中是 "pnts" |
version |
4 | uint32 | 該瓦片的版本,目前限定是 1. |
byteLength |
4 | uint32 | 該瓦片檔案的檔案大小,單位:byte |
featureTableJSONByteLength |
4 | uint32 | 要素表的JSON文本(二進制形式)長度 |
featureTableBinaryByteLength |
4 | uint32 | 要素表的二進制資料長度 |
batchTableJSONByteLength |
4 | uint32 | 批量表的JSON文本(二進制形式)長度 |
batchTableBinaryByteLength |
4 | uint32 | 批量表的二進制資料長度 |
2. 要素表
在 b3dm 篇,有介紹到要素表存在 全域屬性 和 要素屬性,在 pnts 和上篇 i3dm 中,這對概念會解釋得很透徹,
① 要素表的全域屬性
| 屬性名 | 資料型別 | 描述 | 是否必須 |
|---|---|---|---|
| POINTS_LENGTH | uint32 | 瓦片中點的數量,所有的點屬性的長度必須與這個一樣, | 必須存在 |
| RTC_CENTER | float32 * 3 | 如果所有點是相對于某個點定位的,那么這個屬性就是這個相對的點的坐標, | 不必須 |
| QUANTIZED_VOLUME_OFFSET | float32 * 3 | 量化偏移值 | 與QUANTIZED_VOLUME_SCALE屬性必須同時存在或同時不存在 |
| QUANTIZED_VOLUME_SCALE | float32 * 3 | 量化縮放比例 | 與QUANTIZED_VOLUME_OFFSET屬性必須同時存在或同時不存在 |
| CONSTANT_RGBA | uint8 * 4 | 為所有點定義同一個顏色 | 不必須 |
| BATCH_LENGTH | uint32 | BATCH_ID的個數 | 與點屬性中的BATCH_ID必須同時存在或者同時不存在 |
第一第二個能與 b3dm 中的 BATCH_LENGTH 和 RTC_CENTER 類比來理解,就不解釋了,
第3、4個與 i3dm 是一致的,
第5個即每個點的默認顏色,默認是灰色,
最后一個很有意思,和 b3dm 里的“重合”了,它的意義是:點云瓦片中這么多點是可以劃分的,每一類叫做 BATCH,
例如對一棟建筑進行點云掃射,那么墻體的所有的點可以歸屬為 墻體BATCH,窗戶的所有點可以歸屬為 窗戶BATCH,
BATCH_LENGTH 指示了當前pnts瓦片的點被劃分成了多少個類別,
a. pnts瓦片中顏色的優先級
RGBA>RGB>RGB565>CONSTANT_RGBA,其中,CONSTANT_RGBA 是全域的,前三個是點要素屬性里的,
當然,還可以使用 3dTiles 的 style 來改變樣式,
b. 量化空間范圍體
這個詞兒是我自己意譯的,
通常點云資料只留其“形”,而具體每個點的坐標可以不那么精確,因為存盤高精度的點坐標,是十分消耗空間的,默認每個點使用逐要素屬性 POSITION 來記錄每個點的坐標,坐標值型別是 FLOAT,即 4位元組,假如使用量化坐標,每個坐標值使用 UInt16 型別,即 2位元組,那么坐標資訊就能壓縮一倍!
具體什么是 量化空間范圍體,我認為在上一篇 i3dm 中已經解釋得很清楚了:
只不過,在點云瓦片中,POSITION 代表的不再是 instance 的坐標,而是點坐標,
看到這,是否能理解“要素表的全域屬性是對于整個瓦片檔案而言”這句話了呢?
② 要素表的(逐)要素屬性
其實,我覺得在點云中叫 點屬性 更好,
| 屬性名 | 資料型別 | 描述 | 是否必須 |
|---|---|---|---|
| POSITION | float32 * 3 | 直角坐標的點 | 是,除非POSITION_QUANTIZED屬性存在 |
| POSITION_QUANTIZED | uint16 * 3 | 量化空間范圍體內的直角坐標點 | 是,除非POSITION屬性存在 |
| RGBA | uint8 * 4 | 四通道顏色 | 不必須 |
| RGB | uint8 * 3 | RGB顏色 | 不必須 |
| RGB565 | uint16 | 有損壓縮顏色,紅5綠6藍5,即65536種顏色 | 不必須 |
| NORMAL | float32 *3 | 法線 | 不必須 |
| NORMAL_OCT16P | uint8 * 2 | 點的法線,10進制單位向量,有16bit精度 | 不必須 |
| BATCH_ID | uint8/uint16(默認)/uint32 | 從BatchTable種檢索元資料的id | 不必須,取決于全域屬性BATCH_LENGTH |
其中,第一和第二個與 i3dm 中的定義一致,
第三~第五個是顏色資訊,在第①小節中的a部分講了,
第六、七與 i3dm 中的類似,
第八個與 i3dm 中的定義完全一致,
③ 要素表的JSON
上述所有屬性全部會記錄在要素表的 JSON 中,對于 全域屬性,其值記錄在 JSON 中,
對于其要素屬性,因為點云中的點數量會非常巨大,寫在JSON中體積會變大,所以使用 JSON參考要素表二進制資料體 的形式,
下列是一個要素表的JSON:
{
POINTS_LENGTH : 4, // 意味著有4個點
POSITION : {
byteOffset : 0 // 意味著從ftBinary的第0個byte開始讀取
}
}
這個要素表的釋義與 i3dm 中的示例一樣,只不過從 INSTANCES_LENGTH 變成了 POINTS_LENGTH,
④ 要素表體
要素表JSON中參考的二進制資料均順次記錄在此,一般為要素屬性(點屬性),
3. 批量表
批量表與b3dm的差不多,如果在 pnts 的要素表和批量表中存盤了 BATCH_LENGTH 資訊,那每個 BATCH 的屬性就存于此,
但是與 b3dm、i3dm 略有不同的是,如果要素表JSON中沒有 BATCH_ID 的定義,但是批量表中卻存在與點的數量 POINTS_LENGTH 一樣長的屬性陣列,那么說明該點云瓦片的每一個點都有屬性,
結構參考 b3dm 篇章,
4. 要素表與批量表舉例說明
此部分參考官方檔案,
① 只有點坐標
const featureTableJSON = {
POINTS_LENGTH : 4, // 意味著有4個點
POSITION : {
byteOffset : 0 // 意味著從ftBinary的第0個byte開始讀取
}
}
const featureTableBinary = new Buffer(new Float32Array([
0.0, 0.0, 0.0,
1.0, 0.0, 0.0,
0.0, 0.0, 1.0,
1.0, 0.0, 1.0
]).buffer)
這個例子只記錄了4個點,
② 相對坐標與顏色資訊
const featureTableJSON = {
POINTS_LENGTH : 4, // 意味著有4個點
RTC_CENTER : [1215013.8, -4736316.7, 4081608.4], // 意味著相對于這個點
POSITION : {
byteOffset : 0 // 意味著從ftBinary的第0個byte開始讀取
},
RGB : {
byteOffset : 48 // 顏色值意味著從ftBinary的第48個byte讀取,緊接在POSITION后
}
}
const positionBinary = new Buffer(new Float32Array([
0.0, 0.0, 0.0,
1.0, 0.0, 0.0,
0.0, 0.0, 1.0,
1.0, 0.0, 1.0
]).buffer) // 一共12*4byte = 48byte
const colorBinary = new Buffer(new Uint8Array([
255, 0, 0,
0, 255, 0,
0, 0, 255,
255, 255, 0,
]).buffer) // 一共12*1byte = 12byte
// ftBinary一共48+12=60byte
const featureTableBinary = Buffer.concat([positionBinary, colorBinary])
這個例子有4個點,是相對于中心定位的點,顏色依次為:紅綠藍黃,
③ 量化坐標與八進制編碼法向量
const featureTableJSON = {
POINTS_LENGTH : 4, // 意味著有4個點
QUANTIZED_VOLUME_OFFSET : [-250.0, 0.0, -250.0], // 意味著偏移基坐標是 (-250, 0, -250)
QUANTIZED_VOLUME_SCALE : [500.0, 0.0, 500.0], // 意味著x和z方向的縮放比是500
POSITION_QUANTIZED : {
byteOffset : 0 // 意味著量化坐標的資料存在ftBinary的第0個位元組往后
},
NORMAL_OCT16P : {
byteOffset : 24 // 意味著量化坐標頂點法線的資料存在ftBinary的第24個位元組往后
}
}
const positionQuantizedBinary = new Buffer(new Uint16Array([
0, 0, 0,
65535, 0, 0,
0, 0, 65535,
65535, 0, 65535
]).buffer) // 一共12*2byte=24byte,Uint16=16bit=2byte
const normalOct16PBinary = new Buffer(new Uint8Array([
128, 255,
128, 255,
128, 255,
128, 255
]).buffer) // 一共8*1=8byte,Uint8=8bit=1byte
const featureTableBinary = Buffer.concat([positionQuantizedBinary, normalOct16PBinary])
這個例子中,有4個點,每個點的法向量都是八進制編碼的\([0.0, 1.0, 0.0]\),它們將被放置在x和z方向上.
④ 點資料分類(BATCH)
const featureTableJSON = {
POINTS_LENGTH : 4, // 意味著有4個點
BATCH_LENGTH : 2, // 意味著4個點分成了2類(批、batch)
POSITION : {
byteOffset : 0 // 意味著POSITION將存盤在ftBinary的第 0 byte之后
},
BATCH_ID : {
byteOffset : 48, // 意味著BATCH_ID的值將從ftBinary的第 48 byte之后
componentType : "UNSIGNED_BYTE" // 意味著BATCH_ID的值型別是無符號位元組數
}
}
const positionBinary = new Buffer(new Float32Array([
0.0, 0.0, 0.0,
1.0, 0.0, 0.0,
0.0, 0.0, 1.0,
1.0, 0.0, 1.0
]).buffer) // 4個點,一共12個值,每個值4byte(Float每個數字占4byte,即32bit),一共48byte
const batchIdBinary = new Buffer(new Uint8Array([
0,
0,
1,
1
]).buffer) // 前2個的型別是0(batchId),后2個點的型別是1
const featureTableBinary = Buffer.concat([positionBinary, batchIdBinary]); // 合并
const batchTableJSON = {
names : ['object1', 'object2']
} // 批量表JSON記錄了屬性值,有兩個,剛好對上 BATCH_LENGTH
這個例子中,前2個點的 batchId 是0,后2個點的 batchId 是1,
⑤ 每個點都有屬性
const featureTableJSON = {
POINTS_LENGTH : 4, // 意味著有4個點
POSITION : {
byteOffset : 0 // 意味著從ftBinary的第0byte開始
}
}
const featureTableBinary = new Buffer(new Float32Array([
0.0, 0.0, 0.0,
1.0, 0.0, 0.0,
0.0, 0.0, 1.0,
1.0, 0.0, 1.0
]).buffer)
const batchTableJSON = {
names : ['point1', 'point2', 'point3', 'point4'] // 意味著這4個點都有names屬性,其值寫在這里
}
如果在 要素表中沒有 BATCH_ID 屬性的定義,并且批量表中存有屬性資料,那么這些屬性的個數必定與點的個數相同,即每個點都有屬性,
5. 位元組對齊與編碼端序
與b3dm里寫的一致,可以回看:https://www.cnblogs.com/onsummer/p/13252896.html
6. 擴展(extensions)和額外資訊(extras)
同樣,這部分內容與b3dm篇章內介紹的一致,會在后續文章內介紹,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/786.html
標籤:GIS
