Mars3D开发基础:3DTiles三维模型

2,908 阅读10分钟

Mars3D开发基础系列文档导航

  1. 三维场景 Map
  2. 地图控件
  3. 地图图层 Layer
  4. 加载DEM地形
  5. 栅格瓦片图层
  6. 坐标系及坐标变换
  7. 相机Camera及视角控制
  8. 时钟Clock及时序控制
  9. 事件机制
  10. 矢量图层Layer
  11. 矢量数据Graphic
  12. Property属性机制
  13. Material材质
  14. glTF小模型
  15. 3DTiles三维模型
  16. 场景特效
  17. 管理及分析功能

上一节我们介绍了glTF的主要数据结构以及Mars3D是如何对其进行加载的,这一节我们来介绍一下glTF的升级版3D Tiles ,也是目前 Mars3D 在加载海量三维模型数据方面必须采用的一种数据格式。

image.png

1. 3DTiles介绍

2016年,Cesium 团队借鉴传统2DGIS的地图规范:WMTS,借鉴图形学中的层次细节模型,打造出大规模的三维数据标准:3d-Tiles,中文译名:三维瓦片。

它在模型上利用了 gltf 渲染快的特点,对大规模的三维数据进行组织,包括层次细节模型、模型的属性数据、模型的层级数据等。

3D Tiles 是在glTF的基础上,加入了分层LOD的概念(可以把3D Tiles简单地理解为带有 LOD 的 glTF ),专门为流式传输和渲染海量 3D 地理空间数据而设计的,例如倾斜摄影、3D 建筑、BIM/CAD、实例化要素集和点云。它定义了一种数据分层结构和一组切片格式,用于渲染数据内容。3D Tiles 没有为数据的可视化定义明确的规则,客户可以按照自己合适的方式来可视化 3D 空间数据。同时,3D Tiles 也是 OGC 标准规范成员之一,可用于在台式机、Web端和移动应用程序中实现与海量异构3D地理空间数据的共享、可视化、融合以及交互功能。

2. 3dTiles数据示例及其加载

数据处理相关的,可以参看:各类三维模型转为3DTiles格式

2.1 3dTiles数据示例

首先,我从一个简单的3D Tiles数据示例说起,请看下面目录:

image.png

上图是一份 3dTiles数据集在文件夹内的样子,层层打开可得以下特点:

  • 入口文件是tileset.json
  • 各级瓦片用文件夹来组织(类似套娃),目录中有零散的*.json文件
  • 叶子节点有*.b3dm、*.i3dm等格式

对这些数据的结构和详细介绍,我们下一节再详细解说,第一步,我们先学会怎么加载使用这个模型。

2.2 在平台中加载模型

平台内加载3dtiles是使用 TilesetLayer类

3dTiles至少有一个 tileset.json 文件,作为整个数据集的入口,在代码层面,我们拿到这个主瓦片集JSON 文件(tileset.json)的url地址即可使用加载三维模型了。 如: data.mars3d.cn/3dtiles/qx-…

当我们拿到这个模型服务地址后:

  • (1)浏览器输入模型url地址验证下是否可以正常访问。
  • (2)打开模型参数调试编辑页面,在这个页面调试的模型URL输入框内输入模型url地址,并单击加载模型按钮。

image.png

  • (3)可以勾选深度检测来方便测试和调试模型高度

image.png

  • (4)如果是人工模型,可以勾选“鼠标拖拽编辑”来手动拖拽模型的位置与地图上匹配。

  • (5)在该页面调整好所有参数后,单击“保存参数”按钮,保存的参数json,会自动下载一个json文件。

image.png

  • (6) 如果模型是初始化就加载的,可以打开项目的config.json文件,拷贝刚下载的json到config.json文件的layers参数中即可。
layers:[
  {
    "name": "模型名称",
    "type": "3dtiles",
    "url": "http://data.mars3d.cn/3dtiles/qx-dyt/tileset.json",
    "maximumScreenSpaceError": 1,
    "maximumMemoryUsage": 1024,
    "position": {"alt": 452.9 },
    "center": { "lat": 34.216894,  "lng": 108.959834, "alt": 591, "heading": 4,"pitch": -37 }, 
    "show": true
  }
]
  • (7)如果代码中直接使用TilesetLayer类构造三维模型,可以将json中的参数拷贝到类参数中。
var tiles3dLayer = new mars3d.layer.TilesetLayer({
  url: 'http://data.mars3d.cn/3dtiles/qx-simiao/tileset.json',
  maximumScreenSpaceError: 16,
  maximumMemoryUsage: 1024,
  position: { alt: 452.9 },
  center: { lat: 34.216894,  lng: 108.959834, alt: 591, heading: 4,pitch: -37 }, 
  flyTo: true,
})
map.addLayer(tiles3dLayer)

运行效果

image.png

3. 3D Tiles 数据结构

3dTiles 是一种规范(要区分规范和实现的概念),在规范的指导下,各种资源文件可以是独立存在于硬盘中的目录、文件,也可以以二进制形式写入数据库中。

