当前位置: 首页 > article >正文

cesium 3DTiles之pnts格式详解

Point Cloud

1 概述

点云(Point Cloud)瓦片格式用于高效流式传输大规模点云数据,常用于 3D 可视化中。每个点由位置(Position)和可选的属性定义,这些属性用来描述点的外观(如颜色、法线等)或应用特定的元数据。

在 3D Tiles 的术语中,每个点被称为一个“特征”(Feature)。Point Cloud 瓦片本身是一个二进制块,采用小端字节序(Little Endian)。

2 布局

Point Cloud 瓦片由头部(Header)和正文(Body)两部分组成。以下是 Point Cloud 布局的简图(虚线表示可选字段):

| Header | Body (Feature Table + Batch Table) |
2.1 填充

瓦片的字节长度(byteLength)必须对齐到 8 字节边界。同时,瓦片中的特征表(Feature Table)和批处理表(Batch Table)也必须遵循各自的填充要求。

3 头部(Header)

头部是一个 28 字节的数据结构,包含以下字段:

字段名数据类型描述
magic4 字节 ANSI 字符串固定值 “pnts”,用于标识 Point Cloud 瓦片的内容。
versionuint32Point Cloud 格式的版本号,目前版本为 1。
byteLengthuint32整个瓦片的字节长度(包含头部和正文)。
featureTableJSONByteLengthuint32特征表 JSON 部分的字节长度。
featureTableBinaryByteLengthuint32特征表二进制部分的字节长度。
batchTableJSONByteLengthuint32批处理表 JSON 部分的字节长度。0 表示没有批处理表。
batchTableBinaryByteLengthuint32批处理表二进制部分的字节长度。如果批处理表 JSON 长度为 0,则该值为 0。

头部后面紧接着的是正文部分,它由特征表(Feature Table)和批处理表(Batch Table)组成。

4 特征表(Feature Table)

特征表包含每个瓦片和每个点的属性,这些属性定义了如何渲染点云数据。每个点的数据通过不同的语义(Semantics)进行标识,用于描述点的位置、颜色、法线等属性。

4.1 语义(Semantics)
4.1.1 点的语义(Point Semantics)

这些语义映射到一个特征值数组,用于定义每个点的属性。所有语义的数组长度必须相同,且等于点的数量。每个语义的值都是对特征表二进制部分的引用,而不是嵌入在特征表 JSON 头部中的。

  • 如果同时定义了 POSITIONPOSITION_QUANTIZED,则使用高精度的 POSITION
  • 如果同时定义了 NORMALNORMAL_OCT16P,则使用高精度的 NORMAL

常见的点语义包括:

语义名数据类型描述必需
POSITIONfloat32[3]定义点的位置,包含 x、y 和 z 坐标。
POSITION_QUANTIZEDuint16[3]定义量化的点位置,包含 x、y 和 z 坐标的量化值。
RGBAuint8[4]定义点的 RGBA 颜色值。
RGBuint8[3]定义点的 RGB 颜色值。
RGB565uint1616 位压缩 RGB 颜色,提供 5 位红色、6 位绿色、5 位蓝色。
NORMALfloat32[3]定义点的法向量。
NORMAL_OCT16Puint8[2]定义点的法向量,使用 16 位精度的八度编码。
BATCH_IDuint8, uint16, uint32定义点的批处理 ID,用于从批处理表中检索元数据。
4.1.2 全局语义(Global Semantics)

这些语义定义了所有点的全局属性。

语义名数据类型描述必需
POINTS_LENGTHuint32渲染的点的数量。每个语义的数组长度应与该值相同。
RTC_CENTERfloat32[3]定义点的位置相对于中心的偏移量。
QUANTIZED_VOLUME_OFFSETfloat32[3]定义量化体积的偏移量。
QUANTIZED_VOLUME_SCALEfloat32[3]定义量化体积的缩放值。
CONSTANT_RGBAuint8[4]定义所有点的常量 RGBA 颜色。
BATCH_LENGTHuint32定义唯一的 BATCH_ID 数量。

4.2 点的位置(Point Positions)

4.2.1 坐标参考系统(Coordinate Reference System, CRS)

3D Tiles 使用的是右手坐标系,具有三个轴(x, y, z),并且 x 和 y 的叉乘结果为 z。3D Tiles 定义了局部坐标系统中的 z 轴为上(up)轴。这意味着,在局部笛卡尔坐标系统中,z 轴指向上方。

