3dTiles 數據規范詳解[4.3] pnts瓦片二進制數據文件結構


轉載請規范聲明。@秋意正寒 https://www.cnblogs.com/onsummer/p/13252898.html
我的git地址:github.com/onsummer
目錄:https://www.cnblogs.com/onsummer/p/12799366.html

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_LENGTHRTC_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篇章內介紹的一致,會在后續文章內介紹。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM