全面了解3D Tiles

一、3D Tiles介绍

Cesium是一个虚拟地球三维平台,可视化范围上至太空中每一颗卫星,下至地面上每一幢建筑物。为了实现数字地球(Digital Earth vision)的蓝图,使连接世界上的地理空间数据成为可能,就要用到3D-Tiles。

3D-Tiles是一个用于流式(stream)传输大规模、异构的三维空间数据集的开放规范(open specification)。为了在Cesium地形和影像成流技术的基础上拓展功能,需要用3D Tiles成流三维数据,包括建筑物,树,点云和矢量数据。

简单点说,3D Tiles是在gltf的基础上,加入了分层LOD的结构后得到的产品,专门为大量地理3D数据流式传输和海量渲染而设计的一种格式,是webGL框架Cesium的专用格式。

主要有以下几个特点:

  1. Open

    3D Tiles是一个开放式规范,在Cesium中具有开源实现。

  2. Optimized for streaming and rendering(针对流和渲染进行了优化)

    3D Tiles主要是对大规模异构数据集的成流和渲染进行优化。3D Tiles的基础是一种空间数据结构,它支持层次结构细节级别(HLOD),只有可见的图块才会被流式传输。

  3. Interactive(交互式)

    3D Tiles支持交互式选择和样式,可以单独进行模型交互。比如鼠标悬停显示建筑物、使用ID查询数据。

  4. Styleable(设置样式)

    单个模型的元数据可以在运行时用于着色而无需编写代码,样式可以即时更改。

  5. Adaptable(适应性)

    为了满足灵活性的需求,树可以是任何具有空间相干性的空间数据结构,包括k-d树,四叉树(quadtrees),八叉树(octrees),格网(grids)。

  6. Flexible(灵活)

    传统的2D地图图块,当用户放大时,可见的地图图块将被更高分辨率的地图图块替换,这称为细化。

    而3D数据集则可以在子图块下载时呈现,这称为添加剂细化,具有更大的灵活性。

  7. Heterogeneous(异构的)

    3D数据集没有可以适合所有的尺寸,批量模型需要来自实例模型的不同表示,以及来自点云的不同表示等。

    3D Tiles通过启用自适应细分,灵活细化和可扩展的切片格式集支持异构数据集。

  8. Precise(精确)

    3D Tiles提供全精度几何,避免抖动伪像,无需存储双精度值。

  9. Temporal(时间动态)

    Cesium专为时间动态可视化设计,例如卫星、无人机。

3D Tiles数据集(又称为tileset)是由一系列tile组成的树状结构。每一个tile都有一个包围体完全包围它的内容(content)。树具有空间相关性,子tile的内容完全包含在父tile的包围体内。

一个tile代表一个要素或者一个要素集,如建筑物为代表的3D模型、点云中的点和向量数据集中的点。每个tile可以引用以下四种格式中的一种:

  • Batched3DModel
  • Instanced3DModel
  • PointCloud
  • Composite

tile的内容(tile格式的一个单独实例)是一个二进制块,具有特定于格式的组件,包括功能表(Feature Table)和批处理表(Batch Table)。

批处理3D模型和实例3D模型格式基于glTF建立,glTF是为有效传输3D内容而设计的开放规范。这些格式的图块内容在二进制主体中嵌入了glTF资源,其中包含模型几何和纹理信息。点云格式未嵌入glTF。

tile以树形结构组织,其中结合了详细层次结构(HLOD)的概念,可最佳呈现空间数据。每个tile都有一个包围体积(bounding volume)属性,一个对象定义了一个完全包围其内容的空间范围。树具有空间连贯性;子tile的内容完全在父级的包围体积之内。

树可以是任何具有空间相干性的空间数据结构,包括k-d树,四叉树(quadtrees),八叉树(octrees),格网(grids)

二、3D Tiles的文件规范和单位

1. 扩展名

  • Tileset使用.json扩展名;
  • Tile的内容使用上述的四种类型(b3dm,i3dm,pnts,cmpt等);
  • 样式文件也使用.json扩展名

2. JSON的编码规范

  • JSON必须使用没有BOM的UTF-8编码。

  • 所有字符串(属性名称,枚举)仅使用ASCII字符集,并且必须以纯文本形式编写。

  • JSON对象中的名称(键)必须唯一,即不允许重复的键。

3. URIs

  • 3DTiles中的tiels使用URIs来指向外部引用,也可以将资源嵌入JSON的数据,和glTF引用二进制文件或者直接包含数据在JSON中的方式一样。

