1 详解 Cesium .terrain
格式
在 3D 地理信息系统(GIS)和虚拟地球应用中,地形数据的处理至关重要。Cesium 作为一个强大的开源 JavaScript 库,支持多种地形数据格式,其中 .terrain
格式(量化网格)是最常用的格式之一。本文将深入解析 .terrain
格式,探讨其特点、工作原理及如何在 Cesium 中使用该格式。
生成地形工具
TilesBuilder: TilesBuilder提供一个高效、兼容、优化的数据转换工具,一站式完成数据转换、数据发布、数据预览操作。
2 什么是 .terrain
格式?
.terrain
是一种专门为 Cesium 设计的地形数据格式,基于 量化网格(Quantized Mesh)技术。该格式通过将地形数据进行压缩和量化处理,大大减少了地形数据的存储空间,提升了加载和渲染性能。Cesium 使用这种格式来处理大型地形数据集,尤其是需要高效流式加载的地形切片(Tiles)。
3 量化网格(Quantized Mesh)简介
量化网格是一种高效的地形数据存储方式,它将地形高度数据(如 DEM 或数字高程模型)进行空间分割,将高程值通过量化压缩到较小的整数范围。这样做的好处是,减少了数据存储的大小,提升了处理速度。量化网格利用层次化的切片结构,使得系统可以根据用户的视图动态加载需要的地形部分。
3.1.terrain
格式的特点
-
高效的存储方式
.terrain
格式通过量化和压缩技术将地形数据存储为二进制文件,使得大规模的地形数据能够高效地存储和传输。相比传统的地形数据格式(如高度图),.terrain
格式的文件体积较小,加载速度较快。 -
层次化切片结构
.terrain
格式的数据被分成多个切片(tiles),每个切片代表地球表面某个区域的地形数据。每个切片的数据进一步被细分为更小的网格,每个网格包含多个地形点。切片的层次结构确保了在不同的缩放级别下,Cesium 只加载与视图相关的切片,进一步提高了性能。 -
适用于大规模数据集
量化网格支持大范围、高精度的地形数据,例如,全球范围内的地形数据或某个大区域的详细地形模型。由于数据被切分为多个小块,它能够在不同的分辨率下进行渲染,适应不同级别的视图需求。 -
支持动态加载和流式传输
.terrain
格式支持按需加载数据。这意味着当用户缩放或平移地图时,Cesium 会根据视图位置和缩放级别动态加载相应的地形切片,无需一次性加载整个地形数据集,从而减少了初始加载时间和内存占用。
3.2.terrain
格式的工作原理
- 地形数据的切片
.terrain
格式通过将大范围的地形数据分割为许多小块(即切片),每个切片包含一个固定区域的地形数据。每个切片都有不同的细节级别(LOD,Level of Detail),当用户视角距离地形较近时,Cesium 会加载更高分辨率的切片;当视角较远时,加载较低分辨率的切片。 - 量化和压缩
在每个切片内,地形高度值(如DEM数据)通过量化压缩为整数值,减小了数据的存储和传输开销。量化过程通常会使地形精度有所降低,但这种精度损失在大多数应用场景下是可以接受的,尤其是在大范围的地形渲染中,地形细节不会因为量化而明显丧失。 - 切片的传输和渲染
Cesium 在客户端通过TerrainProvider
来请求和加载.terrain
文件中的切片数据。当用户浏览地图时,Cesium 会根据视图范围请求适当的切片进行渲染。随着用户视角的变化,Cesium 会动态加载新的切片,并卸载不再需要的切片,从而实现高效的地形加载。
4 Cesium .terrain
格式的二进制文件结构
Cesium 的 .terrain
格式是基于 量化网格(Quantized Mesh) 技术的,采用了一种高效的二进制文件结构来存储地形数据。这个结构通过将高程数据进行量化和压缩,使得数据体积大大缩小,同时确保渲染性能。
了解 .terrain
文件的二进制结构对于深度定制 Cesium 地形加载和理解底层实现是非常重要的。以下将详细解析 .terrain
格式的二进制文件结构。
4.1 .terrain
文件的整体结构
Cesium .terrain
文件的结构通常包括以下几个主要部分:
- 头部(Header)
- 切片信息(Tile Data)
- 顶点数据(Vertex Data)
- 索引数据(Index Data)
- 其他附加数据(如颜色、纹理、属性数据等)
4.1.1 头部(Header)
头部包含文件的基本信息,如瓦片的中心位置、海拔范围、包围球信息以及地平线遮挡点的坐标。
头部结构
struct QuantizedMeshHeader {
double CenterX; // 瓦片的中心点在地心固定坐标系中的 X 坐标。
double CenterY; // 瓦片的中心点在地心固定坐标系中的 Y 坐标。
double CenterZ; // 瓦片的中心点在地心固定坐标系中的 Z 坐标。
float MinimumHeight; // 瓦片区域内的最小高度。
float MaximumHeight; // 瓦片区域内的最大高度。
double BoundingSphereCenterX; // 瓦片的包围球中心点的 X 坐标。
double BoundingSphereCenterY; // 瓦片的包围球中心点的 Y 坐标。
double BoundingSphereCenterZ; // 瓦片的包围球中心点的 Z 坐标。
double BoundingSphereRadius; // 包围球的半径(单位:米)。
double HorizonOcclusionPointX; // 地平线遮挡点的 X 坐标(地心固定坐标系)。
double HorizonOcclusionPointY; // 地平线遮挡点的 Y 坐标。
double HorizonOcclusionPointZ; // 地平线遮挡点的 Z 坐标。
};
4.1.2 顶点数据(Vertex Data)
每个地形切片的顶点数据包含了地形的高度信息。Cesium 将地形分成多个网格,每个网格包含一个高度值。为了减少文件大小,Cesium 使用量化和压缩方法对高度数据进行处理。
顶点数据结构
-
顶点数据包含描述瓦片三角网格中顶点位置的坐标和高度信息。顶点的坐标和高度值通过增量编码和 ZigZag 编码方式进行存储,以减少所需存储空间。
顶点数据的结构如下:
struct VertexData { unsigned int vertexCount; // 顶点数量。 unsigned short u[vertexCount]; // 水平方向坐标(经度)。 unsigned short v[vertexCount]; // 垂直方向坐标(纬度)。 unsigned short height[vertexCount]; // 顶点高度。 };
u
、v
和height
数组分别表示顶点的经度、纬度和高度。- 这些值使用 ZigZag 编码进行存储,以便高效表示小整数。
解码这些数组的 JavaScript 示例代码如下:
var u = 0, v = 0, height = 0; function zigZagDecode(value) { return (value >> 1) ^ (-(value & 1)); } for (i = 0; i < vertexCount; ++i) { u += zigZagDecode(uBuffer[i]); v += zigZagDecode(vBuffer[i]); height += zigZagDecode(heightBuffer[i]); uBuffer[i] = u; vBuffer[i] = v; heightBuffer[i] = height; }
每个解码后的
u
和v
值表示瓦片相对于边缘的水平和垂直位置,而height
则表示该顶点的海拔。
4.1.3 索引数据(Index Data)
索引数据用于表示如何连接地形网格的顶点。Cesium 将每个切片的顶点数据分成三角形网格,这些三角形通过索引来定义。
索引数据结构
- 索引数据定义了顶点如何连接成三角形。每个三角形由三个顶点组成,顶点通过索引连接。若瓦片包含超过 65536 个顶点,则使用
IndexData32
结构编码索引数据,否则使用IndexData16
结构。
示例索引数据结构:
struct IndexData16 {
unsigned int triangleCount; // 三角形数量。
unsigned short indices[triangleCount * 3]; // 构成三角形的顶点索引。
};
struct IndexData32 {
unsigned int triangleCount; // 三角形数量。
unsigned int indices[triangleCount * 3]; // 构成三角形的顶点索引。
};
4.1.4 边缘索引(Edge Indices)
边缘索引用于描述瓦片边缘上的顶点,这些顶点对邻接瓦片的无缝连接非常重要。边缘索引分为两种类型:
- 16 位边缘索引:适用于顶点数量小于 65536 的瓦片。
- 32 位边缘索引:适用于顶点数量超过 65536 的瓦片。
struct EdgeIndices16 {
unsigned int westVertexCount;
unsigned short westIndices[westVertexCount];
unsigned int southVertexCount;
unsigned short southIndices[southVertexCount];
unsigned int eastVertexCount;
unsigned short eastIndices[eastVertexCount];
unsigned int northVertexCount;
unsigned short northIndices[northVertexCount];
};
struct EdgeIndices32 {
unsigned int westVertexCount;
unsigned int westIndices[westVertexCount];
unsigned int southVertexCount;
unsigned int southIndices[southVertexCount];
unsigned int eastVertexCount;
unsigned int eastIndices[eastVertexCount];
unsigned int northVertexCount;
unsigned int northIndices[northVertexCount];
};
这些边缘索引能够帮助渲染过程中处理瓦片之间的接缝,尤其是在拼接不同层次的瓦片时,避免出现可见的缝隙。
4.1.5 可选扩展(Optional Extensions)
Quantized Mesh 格式支持扩展,允许为地形数据增加额外的信息,例如每个顶点的法线、海岸线水域数据、或瓦片的元数据。扩展数据以特定的结构格式追加到瓦片文件的末尾:
- 扩展类型包括:
- Oct-Encoded Per-Vertex Normals:每个顶点的法线,用 16 位编码表示。
- Water Mask:用于表示瓦片中的水域(0 表示陆地,255 表示水域)。
- Metadata:附加的 JSON 元数据,描述瓦片的其他信息
struct ExtensionHeader {
unsigned char extensionId; // 扩展的唯一标识符。
unsigned int extensionLength; // 扩展数据的长度。
};
4.2 二进制结构总结
以下是 .terrain
文件典型二进制结构的详细,包含字段和对应的字节数:
结构 | 字段 | 类型 | 字节数 | 说明 |
---|---|---|---|---|
1. 头部信息 (QuantizedMeshHeader) | CenterX | double | 8 bytes | 瓦片中心的地心固定坐标系 X 坐标 |
CenterY | double | 8 bytes | 瓦片中心的地心固定坐标系 Y 坐标 | |
CenterZ | double | 8 bytes | 瓦片中心的地心固定坐标系 Z 坐标 | |
MinimumHeight | float | 4 bytes | 瓦片区域的最小高度 | |
MaximumHeight | float | 4 bytes | 瓦片区域的最大高度 | |
BoundingSphereCenterX | double | 8 bytes | 包围球中心的 X 坐标 | |
BoundingSphereCenterY | double | 8 bytes | 包围球中心的 Y 坐标 | |
BoundingSphereCenterZ | double | 8 bytes | 包围球中心的 Z 坐标 | |
BoundingSphereRadius | double | 8 bytes | 包围球的半径 | |
HorizonOcclusionPointX | double | 8 bytes | 地平线遮挡点的 X 坐标 | |
HorizonOcclusionPointY | double | 8 bytes | 地平线遮挡点的 Y 坐标 | |
HorizonOcclusionPointZ | double | 8 bytes | 地平线遮挡点的 Z 坐标 | |
2. 顶点数据 (VertexData) | vertexCount | unsigned int | 4 bytes | 顶点数量 |
u[vertexCount] | unsigned short[] | 2 bytes/值 | 顶点的水平坐标(经度),每个顶点 2 字节 | |
v[vertexCount] | unsigned short[] | 2 bytes/值 | 顶点的垂直坐标(纬度),每个顶点 2 字节 | |
height[vertexCount] | unsigned short[] | 2 bytes/值 | 顶点的高度,每个顶点 2 字节 | |
3. 索引数据 (Index Data) | triangleCount | unsigned int | 4 bytes | 三角形的数量 |
indices[triangleCount * 3] | unsigned short[] (16位) | 2 bytes/索引 | 16 位的三角形顶点索引,每个索引 2 字节 | |
indices[triangleCount * 3] | unsigned int[] (32位) | 4 bytes/索引 | 32 位的三角形顶点索引,每个索引 4 字节 | |
4. 边缘索引 (Edge Indices) | westVertexCount | unsigned int | 4 bytes | 西边顶点数量 |
westIndices[westVertexCount] | unsigned short[] (16位) | 2 bytes/索引 | 西边顶点索引,每个索引 2 字节 | |
southVertexCount | unsigned int | 4 bytes | 南边顶点数量 | |
southIndices[southVertexCount] | unsigned short[] (16位) | 2 bytes/索引 | 南边顶点索引,每个索引 2 字节 | |
eastVertexCount | unsigned int | 4 bytes | 东边顶点数量 | |
eastIndices[eastVertexCount] | unsigned short[] (16位) | 2 bytes/索引 | 东边顶点索引,每个索引 2 字节 | |
northVertexCount | unsigned int | 4 bytes | 北边顶点数量 | |
northIndices[northVertexCount] | unsigned short[] (16位) | 2 bytes/索引 | 北边顶点索引,每个索引 2 字节 | |
5. 扩展数据 (Extension Data) | extensionId | unsigned char | 1 byte | 扩展标识符 |
extensionLength | unsigned int | 4 bytes | 扩展数据长度 | |
扩展数据示例 | OctEncodedVertexNormals | unsigned char[] | 2 bytes/值 | 每个顶点的法线(16 位 xy 编码),每个法线 2 字节 |
WaterMask | unsigned char[256 * 256] | 256 * 256 bytes | 水域掩模数据,0 为陆地,255 为水域,256x256 像素,每个像素 1 字节 | |
Metadata | unsigned int, char[] | 4 bytes + jsonLength | 存储元数据的 JSON 数据,JSON 长度为 jsonLength ,4 字节用于存储 JSON 长度,后跟 JSON 数据 |
5.如何在 Cesium 中使用 .terrain
格式
在 Cesium 中,.terrain
格式的地形数据通常通过 CesiumTerrainProvider
来加载。这个提供者可以连接到远程的 Cesium 服务器或加载本地的 .terrain
文件。以下是如何在 Cesium 中加载 .terrain
数据的示例代码:
// 创建Cesium Viewer
const viewer = new Cesium.Viewer('cesiumContainer', {
terrainProvider: Cesium.createWorldTerrain() // 使用Cesium官方的地形服务
});
// 设置本地地形数据
const terrainProvider = new Cesium.CesiumTerrainProvider({
url : './path/to/terrain' // .terrain文件所在的路径
});
viewer.terrainProvider = terrainProvider;
在这个示例中,Cesium.createWorldTerrain()
是 Cesium 提供的默认地形服务,它使用 .terrain
格式的数据。你也可以使用本地的 .terrain
文件,或者通过指定 URL 来加载自定义的地形数据。
.terrain
格式的应用场景
-
全球地形渲染
.terrain
格式非常适合处理全球范围的地形数据。通过量化网格技术,Cesium 可以在不牺牲性能的情况下展示全球地形,支持流式加载不同区域的地形数据。 -
高精度地形建模
对于需要高精度地形细节的应用,例如城市建模、灾难模拟、科学可视化等,.terrain
格式提供了有效的存储和加载机制,可以在保证性能的前提下,展示高质量的地形数据。 -
地理信息系统(GIS)
.terrain
格式适用于大规模地理信息系统中的地形数据展示。例如,城市规划、环境监测和交通模拟等领域的 GIS 应用可以从中受益。
总结
Cesium 的 .terrain
格式(量化网格)是一个高效的地形数据存储和加载解决方案。通过量化压缩、层次化切片和动态加载等技术,它能够处理大规模地形数据,并保证高效的加载和渲染性能。对于需要全球范围或大区域、高精度地形数据的应用,.terrain
格式提供了理想的支持。
随着 Cesium 的发展,.terrain
格式将继续在地理信息系统、3D 地图和虚拟现实等领域发挥重要作用。了解和掌握 .terrain
格式的使用,可以帮助开发者更好地构建高效的地形渲染应用,提升用户体验。
生成地形工具
TilesBuilder: TilesBuilder提供一个高效、兼容、优化的数据转换工具,一站式完成数据转换、数据发布、数据预览操作。
标签:terrain,bytes,unsigned,地形,详解,Cesium,顶点 From: https://blog.csdn.net/ismartcube/article/details/143907441