3dTiles 数据规范详解[3] 内嵌在瓦片文件中的两大数据表

转载请声明出处:全网@秋意正寒

零、本篇前言

说实话,我很纠结是先先容瓦片的二进制数据文件结构,照样先先容这两个主要的表。思前想后,我决议照样先先容这两个数据表。

由于这两个表不先给读者贯注,那么先容到瓦片的二进制数据文件结构时,就满嘴“艰涩难明”啦。

数据与模子

上文先容到,瓦片的三维模子实际上是由gltf负担起来的(作为glb花样嵌入到瓦片二进制文件中),那么,除了模子数据,一定模子自己自己也有属性数据的。

就好比,门有长宽高、密度、生产日期等信息,楼栋模子有建筑面积、楼层数等信息。

以是,“属性数据” 和 “模子” 是若何发生联系的呢?

dTiles

早在我的博客《聊聊GIS数据的四个分层与GIS服务》中有提及,只需把模子的几何数据作为一个属性,写入属性数据中,即把属性数据和几何数据并列,就可以了。

然则,在3dTiles中,模子数据是以glb的形式嵌入在瓦片文件中的(点云直接就写xyz和颜色信息了),模糊了二维中“要素”的观点,而且gltf规范看起来并没有所谓的“要素”的观点,仅仅是对GPU友好的vertex、normal、texture等信息。

若何让gltf模子的每一个模子,甚至每一个三角面,甚至每一个极点打上“我属于哪个模子”的印记呢?我们本篇稍稍晚一些先容。

再回忆一个主要的 3dTiles 理念:

3dTiles 规范自己不包罗模子数据的界说,它仅仅纪录模子酿成瓦片后的空间组织关系、模子与其属性数据之间的关系。

以是,3dTiles 规范在瓦片二进制数据文件中,使用了两个主要的表来纪录这种 ”模子与属性“ 的联系:

  • FeatureTable(要素表)
  • BatchTable(批量表)

瓦片二进制数据文件的大致字节结构结构

dTiles

上一篇简朴提过,瓦片引用的二进制文件有4种,即:b3dm、i3dm、pnts、cmpt。

除去cmpt这个复合类型不谈,前三种的大致结构见上图。

每一种瓦片二进制数据文件都有一个纪录该瓦片的文件头信息,文件头包罗若干个因瓦片差别而不太一致的数据信息,紧随其后的是两大数据表:FeatureTable(我翻译其为:要素表)、BatchTable(我翻译其为:批量表)。

这两个表既然是二进制的数据,尽管它名字里带“表”,然则却不是二维表格,它更多的是一些 键值 信息。

关于差别瓦片二进制文件的这两个表的结构,在后续博文会详细先容。

一、纪录渲染相关的数据:FeatureTable,要素表

在 b3dm 瓦片中,要素表纪录这个批量模子瓦片中模子的个数,这个模子单体在人类逻辑上不能再分。

(在衡宇级别来看,屋子并不是单体,组织它的门、门把、窗户、屋顶、墙等才是模子单体;然则在模子壳子的通俗外面建模数据中,屋子就是一个简朴的模子)

要素表还可以纪录当前瓦片的中央坐标,以便gltf使用相对坐标,压缩极点坐标数字的数据量。

官方给的界说是:

要素表纪录的是与渲染有关的数据。

直球!听不懂!

我来“翻译”一下好了:

要素表,纪录的是整个瓦片渲染相关的数据,而不是渲染所需的数据。

渲染相关,即有多少个模子,坐标是相对的话相对于哪个中央,若是是点云的话颜色信息是什么以及坐标若何等;

渲染所需,例如极点信息、法线贴图材质信息均有glb部门完成。

我们以pnts(点云瓦片)举例,它的要素表允许有两大类数据(看不懂没关系,之后的博客还会继续先容四种瓦片文件的结构):

  • 点属性:纪录每个点云点的信息
属性名 数据类型 形貌 是否必须
POSITION float32 * 3 直角坐标的点 是,除非下面的属性存在
POSITION_QUANTIZED uint16 * 3 量化的直角坐标点 是,除非上面的属性存在
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 /
  • 全局属性:纪录整个点云瓦片的信息
属性名 数据类型 形貌 是否必须
POINTS_LENGTH uint32 瓦片中点的数目。所有的点属性的长度必须与这个一样。
RTC_CENTER float32 * 3 若是所有点是相对于某个点定位的,那么这个属性就是这个相对的点的坐标。 /
QUANTIZED_VOLUME_OFFSET float32 * 3 量化偏移值(不知道是什么) 与下面的属性必须同时存在
QUANTIZED_VOLUME_SCALE float32 * 3 量化缩放比例(不知道是什么) 与上面的属性必须同时存在
CONSTANT_RGBA uint8 * 4 为所有点界说同一个颜色 /
BATCH_LENGTH uint32 BATCH_ID的个数 与点属性中的BATCH_ID必须同时存在

简略一瞥,可以看出点云由于没有使用gltf模子(也没必要),把点云要渲染到屏幕上所需的坐标、法线、颜色等信息写在了要素表中。

若是照样不能明白作甚“渲染相关”,那么请阅读后续四种瓦片文件花样的详细先容,相信你会有所收获——有可能是我表达对照菜。

Flv.js文档使用随记

要说明一个“业界黑话”:

在一个瓦片中,一个三维要素(GIS中的通常叫法)= 一个模子(图形学、工业建模叫法) = 一个BATCH(3dtiles叫法)