4. 单位

  • 所有线性距离的单位是米。

  • 所有角度均以弧度为单位

5. 坐标系

  • 3D Tiles使用右手笛卡尔坐标系,整体坐标系为WGS 84坐标系,但是WGS 84坐标系并不是必须的,也可以只有自己局部坐标系,不定义全局坐标系。
  • 区域边界体积使用地理坐标系(纬度,经度,高度),特别是EPSG 4979来指定边界

三、格式介绍

1. Geometric error(几何误差)

根节点是源几何图形的最简化版本,是最粗糙的模型,其几何误差最大。然后,每个连续级别的子级将具有比其父级低的几何误差,而叶子节点的几何误差为0或接近0。

在不同视距、不同视角、不同分辨率下,几何误差都是不同的,几何误差是根据度量标准制定的。通常,较高的几何误差表示将更快的优化tile,并且将更快地加载和渲染子tile。

2. Refinement(细化方式)

细化确定了较低分辨率的父tile被选择渲染的子级时渲染的过程。 允许的细化类型为替换(“ REPLACE”)和添加剂(“ ADD”)。

如果tile具有替换细化,则将渲染子tile代替父tile,即不再渲染父tile,即REPLACE是在Tile从低Lod到高Lod时,将低Lod的数据直接移除,用高Lod的数据替换。 如果tile具有添加剂细化,则除了父tile之外,还将渲染子代。

ADD方式是一种非常好的方式,是一种增量的LOD策略,能减少数据的传输

3. Bounding volumes(包围体)

简单点理解是能将三维对象完全包住的最小的几何体。3D Tiles有三种包围体:

  • Bounding box:box属性是一个由12个数字组成的数组。 前三个元素定义框中心的x,y和z值。 接下来的三组元素分别定义x,y,z轴方向和半轴长度

  • Bounding region:region属性是一个由六个数字组成的数组,这些数字用纬度,经度和高度坐标定义了地理区域,其坐标顺序为[西,南,东,北,最小高度,最大高度]。 纬度和经度在EPSG 4979中定义的WGS 84基准中,以弧度表示。 高度在WGS 84椭圆形上方(或下方)以米为单位。其每条边都和坐标轴平行。

  • Bounding sphere:sphere属性是由四个数字组成的数组,这些数字定义了一个最小包围球。 前三个元素定义了在右手3轴(x,y,z)直角坐标系中x轴的x,y和z值,其中z轴位于上方。 最后一个元素以米为单位定义半径。

    全面了解3D Tiles_第1张图片

    蓝色是region包围框,每条边都和坐标轴平行;红色的是box包围框,是能包围三维对象的最小几何体。

4. Viewer request volume(观察者请求体)

这个是对每个tile何时可见进行控制,它也包含了上面的box,region,sphere三种类型。当观察点在viewerRequestVolume值内的时候,tile才会显示,这样更有利于精确控制tile的可见性。

5. Transform(位置变换矩阵)

> Tile Transform(tile 的变换矩阵)

为了支持局部坐标系,给每个tile都提供了一个可选的transform属性。

transform属性是一个4x4变换矩阵,按列优先顺序存储,可从tile的本地坐标系转换到父节点的坐标系中,或者在根节点的情况下从tileset的坐标系转换.

  1. tile.content:这个字段是tile数据的存放位置字段,tranform矩阵会应用到content中的每个feature的位置坐标、法向量。在进行缩放旋转变换时,法向量才需要变换,通过左上角3×3矩阵对法向量进行变换。
  2. content.boundingVolume:除非定义了content.boundingVolume.region,它在EPSG:4979坐标中明确表示。
  3. tile.boundingVolume:除非定义了tile.boundingVolume.region,它在EPSG:4979坐标中明确表示。
  4. tile.viewerRequestVolume:和上面一样,region除外。

对tile的变化是从上自下多个变换的一个级联变换的过程,因为LOD是一个树的结构,所以叶子节点的变换就是从根节点到下的一个矩阵级联变换的过程。

> glTF transforms

  1. 批处理3D模型和实例3D模型,这两种类型的模型都是通过嵌入glTF模型来实现,而glTF模型本身就有矩阵变换,glTF定义了自己的节点层次结构并使用y向上坐标系,所以tile的transform是应用在glTF的变换之后的,在应用glTF变换之后,应该对glTF模型绕着x轴旋转90°。
  2. 针对模型的变换顺序为:先根据glTF规范应用glTF节点层次结构转换;接下来,在运行时,glTF使用矩阵从y向上转换为z向上;Tiles特定格式的转换,包括批处理3D模型和实例3D模型;最后是Tile的transform变换。