3dTiles还有一个特点:那就是不记录模型数据(指三维模型的顶点、贴图材质、法线、颜色等信息),只记录各级“Tile”的逻辑关系(指LOD是如何组织的),以及“Tile”自己的属性信息(如房子的名称、建设年限、面积等)。

image.png

3.1 3D Tiles支持的模型

  • 城市建筑白膜:在拥有如shp、kml等格式的建筑物二维面边界坐标数据,和高度或楼层数属性信息,再通过工具转换为三维立体的白膜建筑物3DTiles模型。
  • 倾斜摄影:一般是无人机拍摄,拍摄的数据通过建模工具ContextCapture Cente等建模软件可以直接导出3DTiles格式。也可以通过osgb通用格式转3DTiles格式后在平台中使用。
  • 点云数据:一般是激光扫描后生产的数据,有las、pts、ply等格式。
  • 人工建模:数据来源于3dmax、Maya等建模软件建模,建好的三维模型导出为dae和obj数据后,再转换为3DTiles数据格式。
  • BIM模型:数据来源于专业的BIM软件,常见的有rvt和dgn格式。

:::tip 这些数据的原始格式都需要转换为3dtiles格式后,才能在平台加载使用。 :::

3.2 LOD树结构

通过上面介绍,3dTiles数据的入口文件是一个名叫tileset.json的文件,在这个json文件中root属性下通过children属性来关联子级节点*.json ,这样一层层关联到叶子节点(如*.b3dm等格式)。

image.png 树结构对于三维空间数据的组织有很大的优势。3dTiles在空间上允许数据集使用如下几种树结构:

  • 四叉树:允许使用传统的均匀四叉树,也允许使用松散四叉树等变种(例如,允许子节点,即子瓦片允许存在空间范围重叠),常用于 建筑物(存在不可能严格切分的特点)。
  • 八叉树: 四叉树对在高度上不太好切分的数据比较适合,而如果追求极致的空间分割和分级(例如点云数据),那么八叉树更合适。八叉树也允许使用各种变种。
  • KD树:
  • 格网结构:允许瓦片存在多个子瓦片,通常出现在倾斜摄影数据上,但是这会导致网络请求过多的问题。

八叉树

image.png

3.3 构成3dtiles的成员:Tile瓦片

瓦片对象会引用一个二进制的瓦片数据文件,目前这些文件有以下类型:

文件后缀名名称英文名称对应实际数据
b3dm批量三维模型Batch 3D Model传统三维建模数据、BIM数据、倾斜摄影数据
i3dm实例三维模型Instance 3D Model一个模型多次渲染的数据,灯塔、树木、椅子等
pnts点云PointCloud点云数据
cmpt复合模型Component前三种数据的复合(允许一个cmpt文件内嵌多个其他类型的瓦片)

image.png

上面表格中的b3dm 和 i3dm 格式是基于 glTF(一种专为高效传输 3D 内容而设计的开放性规范)构建的,它们的瓦片内容在二进制体中嵌入了 glTF 资源,包含模型的几何和纹理信息,而 pnts 格式却没有嵌入 glTF 资源。

3.4 单个Tile瓦片的内部构成

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

瓦片引用的二进制文件有4种,即:b3dm、i3dm、pnts、cmpt。 除去cmpt这个复合类型不谈,前三种的瓦片二进制数据文件的大致字节布局结构见下图:

image.png

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

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

(1)FeatureTable 要素表: 记录渲染相关的数据

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

(在房屋级别来看,房子并不是单体,构造它的门、门把、窗户、屋顶、墙等才是模型单体;但是在模型壳子的普通表面建模数据中,房子就是一个简单的模型)

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

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

要素表的结构:JSON描述信息+要素表数据体

image.png

(2)BatchTable 批量表: 记录属性数据

批量表就是所谓的模型属性表,批量表中每个属性数组的个数,就等于模型的个数,因为有多少个模型就对应多少个属性嘛!如果把批量表删除,那么3dTiles数据还能正常渲染。

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

image.png

(3)四类类型对应的具体结构

b3dm:

image.png

i3dm:与 b3dm 一致,文件头多了个gltfFormat属性。

image.png

pnts不存在gltf模型,故结构如下:

image.png

cmpt:这是前三种的一种更灵活的组织,允许一个瓦片使用 cmpt 形式,组合多种瓦片,cmpt瓦片可以内嵌任意个、任意类型的瓦片,b3dm、i3dm、pnts均可。

image.png

(4)代码中如何查询瓦片的批量表

我们通常在平台中使用 点击 事件,来获取一个 BATCH,即三维要素。在API中,这个被叫做:Cesium3DTileFeature。那么,这个 Cesium3DTileFeature 就能访问到它自己的批量表中的属性数据:


map.on(mars3d.EventType.click, function(event) {
  let feature = event.pickedObject;
  //下面只是演示解释底层实现,在平台中直接通过event.graphic.attr可以获取属性
  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));
      }
  }
});

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

获取更多关于3D Tiles 的格式信息可访问:

官方github 官方格式说明 秋意正寒博客详解

image.png

image.png

image.png

image.png