然后,我向读者盛大先容要素表的简朴结构,由于要素表、批量表都是以 二进制 形式存储,以是领会每一种瓦片的二进制数据结构十分主要。

要素表的结构:JSON形貌信息+要素表数据体

要素表紧随在若干个字节的文件头后,它自己还可以再分为 二进制的JSON文本头 + 二进制的数据体

如下图所示:

dTiles

有迫在眉睫的读者希望更进一步领会要素表了,不要急,后续篇章一定睁开,例如若何读取要素表和其中的数据等。

接下来,是另一个数据表:批量表。

二、纪录属性数据:BatchTable,批量表

若是把批量表删除,那么3dTiles数据还能正常渲染。

是的,批量表就是所谓的模子属性表,批量表中每个属性数组的个数,就即是模子的个数,由于有多少个模子就对应多少个属性嘛!

(嘿嘿,实在也有破例的情形,我们到后续聊3dtiles数据规范的扩展能力时,再把这个坑填上,否则怎么说3dtiles很灵 [keng] 活 [die] 呢)

批量表相对对照自由,只要能与模子对得上号,想写啥就写啥。

批量表中的属性数据 ↔ 模子的关联

假定读者在阅读此 3dtiles 博客之前,已经对 gltf 数据规范有一定的领会。

gltf 数据有三层逻辑:Node ← Mesh ← Primitive。

其中,Primitive 即 gltf 数据规范中最小的图形单元,其极点界说由其下的 attributes 工具下 POSITION 属性来寻找接见器(Accessor),从而获取到数据。

{
    ...
    "meshes": [
       {
           "primitives": [
               {
                   "attributes": {
                       "POSITION": 0,
                       "TEXTURE_0": 2
                       ...
                   },
                   "indices": 1,
                   "mode": 4,
                   "material": 0
               }
           ]
       } 
    ],
    ...
}

获取到 POSITIONindices 对应的接见器、缓存视图、缓存文件后,即可获取 gltf 模子的所有极点,即几何模子,即三维要素的几何数据。

现在问题来了,若何将这些极点 “打” 上一个印记呢?就像检疫的猪肉一样,打个印记,说明猪是康健的。

Cesium团队在设计 3dtiles 规范的时刻充分利用了 gltf 规范的特点:开源。因此,每一个 primitive 被在其 attributes 中添加了分外的接见器:_BATCHID

"primitives": [
    {
        "attributes": {
            "POSITION": 0,
            "_BATCHID": 3,
            "TEXTURE_0": 2
            ...
        },
        "indices": 1,
        "mode": 4,
        "material": 0
    }
]

它与 POSITION 等没什么两样,同样会占用一部门数据。伶俐的读者应该能想到了,若是每一个极点都有一个所谓的 _BATCHID 对应,那么我随便给个点,我不就知道这个点的 _BATCHID,从而就知道这个点属于哪一个 BATCH 了吗?

翻翻前面的 “黑话”,GIS的读者更容易关联起来:

一个 BATCH (即三维要素)用自己的 BATCHID 与几何数据一一对应,属性数据也与这个 BATCHID 一一对应,由通报关系,那么三维的几何数据 (gltf) 也就能和 属性数据 (批量表) 一一对应了。

不外遗憾的是,并不是所有的瓦片都有 gltf 模子,例如pnts瓦片。

以是这个 几何 与 属性 两大数据若何关联,在之后的博文再具体问题具体分析。

关于这个模子和属性的关联,在b3dm瓦片的博文中要重点先容。

批量表的结构:JSON形貌信息+批量表数据本体

与 要素表 很像,批量表也是由: 二进制的JSON文本头 + 二进制的数据体 组成的。如下图所示:

dTiles

关于两个表的更深条理的数据内容,例如若何承载模子与模子之间的逻辑关系,若何纪录使用 Google 压缩算法的模子数据,那就是后续文章的内容了。

三、结语

本篇没有特定的数据作为说明,写得不太好,由于是第一次尝试用自己的语言表达这两大数据表,谋篇结构能力不太行,还请读者原谅。

这两个数据表真正的内容,还要等到接下来的四篇对瓦片二进制文件的重点先容中,才气细细讲完,本篇仅仅作为接下来四篇博客的 “总结”,也可以说是 “先容”。

附:CesiumJS API 若何查询瓦片的批量表

我们通常在Cesium中使用 点击 事宜,来获取一个 BATCH,即三维要素。在Cesium API中,这个被叫做:Cesium3DTileFeature。

那么,这个 Cesium3DTileFeature 就能接见到它自己的批量表中的属性数据:

const handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
handler.setInputAction(function(movement) {
    let feature = scene.pick(movement.endPosition);
    if (feature instanceof Cesium.Cesium3DTileFeature) {
        let propertyNames = feature.getPropertyNames();
        let length = propertyNames.length;
        for (var i = 0; i < length; ++i) {
            let propertyName = propertyNames[i];
            console.log(propertyName + ': ' + feature.getProperty(propertyName));
        }
    }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

用到了 Cesium3DTileFeature.getPropertyNames() 方式获取批量表中所有属性名,用了 Cesium3DTileFeature.getProperty(string Name) 来获取对应属性名的属性值。更多 API 见官方文档。

原创文章,作者:28x29新闻网,如若转载,请注明出处:https://www.28x29.com/archives/20376.html