6. Content(内容)

content属性用来指向Tile实际渲染的内容。content.uri指向渲染内容的定位符,可能指向一个二进制块的位置,也可能指向另一个Tileset。content.uri不需要文件扩展名。内容的tile格式可以通过其标题中的magic字段标识,如果内容为JSON,则可以将其标识为外部tileset.

content.boundingVolume属性用来所指向描述渲染内容的包围体,其与tile.boundingVolume的区别是,content属性只是渲染内容的包围体,而tile需要将子节点包围在里面。

红色的是tile的包围体,蓝色的是content的包围体。

7. Children(子节点)

因为3DTiles是以树结构组织的,每个Tile还有子节点,就存储在children数组中,数组中每个元素仍然是Tile,这样就形成了一种递归定义的树的结构,叶子节点的children的元素个数为0。需要注意是,子节点的boudingVolume肯定是被父节点的boudingVolume包围着的,子节点的geometricError肯定是要比父节点小的,因为越接近叶子节点,模型越精细,所以其与原模型的几何误差越小。

一个tileJSON对象由以下属性组成:

全面了解3D Tiles_第2张图片

每个属性的作用总结为下:

  1. boudingVolume:boudingVolume定义了Tile的最小包围体,其作用是在渲染的时候,根据包围体确定哪个Tile需要渲染的。其有region,box,sphere三种形式。
  2. geometricError:geometricError是一个非负数,以米为单位定义了不同LOD层级(或者说Tile层级)的几何误差,通过几何误差来计算屏幕误差,从而确定什么时候应该用哪个LOD层级的Tile。
  3. viewerRequestVolume:viewerRequestVolume用一个和boudingVolume相同的类型定义的范围,只有当观察者处于其定义的范围内时,Tile才显示,从而精细控制了tile的显示与否。
  4. refine:refine属性定义了tile切换的方式,有替换和添加两种模式。该属性在根节点的Tile中是必须的,子节点中非必须,子节点中该属性缺失时,继承父节点的该属性。
  5. content:此属性指向真正的渲染数据。
  6. children:定义子节点的对象数组。

四、Tileset JSON

1. TilesetJSON文件

3D Tiles使用一个或者多个tileset的json文件来组成整个场景,这些json文件不需要遵循特定的命名规范。

{
  "asset" : {
    "version": "1.0",
    "tilesetVersion": "e575c6f1-a45b-420a-b172-6449fa6e0a59",
  },
  "properties": {
    "Height": {
      "minimum": 1,
      "maximum": 241.6
    }
  },
  "geometricError": 494.50961650991815,
  "root": {
    "boundingVolume": {
      "region": [
        -0.0005682966577418737,
        0.8987233516605286,
        0.00011646582098558159,
        0.8990603398325034,
        0,
        241.6
      ]
    },
    "geometricError": 268.37878244706053,
    "refine": "ADD",
    "content": {
      "uri": "0/0/0.b3dm",
      "boundingVolume": {
        "region": [
          -0.0004001690908972599,
          0.8988700116775743,
          0.00010096729722787196,
          0.8989625664878067,
          0,
          241.6
        ]
      }
    },
    "children": [..]
  }
}

这是一个tileset的JSON文件,主要有四个属性:asset、properties、geometricError、root。

  1. asset
    asset是一个对象,其中包含有关整个tileset的元数据。 asset.version属性是一个字符串,用于定义3D Tiles版本,该版本指定tileet的JSON模式和基本的tile格式集。 tileetVersion属性是一个可选字符串,用于定义特定于应用程序的tileset版本。
  1. properties
    该属性中包含tileset中每个功能属性的对象。此tileset JSON代码段适用于3D建筑物,因此每个tile均具有建筑物模型,并且每个建筑物模型均具有Height属性。属性中每个对象的名称与每个功能属性的名称匹配,并且其值定义其最小和最大数值,这对于创建用于样式的色带很有用。
  1. geometricError
    geometricError是一个非负数,用于定义未渲染图块时的误差(以米为单位),用于确定是否渲染tile的元数据。tile也有geometricError这个属性,不同的是,tileSet的geometricError是根据屏幕误差来控制tileSet中的root是否渲染。而tile中的geometricError则是用来控制tile中的children是否渲染。
  1. root
    tileet的geometricError是未渲染整个tileset时的误差; root.geometricError是仅渲染根节点时的误差。

