3dTiles 数据规范详解[4.3]pnts ⽡⽚⼆进制数据⽂件结构
pnts,即 Points ,点云的意思。las、xyz数据等均可。
⽡⽚⽂件⼆进制布局(⽂件结构)
array工艺详解pnts不存在gltf模型,故结构如下:
1. ⽂件头:28byte
与b3dm是⼀样的。
2. 要素表
在 b3dm 篇,有介绍到要素表存在 全局属性 和 要素属性。在 pnts 和上篇 i3dm 中,这对概念会解释得很透彻。
① 要素表的全局属性
第⼀第⼆个能与 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. 量化空间范围体
这个词⼉是我⾃⼰意译的。
属性的官⽅名称字节长类型
含义
magic 4string (或char[4])该⽡⽚⽂件的类型,在pnts 中是 "pnts"version 4uint32该⽡⽚的版本,⽬前限定是 1.byteLength
4uint32该⽡⽚⽂件的⽂件⼤⼩,单位:byte featureTableJSONByteLength 4uint32要素表的JSON ⽂本(⼆进制形式)长度featureTableBinaryByteLength 4uint32要素表的⼆进制数据长度
batchTableJSONByteLength 4uint32批量表的JSON ⽂本(⼆进制形式)长度batchTableBinaryByteLength
4
uint32
批量表的⼆进制数据长度
属性名
数据类型描述
是否必须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 必须同时存在或者同时不存在
Processing math: 100%
通常点云数据只留其“形”,⽽具体每个点的坐标可以不那么精确。因为存储⾼精度的点坐标,是⼗分消耗空间的。默认每个点使⽤逐要素属性 POSITION 来记录每个点的坐标,坐标值类型是 FLOAT ,即 4
字节,假如使⽤量化坐标,每个坐标值使⽤ UInt16 类型,即 2字节,那么坐标信息就能压缩⼀倍!具体什么是 量化空间范围体,我认为在上⼀篇 i3dm 中已经解释得很清楚了:只不过,在点云⽡⽚中,POSITION 代表的不再是 instance 的坐标,⽽是点坐标。看到这,是否能理解“要素表的全局属性是对于整个⽡⽚⽂件⽽⾔”这句话了呢?
② 要素表的(逐)要素属性
其实,我觉得在点云中叫 点属性 更好。
其中,第⼀和第⼆个与 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. 要素表与批量表举例说明
此部分参考官⽅⽂档。
① 只有点坐标
属性名数据类型描述
是否必须
POSITION
float32 * 3直⾓坐标的点
是,除⾮POSITION_QUANTIZED 属性存在
POSITION_QUANTIZED uint16 * 3量化空间范围体内的直⾓坐标点是,除⾮POSITION 属性存在RGBA uint8 * 4四通道颜⾊不必须RGB uint8 * 3RGB 颜⾊
不必须RGB565uint16有损压缩颜⾊,红5绿6蓝5,即65536种颜⾊不必须NORMAL
float32 *3法线
不必须NORMAL_OCT16P uint8 * 2点的法线,10进制单位向量,有16bit 精度不必须
BATCH_ID
uint8/uint16(默认)/uint32
从BatchTable 种检索元数据的id
不必须,取决于全局属性BATCH_LENGTH
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 = at([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 = at([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 = at([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. 字节对齐与编码端序
6. 扩展(extensions)和额外信息(extras)
同样,这部分内容与b3dm篇章内介绍的⼀致,会在后续⽂章内介绍。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论