4.2.2 RTC_CENTER

点的位置可以相对于一个中心点进行定义,以提高渲染的精度(见 “Precisions”)。如果定义了 RTC_CENTER,则所有点的位置都相对于该中心点进行计算。这种方法尤其适用于高精度渲染,允许对整个点云的变换应用更加精确的操作。

4.2.3 量化位置(Quantized Positions)

如果未定义 POSITION,则可以使用 POSITION_QUANTIZED 来存储点的位置,这些位置是相对于量化体积(Quantized Volume)定义的。量化体积通过偏移量(offset)和缩放因子(scale)来映射量化位置到局部坐标空间。

如果既没有定义 POSITION 也没有定义 POSITION_QUANTIZED,则该瓦片无需渲染。

请添加图片描述

量化体积的定义包括偏移量和缩放因子,分别存储在全局语义 QUANTIZED_VOLUME_OFFSETQUANTIZED_VOLUME_SCALE 中。如果没有定义这些全局语义,就无法使用 POSITION_QUANTIZED

量化位置到局部空间的映射公式如下:

POSITION = POSITION_QUANTIZED * QUANTIZED_VOLUME_SCALE / 65535.0 + QUANTIZED_VOLUME_OFFSET

4.3 点的颜色(Point Colors)

如果定义了多个颜色语义,则颜色的优先顺序为:RGBA > RGB > RGB565 > CONSTANT_RGBA。例如,如果一个瓦片的特征表包含 RGBACONSTANT_RGBA 属性,运行时将使用 RGBA 作为每个点的颜色。

如果没有定义任何颜色语义,运行时可以使用应用程序定义的默认颜色来渲染点。

无论如何,都可以使用 3D Tiles 样式(Style)在运行时改变最终渲染的颜色和其他视觉属性。

4.4 点的法线(Point Normals)

每个点的法线是一个可选属性,能够通过启用光照、隐藏表面去除等渲染技术来提高点云的视觉质量。法线将在应用瓦片变换的逆转置矩阵后进行变换。

4.4.1 八度编码法线向量(Oct-encoded Normal Vectors)

八度编码(Oct-encoding)是一种高效表示独立单位向量的方式。具体而言,八度编码将单位法线向量存储为无符号且未归一化的范围([0, 255]),并在运行时将其映射到有符号归一化范围([-1.0, 1.0])。

Cesium 中提供了一个实现,用于编码和解码这些单位向量,相关模块为 AttributeCompression

4.5 批处理点(Batched Points)

点云中的不同特征可以通过 BATCH_ID 语义进行批处理。例如,一个房间的门的所有点会分配相同的 BATCH_ID,而窗户的点则会有不同的 BATCH_ID。这对于按对象进行拾取(picking)或存储应用程序特定的元数据非常有用,特别是在声明式样式(styling)和应用程序用例(如填充用户界面、发出 REST API 请求等)中。

BATCH_ID 语义可以具有 UNSIGNED_BYTEUNSIGNED_SHORTUNSIGNED_INT 的数据类型。如果没有指定 componentType,则默认为 UNSIGNED_SHORT

全局语义 BATCH_LENGTH 定义了唯一的 BATCH_ID 数量,类似于Batched 3D Model

4.6 示例(Examples)

4.6.1 只有位置(Positions Only)

这是一个简单的示例,包含四个点,它们位于单位长度正方形的四个角上:

var featureTableJSON = { 
  POINTS_LENGTH: 4, 
  POSITION: { 
    byteOffset: 0 
  } 
}; 

var featureTableBinary = new Buffer(new Float32Array([ 
  0.0, 0.0, 0.0,  
  1.0, 0.0, 0.0, 
  0.0, 0.0, 1.0, 
  1.0, 0.0, 1.0 
]).buffer);
4.6.2 位置和颜色(Positions and Colors)

以下示例包含四个点(分别为红色、绿色、蓝色和黄色),它们的位置是相对于中心定义的:

var featureTableJSON = { 
  POINTS_LENGTH: 4, 
  RTC_CENTER: [1215013.8, -4736316.7, 4081608.4], 
  POSITION: { 
    byteOffset: 0 
  }, 
  RGB: { 
    byteOffset: 48 
  } 
}; 

var positionBinary = new Buffer(new Float32Array([ 
  0.0, 0.0, 0.0,  
  1.0, 0.0, 0.0,  
  0.0, 0.0, 1.0,  
  1.0, 0.0, 1.0 
]).buffer); 