2. 外部tileset

要创建一棵树,tile的content.uri可以指向外部tileset(另一个图块JSON文件的uri)。这样可以把不同的tileset分开存储,比如一个国家的模型,可以将每个城市存储在一个tileset 中,然后用一个具有全局的tileset的JSON文件将整个国家组织起来。

当一个tile指向一个外部的tileset时,必需遵循一下原则:

  1. 不能有子集; tile.children必须未定义或为空数组。

  2. 不能用于创建循环,例如有set1、set2、set3三个tileSet,set1指向set2,set2指向set3,然后set3又指向set1,这就形成一个引用环,这种情况是不允许的。

  3. 利用transform变换的时候,将会应用自己的transform变换和root的transform变换。 例如,在以下引用中,针对T3的计算转换为[T0] [T1] [T2] [T3]。

全面了解3D Tiles_第3张图片

3. 包围体的空间连贯性

如上所述,树具有空间连贯性。每个tile都有一个完全包围其内容的包围体,子节点包围体内的模型内容(是模型内容而不是子节点的包围体)应完全被父节点的包围体所包围,但这并意味着children的包围体要完全被父节点的包围体包围。例如:

全面了解3D Tiles_第4张图片

四个子节点的包围体。子对象的内容完全在父对象的包围体内,但子对象的包围体不在此范围内。

4. 空间数据结构

3DTiles是一种利用HLOD来组织场景的,tileSet内的数据结构是一个树形的结构(在tileSet的JSON文件中,通过root和children来递归的定义),可以通过不同类型的空间数据结构进行组织。

4.1 四叉树划分

当每个Tile具有四个统一细分的子级(例如,使用中心纬度和经度)时,就会创建四叉树,类似于典型的2D地理空间切片方案。空的子tile可以省略。

3D Tiles支持非规则的四叉树,例如用非均匀细分和紧密的包围体来划分。
全面了解3D Tiles_第5张图片 这是一个实例,注意左下角,其中包围体不包括左侧的水,此处没有建筑物:

3DTiles同样支持松散四叉树,这种情况下,子节点之间可能会出现压盖,但是包围体的连贯性还是需要保持(即父节点的包围体必须要将子节点的数据包含在里面)。使用松散四叉树分割,就可以割裂建筑物。松散四叉树的示意图如下:

全面了解3D Tiles_第6张图片

松散四叉树的实际应用如下图所示,可以看到中间有两个包围体是有压盖的。这样与包围体相交的两个建筑物就不需要分割开了。

4.2 K-d树划分

当每个节点有两个子节点时,会创建k-d树,这两个子节点由平行于x、y或z轴(或纬度、经度、高度)的分割平面分隔开。分割轴通常随着树的层级增加而循环旋转,并且分割平面可以使用中间分割、表面积分割或其他方法来拆分。

树的每个节点代表一个超平面,该超平面垂直于当前划分维度的坐标轴,并在该维度上将空间划分为两部分,一部分在其左子树,另一部分在其右子树;即若当前节点的划分维度为i,其左子树上所有点在i维的值均小于当前值,右子树上所有点在i维的值均大于等于当前值,本定义对其任意子节点均成立。一个k=2的k-d树如下所示:

全面了解3D Tiles_第7张图片 请注意,k-d树不像典型的2D地理空间切片方案那样具有统一的细分,因此可以为稀疏和非均匀分布的数据集创建更加平衡的树,每个tile有n个孩子,而不是每个tile有2个孩子。

4.3 八叉树划分

八叉树通过使用三个正交拆分平面将tile细分为八个子级来扩展四叉树。像四叉树一样,3D Tiles允许对八叉树进行变化,例如不均匀的细分,紧密的包围体和重叠的子代。如下为八叉图分割示例:

全面了解3D Tiles_第8张图片

4.4 网格划分

3DTiles支持任意数量的子节点来实现均匀和非均匀重叠的网格。 例如,以下是剑桥的非均匀重叠网格的俯视图:

总体来说,3D Tiles就是定义了一种用递归构造的树的数据结构,树怎么形成可以由用户自定义。其次,3D Tiles也给每个tile定义了诸如几何误差等的属性,用于控制tile的显示与否。

3DTiles规范原文点这里!

你可能感兴趣的:(学习问题记录)