本篇翻译自3d-tiles specification Batched 3D Model瓦片格式官方说明,部分参考自3dTiles 数据规范详解b3dm瓦片二进制数据文件结构
0 Overview
Batched 3D Model allows offline batching of heterogeneous 3D models, such as different buildings in a city, Batched 3D Model 允许离线批处理合并异构的3D模型(比如在城市中的不同建筑物) for efficient streaming to a web client for rendering and interaction. Efficiency comes from transferring multiple models in a single request and rendering them in the least number of WebGL draw calls necessary. 其高效来自于一次请求传输多个模型,并且在最少次数的WebGL的draw calls来渲染。 Using the core 3D Tiles spec language, each model is a feature.
Per-model properties, such as IDs, enable individual models to be identified and updated at runtime, e.g., show/hide, highlight color, etc. Properties may be used, for example, to query a web service to access metadata, such as passing a building’s ID to get its address. 每个模型的属性,比如IDs,使得在运行时单独标记和更新对象成为可能,比如:显示/隐藏、高亮颜色等等。例如属性可能被用来从服务器中查询元数据(例如传递建筑物的 ID 以获取其地址)。 Or a property might be referenced on the fly for changing a model’s appearance, e.g., changing highlight color based on a property value.
A Batched 3D Model tile is a binary blob in little endian.
1 Layout
瓦片由标头及紧随其后的内容体组成,瓦片文件二进制布局如下:
Padding
A tile’s byteLength
must be aligned to an 8-byte boundary.byteLength
必须以8字节边界进行对齐。 The contained Feature Table and Batch Table must conform to their respective padding requirement.
The binary glTF must start and end on an 8-byte boundary so that glTF’s byte-alignment guarantees are met. This can be done by padding the Feature Table or Batch Table if they are present.
2 Header 头文件
头文件占28字节(byte),包含7个属性数据:
属性名 | 数据类型 | 含义 |
---|---|---|
magic |
4-byte ANSI string | 该瓦片文件的类型,在b3dm中是 “b3dm” |
version |
uint32 |
该瓦片的版本,目前限定是 1. |
byteLength |
uint32 |
该瓦片文件的文件大小,单位:byte |
featureTableJSONByteLength |
uint32 |
要素表的JSON文本(二进制形式)长度 |
featureTableBinaryByteLength |
uint32 |
要素表的二进制数据长度 |
batchTableJSONByteLength |
uint32 |
批量表的JSON文本(二进制形式)长度,0表示无批量表 |
batchTableBinaryByteLength |
uint32 |
批量表的二进制数据长度 |
其中,byteLength
= 28 + featureTableJSONByteLength
+ featureTableBinaryByteLength
+ batchTableJSONByteLength
+ batchTableBinaryByteLength
+ glb的字节长度
The body section immediately follows the header section, and is composed of three fields: Feature Table
, Batch Table
, and Binary glTF
.
3 Feature Table 要素表
Contains values for b3dm
semantics.
More information is available in the Feature Table specification.
See Property reference for the b3dm
feature table schema reference. The full JSON schema can be found in b3dm.featureTable.schema.json.
Semantics 属性
Feature semantics 要素属性
b3dm文件暂时没有。
Global semantics 全局属性
什么是全局属性?即对于瓦片内每个三维模型(或BATCH、要素features)起作用的数据(不作用于单个Batch),在b3dm中,要素表有以下全局属性:
属性名 | 数据类型 | 描述 | 是否必须 |
---|---|---|---|
BATCH_LENGTH |
uint32 |
当前瓦片文件内可分的三维模型(distinguishable models)(或称为BATCH、要素)的个数,If the Binary glTF does not have a batchId attribute, this field must be 0 . |
Yes |
RTC_CENTER |
float32[3] |
为模型相对坐标定义的中心参考坐标,(see Coordinate system). | No |
4 Batch Table 批量表
批量表记录的是每个模型的属性数据,以及扩展数据, indexable by batchId
, that can be used for declarative styling and application-specific use cases such as populating a UI or issuing a REST API request. 在二进制的glTF部分,每个顶点有一个数值类型属性batchId(范围在[0, number of models in the batch - 1
])。 The batchId
indicates the model to which the vertex belongs. 这使得对象(models)可以被合并在一起(为了高效传输和渲染),但仍旧可以是独立识别的。
See the Batch Table reference for more information.
要素表和批量表唯一的联系就是 BATCH_LENGTH
,在 i3dm 中叫 INSTANCE_LENGTH
,在 pnts 中叫 POINTS_LENGTH
。
这很好理解,要素表记录了有多少个模型(BATCH、要素),那么批量表每个属性就有多少个值。
参考示例
JSON头部数据
先上一份批量表的JSON看看:
{
"height" : {
"byteOffset" : 0,
"componentType" : "FLOAT",
"type" : "SCALAR"
},
"geographic" : {
"byteOffset" : 40,
"componentType" : "DOUBLE",
"type" : "VEC3"
},
}
这个批量表的JSON有两个属性:height、geographic,字面义即模型的高度值、地理坐标值。
height 属性通过其 componentType
指定数据的值类型为 FLOAT
,通过其 type
指定数据的元素类型为 SCALAR
(即标量)。
geographic 属性通过其 componentType
指定数据的的值类型是 DOUBLE
,通过其 type
指定数据的元素类型为 VEC3
(即3个double数字构成的三维向量)。
byteOffset ,即这个属性值在 二进制本体数据 中从哪个字节开始存储。
从上表可以看出,height 属性跨越 0 ~ 39 字节,一共40个字节。
通过 FeatureTableJSON 可以获取 BATCH_LENGTH 为10,那么就有10个模型,对应的,这 40 个字节就存储了10个 height 值;FLOAT类型的数据字节长度为 4,刚好 4 byte × 10 = 40 byte,即 height 属性的全部数据的总长。
geographic 属性也同理,VEC3 代表一个 geographic 有3个 DOUBLE 类型的数字,一个 DOUBLE 数值占 8byte,那么 geographic 一共数据总长是:
type
× componentType
× BATCH_LENGTH
= 3 × 8byte × 10 = 240 byte.
事实上,两个属性的总长是 40 + 240 = 280 byte,与 b3dm 文件头中的第七个属性 batchTableBinaryByteLength
= 280 是一致的。
二进制本体数据
二进制本体数据即批量表中每个属性的顺次存储。
能不能不写二进制本体数据?
可以。如果你觉得数据量比较小,可以直接把数据写在 BatchTableJSON
中,还是以上述两个数据为例:
{
"height": [10.0, 20.0, 15.0, ...], // 太长了不写那么多,一共10个
"geographic": [
[113.42, 23.10, 102.1],
[111.08, 22.98, 24.94],
// 太长不写
]
}
但是,读者请一定注意这一点:同样是一个数字,二进制的JSON文本大多数时候体积会比二进制数据大。因为JSON文本还包括括号、逗号、冒号等JSON文本必须的符号。对于属性数据相当大的情况,建议使用 JSON引用二进制本体数据的组织形式,此时JSON充当的角色是元数据。
注意:对于属性的值类型是 JSON 中的 object、string、bool 类型,则必须存于 JSON 中,因为二进制体只能存标量、234维向量四种类型的数字数据。
5 Binary glTF 内嵌的glb
Batched 3D Model内嵌glTF 2.0,其中包含模型的几何和纹理信息。
binary glTF 紧随在Feature Table和Batch Table之后。它可以嵌入所有的几何、纹理和动画数据,也可以引用外部的资源来表达部分或所有的这些数据。
如上所述,每个顶点都可以用一个batchId
特性来标记它属于哪个对象(model)。例如,一个有3个model的一个batch的顶点可能如下:
batchId: [0, 0, 0, ..., 1, 1, 1, ..., 2, 2, 2, ...]
position: [xyz, xyz, xyz, ..., xyz, xyz, xyz, ..., xyz, xyz, xyz, ...]
normal: [xyz, xyz, xyz, ..., xyz, xyz, xyz, ..., xyz, xyz, xyz, ...]
顶点不需要根据batchId
Vertices do not need to be ordered by batchId
, so the following is also OK:
batchId: [0, 1, 2, ..., 2, 1, 0, ..., 1, 2, 0, ...]
position: [xyz, xyz, xyz, ..., xyz, xyz, xyz, ..., xyz, xyz, xyz, ...]
normal: [xyz, xyz, xyz, ..., xyz, xyz, xyz, ..., xyz, xyz, xyz, ...]
Note that a vertex can’t belong to more than one model; in that case, the vertex needs to be duplicated so the batchId
s can be assigned.
The batchId
parameter is specified in a glTF mesh primitive by providing the _BATCHID
attribute semantic, along with the index of the batchId
accessor. For example,
"primitives": [
{
"attributes": {
"_BATCHID": 0
}
}
]
{
"accessors": [
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 4860,
"max": [2],
"min": [0],
"type": "SCALAR"
}
]
}
The accessor.type
must be a value of "SCALAR"
. All other properties must conform to the glTF schema, but have no additional requirements.
When a Batch Table is present or the BATCH_LENGTH
property is greater than 0
, the _BATCHID
attribute is required; otherwise, it is not.
Coordinate system
By default embedded glTFs use a right handed coordinate system where the y-axis is up. For consistency with the z-up coordinate system of 3D Tiles, glTFs must be transformed at runtime. See glTF transforms for more details.
Vertex positions may be defined relative-to-center for high-precision rendering, see Precisions, Precisions. If defined, RTC_CENTER
specifies the center position that all vertex positions are relative to after the coordinate system transform and glTF node hierarchy transforms have been applied.
6 File extension and MIME type
Batched 3D Model tiles使用.b3dm
扩展格式和application/octet-stream
MIME type。
文件后缀名可改,一般程序通过文件头magic
字段读取确定文件类型。
7 Implementation example
本章节是非规范性的
Code for reading the header can be found in
Batched3DModelTileContent.js
in the CesiumJS implementation of 3D Tiles.
8 字节对齐与编码端序
JSON二进制文本对齐
FeatureTableJSON、BatchTableJSON的二进制文本,最后一个字节相对于整个b3dm文件来说,偏移量必须是8的倍数。
如果不对齐,必须用二进制空格(即 0x20
)填够。
你问我为啥不对起始偏移量也要求 8byte 对齐?因为 FeatureTableJSON 之前是28byte的 文件头,为了凑齐8倍数对齐,文件头和 FeatureTableJSON 还要塞4个字节填满,那就有点多余了。
末尾对齐,即 (28 + ftJSON长)能整除8,(28 + ftTable长 + btJSON长)能整除8.
数据体的起始、末尾对齐
二进制数据体,无论是要素表、批量表,首个字节相对于b3dm文件的字节偏移量,必须是8的倍数,结束字节的字节偏移量,也必须是8的倍数。
如果不满足,可以填充任意数据字节满足此要求。
特别的,二进制数据体中,每一个属性值的第一个数值的第一个字节的偏移量,相对于整个b3dm文件,必须是其 componentType
的倍数,如果不满足,则必须用空白字节填满。
例如,上述 height 属性所在的批量表二进制数据体,理所当然位于批量表JSON之后,而批量表的JSON又是8byte对齐的,假设批量表的数据体起始字节是800,那么 height 的第一个值起始字节就是 800,由于 height 属性的 componentType
是 FLOAT,即 4字节,800 ÷ 4 能整除,所以没有问题。
但是,假如 换一个属性,其 componentType
是 BYTE
,即 1字节,那么假设第二个属性的 componentType
是 DOUBLE
,即 8字节,就会出现 第二个属性的第一个值起始偏移量是810,810 ÷ 8 并不能整除,必须补齐 6个空白字节,以满足第二个属性第一个值的起始偏移量是 810+6 = 816字节。
编码端序
要素表、批量表的二进制数据,无论是JSON还是数据体,均使用小端序编码(LittleEndian)。
「如果这篇文章对你有用,请随意打赏」
如果这篇文章对你有用,请随意打赏
使用微信扫描二维码完成支付

comments powered by Disqus