var colorBinary = new Buffer(new Uint8Array([ 
  255, 0, 0, 
  0, 255, 0, 
  0, 0, 255, 
  255, 255, 0 
]).buffer); 

var featureTableBinary = Buffer.concat([positionBinary, colorBinary]);
4.6.3 量化位置和八度编码法线(Quantized Positions and Oct-encoded Normals)

这个示例中,四个点将有指向上方的法线向量 [0.0, 1.0, 0.0],并且它们位于一个量化体积的角上,量化体积的范围从 -250.0 到 250.0 单位:

var featureTableJSON = { 
  POINTS_LENGTH: 4, 
  QUANTIZED_VOLUME_OFFSET: [-250.0, 0.0, -250.0], 
  QUANTIZED_VOLUME_SCALE: [500.0, 0.0, 500.0], 
  POSITION_QUANTIZED: { 
    byteOffset: 0 
  }, 
  NORMAL_OCT16P: { 
    byteOffset: 24 
  } 
}; 

var positionQuantizedBinary = new Buffer(new Uint16Array([ 
  0, 0, 0,  
  65535, 0, 0,  
  0, 0, 65535,  
  65535, 0, 65535 
]).buffer); 

var normalOct16PBinary = new Buffer(new Uint8Array([ 
  128, 255, 
  128, 255, 
  128, 255, 
  128, 255 
]).buffer); 

var featureTableBinary = Buffer.concat([positionQuantizedBinary, normalOct16PBinary]);
4.6.4 批处理点(Batched Points)

这个示例中,前两个点的 batchId 为 0,后两个点的 batchId 为 1。注意,Batch Table 只包含两个名字:

var featureTableJSON = { 
  POINTS_LENGTH: 4, 
  BATCH_LENGTH: 2, 
  POSITION: { 
    byteOffset: 0 
  }, 
  BATCH_ID: { 
    byteOffset: 48, 
    componentType: "UNSIGNED_BYTE" 
  } 
}; 

var positionBinary = new Buffer(new Float32Array([ 
  0.0, 0.0, 0.0, 
  1.0, 0.0, 0.0, 
  0.0, 0.0, 1.0, 
  1.0, 0.0, 1.0 
]).buffer); 

var batchIdBinary = new Buffer(new Uint8Array([ 
  0, 
  0, 
  1, 
  1 
]).buffer); 

var featureTableBinary = Buffer.concat([positionBinary, batchIdBinary]); 

var batchTableJSON = { 
  names: ['object1', 'object2'] 
};
4.6.5 每点属性(Per-point Properties)

在这个示例中,四个点将有元数据存储在 Batch Table 的 JSON 和二进制部分:

var featureTableJSON = { 
  POINTS_LENGTH: 4, 
  POSITION: { 
    byteOffset: 0 
  } 
}; 

var featureTableBinary = new Buffer(new Float32Array([ 
  0.0, 0.0, 0.0, 
  1.0, 0.0, 0.0, 
  0.0, 0.0, 1.0, 
  1.0, 0.0, 1.0 
]).buffer); 

var batchTableJSON = { 
  names: ['point1', 'point2', 'point3', 'point4'] 
};

5 批处理表(Batch Table)

批处理表存储的是按 batchId 索引的应用程序特定元数据,可用于声明式样式和应用程序特定用例(如填充 UI 或发出 REST API 请求)。

  • 如果定义了 BATCH_ID 语义,批处理表存储每个 batchId 的元数据,批处理表的数组长度将等于 BATCH_LENGTH
  • 如果未定义 BATCH_ID 语义,批处理表存储每个点的元数据,批处理表的数组长度将等于 POINTS_LENGTH

6 文件扩展名和 MIME 类型(File Extension and MIME Type)

点云瓦片使用 .pnts 扩展名和 application/octet-stream MIME 类型。文件扩展名是可选的,有效的实现可以忽略扩展名,直接通过头部的魔术字段来识别内容格式。

7 实现示例(Implementation Example)

这部分内容是非规范性的,实际代码实现可以参考 Cesium 的 PointCloud3DModelTileContent.js 文件,它提供了 3D Tiles 的头部读取代码。
TilesBuilder 工具可转换部分三维格式

8 属性参考(Property Reference)

8.1 点云特征表(Point Cloud Feature Table)

点云特征表定义了用于描述瓦片中点的位置信息和外观属性的语义。其属性包括:

  • POSITION: 定义点的位置(包括量化位置)。
  • POSITION_QUANTIZED: 定义量化点的位置。
  • RGBA, RGB, RGB565: 定义点的颜色。
  • NORMAL, NORMAL_OCT16P: 定义点的法线。
  • BATCH_ID: 用于批处理每个点的 batchId
  • POINTS_LENGTH: 定义点的数量。
  • RTC_CENTER: 定义渲染中心。
  • QUANTIZED_VOLUME_OFFSETQUANTIZED_VOLUME_SCALE: 定义量化体积的偏移和缩放因子。

这些属性可以直接在 JSON 中定义,或者通过 BinaryBodyReference 对象引用二进制体中的对应部分。

8.2 二进制体引用(BinaryBodyReference)

BinaryBodyReference 定义了一个对象,该对象指向二进制体中存储特定属性值的部分,包含 byteOffset 属性,指定从二进制缓冲区的偏移量。

属性:
  • byteOffset (类型: number, 必需):
    指定在二进制体中的偏移量(单位为字节)。

    • 要求: 必需
    • 最小值: 大于等于 0
  • 其他属性:
    可以根据需要在 BinaryBodyReference 中添加其他自定义属性,但 byteOffset 是必需的。

8.2.1 BinaryBodyReference.byteOffset

byteOffsetBinaryBodyReference 中的一个关键属性,定义了该属性值在二进制缓冲区中的起始位置。它指定了从二进制数据开始位置的偏移量,通常是字节单位。

  • 类型: number
  • 要求: 必需
  • 最小值: >= 0

8.3 GlobalPropertyCartesian3

GlobalPropertyCartesian3 是一个对象,它定义了适用于所有特征的全局 3 组件数值属性。 通常,这些数值表示与三维坐标相关的全局属性,如位置、方向等。

8.4 GlobalPropertyCartesian4

GlobalPropertyCartesian4 是一个对象,它定义了适用于所有特征的全局 4 组件数值属性。 这通常用于表示四维数值属性,例如带有时间或颜色信息的 3D 坐标。

8.5 GlobalPropertyScalar

GlobalPropertyScalar 是一个对象,它定义了适用于所有特征的全局标量数值属性。 这种类型的属性用于表示单一的数值,如某些全局设置或常量参数。

8.6 Property

Property 是一个用户定义的属性,指定每个特征的应用程序特定元数据。
这些属性的值可以直接在 JSON 中定义,也可以通过BinaryBodyReference 引用二进制体中的某个部分。 如果 Property 是数组类型,它允许存储每个特征的多个值。

如果你有兴趣了解如何实现或使用点云格式,或者在具体的项目中遇到技术难题,可以随时向我咨询!


http://www.kler.cn/a/391191.html

相关文章:

  • Jmeter基础篇(22)服务器性能监测工具Nmon的使用
  • java模拟键盘实现selenium上下左右键 table中的左右滚动条实现滚动
  • 《深度解析 C++中的弱引用(weak reference):打破循环依赖的利器》
  • AI 写作(五)核心技术之文本摘要:分类与应用(5/10)
  • pip3 install -e .[stable]讲解
  • Stable Diffusion:照片转视频插件
  • D. Cool Graph
  • 【Python进阶】Python中的数据库交互:使用SQLite进行本地数据存储
  • YOLOv9改进,YOLOv9引入EffectiveSE注意力机制,二次创新RepNCSPELAN4结构
  • 谈谈编程思想-抽象,状态,面向对象
  • ssm100医学生在线学习交流平台+vue(论文+源码)_kaic
  • Jtti:服务器为什么要做raid?原因是什么?
  • github 以及 huggingface下载模型和数据
  • 监控架构- Grafana-监控大屏
  • 【go从零单排】XML序列化和反序列化
  • 高校大数据人工智能教学沙盘分享
  • Nginx 的 proxy_pass 使用简介
  • DriveLM 论文学习
  • 前端Cypress自动化测试全网详解
  • 如何快速解决Windows系统中的emp.dll问题
  • Vue中优雅的使用Echarts的三种方式
  • Kubernetes的基本构建块和最小可调度单元pod-0
  • 单例模式全面解析
  • API架构解说
  • Linux(CentOS)项目总结(前后端分离)
  • js | 作用域