博客

OSGB 倾斜摄影数据转换为 3D Tiles 技术文档

本文整理了 OSGB 倾斜摄影模型从数据检查、坐标处理、工具转换、3D Tiles 优化、服务发布到 CesiumJS 加载与验收排查的完整技术流程。

适用场景:将无人机/航空倾斜摄影、ContextCapture / Smart3D / 大疆智图等软件输出的 OSGB 模型,转换为 CesiumJS、三维数字孪生平台、WebGIS 三维场景可流式加载的 3D Tiles 数据。
推荐目标:生成 tileset.json + b3dm/glb 结构,或 3D Tiles 1.1 的 tileset.json + glb 结构,并通过 Nginx / Tomcat / Spring Boot 静态资源服务发布。


1. 文档目标#

本文档解决以下问题:

  1. OSGB 是什么,为什么不能直接在 CesiumJS 中加载。
  2. 3D Tiles 的基本结构是什么,OSGB 转换后应生成哪些文件。
  3. OSGB 转 3D Tiles 有哪些工具路线。
  4. 如何完成从数据检查、坐标确认、转换、优化、发布到 Cesium 加载的完整流程。
  5. 如何处理常见问题:位置偏移、模型倒置、高度不对、加载慢、白模、纹理丢失、跨域、gzip、LOD 闪烁等。

2. 基础概念#

2.1 OSGB 是什么#

OSGB 在倾斜摄影领域通常指 OpenSceneGraph Binary 格式,不是英国国家格网坐标系 Ordnance Survey National Grid 的 OSGB36。

OSGB 是 OpenSceneGraph 的二进制场景格式,常用于存储倾斜摄影模型。一个完整的倾斜摄影成果通常不是单个 .osgb 文件,而是由大量分块模型、纹理图片、LOD 层级和索引文件组成的目录结构。

常见结构如下:

text
Data/ ├── Tile_+000_+000/ │ ├── Tile_+000_+000.osgb │ ├── Tile_+000_+000_L00.osgb │ ├── Tile_+000_+000_L01.osgb │ └── texture/ │ ├── xxx.jpg │ └── xxx.png ├── Tile_+000_+001/ │ └── ... └── metadata.xml / meta.xml / config.xml

OSGB 的特点:

  • 适合本地桌面三维软件加载。
  • 数据量大,文件数量多。
  • 纹理和模型通常采用相对路径关联。
  • 常包含多级 LOD。
  • 坐标可能是地方投影、高斯投影、CGCS2000、WGS84、ENU 局部坐标或无明确地理坐标。
  • CesiumJS 不能直接把 OSGB 目录当作三维瓦片加载,需要转换为 3D Tiles。

2.2 3D Tiles 是什么#

3D Tiles 是面向大规模三维地理数据流式传输和渲染的开放标准,适合倾斜摄影、三维建筑、BIM/CAD、点云等数据类型。

一个典型 3D Tiles 数据集结构如下:

text
output_3dtiles/ ├── tileset.json ├── 0/ │ ├── 0.b3dm │ ├── 1.b3dm │ └── ... ├── 1/ │ └── ... └── textures/

核心文件是 tileset.json,它描述:

  • 根节点和子节点的空间层级关系。
  • 每个瓦片的 boundingVolume。
  • 每个瓦片的 geometricError。
  • 每个瓦片的内容地址,如 .b3dm、.glb、.pnts。
  • 根节点或子节点的坐标变换 transform。

3D Tiles 1.0 常见瓦片内容格式:

格式 用途
.b3dm 批量三维模型,倾斜摄影和三维建筑常用
.i3dm 实例化三维模型,如树木、风机、路灯
.pnts 点云数据
.cmpt 组合瓦片,可包含多个子瓦片内容

3D Tiles 1.1 更强调直接使用 glTF / GLB 内容,传统的 .b3dm、.i3dm、.pnts、.cmpt 在新规范中逐步被 glTF 内容和元数据机制替代。工程上仍大量使用 3D Tiles 1.0 的 .b3dm,兼容性最好。


2.3 OSGB 转 3D Tiles 的本质#

OSGB 转 3D Tiles 不是简单改后缀,而是要完成以下转换:

text
OSGB 层级模型 ↓ 读取模型节点、LOD、纹理、坐标 ↓ 转换几何数据和纹理引用 ↓ 生成 glTF / GLB 或 b3dm ↓ 重建空间层级和包围体 ↓ 生成 tileset.json ↓ 优化、压缩、发布

转换过程主要涉及 5 类关键问题:

  1. 格式转换:OSGB 的几何和纹理转换为 glTF / GLB / b3dm。
  2. 空间层级转换:OSGB 的瓦片树转换为 3D Tiles 的 tile tree。
  3. 坐标转换:地方坐标或投影坐标转换为 Cesium 可识别的 ECEF / WGS84 空间位置。
  4. LOD 控制:设置合理的 geometricError,保证远近切换自然。
  5. Web 优化:压缩纹理、压缩几何、gzip、HTTP 缓存、切片大小控制。

3. 转换前准备#

3.1 数据准备清单#

转换前应确认以下内容:

检查项 要求
OSGB 根目录 应包含完整瓦片目录,不要只复制部分 .osgb 文件
纹理文件 确认 .jpg、.png、.dds 等纹理路径完整
元数据文件 检查是否有 metadata.xml、meta.xml、metadata.json、Data 目录
坐标系统 明确是 WGS84、CGCS2000、高斯投影、UTM、本地坐标还是无坐标
单位 一般为米,若模型过大或过小,需要确认单位
高程基准 明确是否为椭球高、正常高、相对高程
数据范围 记录中心点经纬度、范围、高程
输出目标 明确要生成 3D Tiles 1.0 .b3dm 还是 3D Tiles 1.1 .glb

3.2 推荐目录规范#

建议将原始数据、转换结果、发布目录分开管理:

text
project/ ├── 00_raw_osgb/ # 原始 OSGB 数据,只读保存 ├── 01_checked_osgb/ # 检查修正后的 OSGB ├── 02_3dtiles_output/ # 转换结果 ├── 03_optimized_3dtiles/ # 压缩优化后结果 ├── 04_publish/ # Web 发布目录 ├── logs/ # 转换日志 └── docs/ # 坐标说明、转换参数记录

不要直接在原始 OSGB 目录上执行覆盖式转换,避免损坏原始成果。


3.3 坐标系统确认#

OSGB 倾斜摄影数据最常见的问题是坐标不明确。转换前至少要拿到以下信息之一:

  1. 模型中心点经纬度。
  2. EPSG 坐标系编号。
  3. 投影坐标范围。
  4. 生产软件导出的 metadata 文件。
  5. 外业控制点成果。
  6. 与正射影像、DOM、DEM 或矢量边界可对齐的参考数据。

常见情况:

原始坐标类型 处理方式
WGS84 经纬度 可直接用于 Cesium 定位
CGCS2000 经纬度 与 WGS84 在多数工程展示中差异很小,但严谨项目应明确转换参数
CGCS2000 / 西安80 / 北京54 高斯投影 需要投影转换为 WGS84 或 ECEF
UTM 需要 EPSG 编号,如 EPSG:32650
地方独立坐标 需要七参数、四参数或控制点配准
无坐标模型 只能按手动经纬度、高程和旋转参数放置

Cesium 的全球场景通常使用 WGS84 椭球和 ECEF 坐标。3D Tiles 的 transform 可以把局部坐标系中的瓦片放置到地球上的正确位置。


4. 工具路线选择#

4.1 路线 A:商业/桌面工具转换,适合生产交付#

适用场景:

  • 项目交付要求稳定。
  • 数据量大。
  • 需要图形界面检查。
  • 不希望自己编译开源工具。
  • 对坐标、压缩、发布有较高要求。

常见工具:

工具 说明
Cesium ion 可将多类三维数据转换和托管为 3D Tiles,但不一定适合内网私有化和 OSGB 本地批量处理
Bentley ContextCapture / iTwin Capture Modeler 倾斜摄影生产软件,部分流程可直接输出 3D Tiles
SuperMap iDesktop / iServer 国内 GIS 项目中常用于倾斜摄影切片、S3M、3D Tiles、服务发布
ArcGIS Pro 可处理 I3S / SLPK 等三维场景图层;OSGB 支持能力与版本、扩展和工作流有关
GISBox / CesiumLab 等工具 常用于 OSGB、3D Tiles、S3M 等格式转换与发布
FME 数据转换能力强,适合复杂格式 ETL,但授权成本较高

推荐结论:

  • 政务内网、国产化交付、倾斜摄影批量处理:优先考虑 SuperMap、GISBox、CesiumLab 这类成熟桌面工具。
  • 公网展示或 SaaS 可接受:可考虑 Cesium ion。
  • 已有 ContextCapture 生产链:优先从生产软件侧直接导出 3D Tiles,减少二次转换损失。

4.2 路线 B:开源命令行工具转换,适合可控自动化#

适用场景:

  • 希望在服务器或脚本中批量转换。
  • 可接受编译、调参和排错。
  • 有开发人员维护工具链。
  • 需要纳入自动化处理流程。

常见开源工具:

工具 作用
fanvanzh/3dtiles 支持 OSGB、Shapefile、FBX 转 3D Tiles,支持网格优化、Draco、KTX2 等能力
osgb23dtiles 基于 fanvanzh/3dtiles 的 Python 包,可转换 OSGB 到 3D Tiles 或 GLB
CesiumGS/3d-tiles-tools Cesium 官方工具,主要用于 3D Tiles 分析、gzip、合并、升级、b3dm/glb 互转和优化,不是通用 OSGB 读取器
gltf-pipeline glTF / GLB 优化、glTF 1.0 到 2.0 转换、Draco 压缩
gltf-transform glTF 2.0 资产检查、纹理压缩、几何压缩、优化
OpenSceneGraph osgconv 可将单个 OSGB 转为 OBJ/DAE/OSG 等中间格式,但不负责生成完整 3D Tiles 层级

推荐结论:

  • OSGB → 3D Tiles:优先使用专门支持 OSGB 的工具,如 fanvanzh/3dtiles、osgb23dtiles 或成熟商业工具。
  • 3D Tiles 转换后的检查和优化:使用 3d-tiles-tools、gltf-pipeline、gltf-transform。
  • 不要把 osgconv 当作完整 OSGB 倾斜摄影转 3D Tiles 的主工具。它更适合单模型格式转换,不适合重建大规模瓦片层级。

5. 推荐技术流程#

完整流程如下:

text
原始 OSGB 数据 ↓ 数据完整性检查 ↓ 坐标系统确认 ↓ 选择转换工具 ↓ OSGB 转 3D Tiles ↓ 检查 tileset.json ↓ 模型空间位置校正 ↓ 纹理/几何/瓦片优化 ↓ Web 服务发布 ↓ CesiumJS 加载 ↓ 效果检查与问题修正

6. 方案一:使用桌面工具转换#

不同工具界面不同,但核心参数基本一致。以下以通用流程描述。

6.1 新建转换任务#

  1. 打开转换工具。
  2. 选择数据类型:倾斜摄影 / OSGB。
  3. 指定 OSGB 根目录。
  4. 选择输出格式:3D Tiles。
  5. 指定输出目录。

注意:输入目录通常应选择包含 Data、metadata.xml 或瓦片根节点的上级目录,而不是某一个最底层 .osgb 文件。


6.2 设置坐标参数#

需要配置:

参数 说明
源坐标系 原始 OSGB 数据坐标系
目标坐标系 通常为 WGS84 / ECEF
中心点 模型中心经纬度和高程
高程偏移 用于修正模型悬浮或下沉
旋转角度 用于修正模型方向不一致
单位 通常为米
原点 局部坐标模型需要设置地理原点

如果工具支持自动读取 metadata,可先自动识别;如果加载后位置明显偏移,再手动修正。


6.3 设置切片参数#

常见参数建议:

参数 建议值 说明
输出格式 3D Tiles 1.0 b3dm 兼容性最好
根瓦片几何误差 500–2000 大范围模型取大值,小范围取小值
最大屏幕误差 16 Cesium 默认常用值
单瓦片目标大小 1–10 MB 过大会卡顿,过小会请求过多
纹理最大尺寸 1024 / 2048 根据清晰度和性能平衡
纹理格式 jpg / webp / ktx2 Web 端优先考虑压缩纹理
法线 可保留 有光照需求时保留
Draco 视工具支持开启 可减小几何体积,但会增加解码开销
合并小瓦片 建议开启 减少请求数量
空瓦片剔除 建议开启 减少无效数据

6.4 执行转换#

转换过程中应保存日志,记录:

  • 工具名称与版本。
  • 输入路径。
  • 输出路径。
  • 源坐标系。
  • 目标坐标系。
  • 中心点。
  • 高程偏移。
  • 几何误差参数。
  • 纹理压缩参数。
  • 是否启用 Draco / KTX2。
  • 转换开始和结束时间。
  • 错误日志。

6.5 转换结果检查#

转换完成后,输出目录至少应包含:

text
output_3dtiles/ ├── tileset.json └── 若干 .b3dm / .glb / 子目录

检查项:

  1. tileset.json 是否存在。
  2. tileset.json 中的 asset.version 是否合理。
  3. root.boundingVolume 是否存在。
  4. root.geometricError 是否大于子节点。
  5. content.uri 路径是否能访问。
  6. .b3dm 或 .glb 文件大小是否异常为 0。
  7. 纹理是否随结果一起输出。
  8. 目录路径大小写是否一致。

7. 方案二:使用开源工具 fanvanzh/3dtiles 转换#

说明:开源工具版本变化较快,具体命令参数以项目 README 为准。本文给出工程流程和常用命令示例,实际项目应先用小范围样例测试,再批量处理。

7.1 环境准备#

建议环境:

text
操作系统:Windows 10/11、Ubuntu 20.04+、macOS CPU:8 核以上 内存:32 GB 起步,大数据建议 64 GB+ 磁盘:SSD,剩余空间至少为原始数据 2–3 倍 Node.js:用于 3d-tiles-tools / gltf-pipeline Python:用于辅助脚本

安装 Node.js 后:

bash
node -v npm -v

安装官方 3D Tiles 工具:

bash
npm install -g 3d-tiles-tools npm install -g gltf-pipeline

7.2 获取 OSGB 转换工具#

如果使用 fanvanzh/3dtiles,通常需要下载预编译版本或源码编译。

示例目录:

text
tools/ └── 3dtiles/ ├── 3dtiles.exe └── README.md

检查工具是否可执行:

bash
3dtiles --help

如果使用 Python 包 osgb23dtiles:

bash
pip install osgb23dtiles

7.3 执行 OSGB 转 3D Tiles#

通用命令示意:

bash
3dtiles \ -f osgb \ -i /data/project/00_raw_osgb \ -o /data/project/02_3dtiles_output

不同版本参数可能不同,也可能使用类似:

bash
3dtiles osgb \ --input /data/project/00_raw_osgb \ --output /data/project/02_3dtiles_output

使用 Python 包示例:

python
from osgb23dtiles import osgb_to_b3dm_3dtiles osgb_to_b3dm_3dtiles( "D:/project/00_raw_osgb", "D:/project/02_3dtiles_output" )

转换后检查:

bash
ls /data/project/02_3dtiles_output

应看到:

text
tileset.json *.b3dm / 子目录

7.4 坐标参数处理#

如果原始 OSGB 是局部坐标,转换工具可能只能生成局部 tileset,加载到 Cesium 后会出现在地心、海面附近或完全看不到。这时需要设置 tileset.json 的根节点 transform。

Cesium 常用方式是根据经纬度、高度生成 East-North-Up 到 Fixed Frame 的矩阵:

javascript
const position = Cesium.Cartesian3.fromDegrees(116.391, 39.907, 50); const transform = Cesium.Transforms.eastNorthUpToFixedFrame(position);

如果转换工具不支持写入 transform,可在前端加载后动态设置:

javascript
const tileset = await Cesium.Cesium3DTileset.fromUrl('/data/osgb_3dtiles/tileset.json'); const position = Cesium.Cartesian3.fromDegrees(116.391, 39.907, 50); const matrix = Cesium.Transforms.eastNorthUpToFixedFrame(position); tileset.modelMatrix = matrix; viewer.scene.primitives.add(tileset); viewer.zoomTo(tileset);

更推荐在转换阶段或后处理阶段写入 tileset.json,这样不同客户端加载结果一致。


8. 3D Tiles 后处理与优化#

8.1 使用 3d-tiles-tools 检查#

安装:

bash
npm install -g 3d-tiles-tools

分析单个 b3dm:

bash
npx 3d-tiles-tools analyze \ -i ./output_3dtiles/0/0.b3dm \ -o ./analyze/0_0

分析结果可用于检查:

  • b3dm 头信息。
  • glb 是否有效。
  • feature table / batch table。
  • 是否存在 glTF 1.0。
  • 是否存在 Draco 扩展。
  • 是否存在贴图路径异常。

8.2 gzip 压缩#

对整个 tileset 进行 gzip:

bash
npx 3d-tiles-tools gzip \ -i ./02_3dtiles_output \ -o ./03_optimized_3dtiles

注意:

  • 如果 .b3dm 文件已经 gzip 压缩,Web 服务器必须返回 Content-Encoding: gzip。
  • 如果服务端没有返回该头,Cesium 会按未压缩二进制解析,导致加载失败。
  • 如果文件未压缩但服务端错误返回 Content-Encoding: gzip,也会加载失败。

8.3 b3dm 几何优化和 Draco 压缩#

如果数据是 .b3dm,可尝试:

bash
npx 3d-tiles-tools optimizeB3dm \ -i ./input.b3dm \ -o ./output.b3dm \ --options --draco.compressMeshes --draco.compressionLevel=7

注意:

  • Draco 可显著减小几何体积,但首次加载会有解码开销。
  • 对纹理占比很高的倾斜摄影,Draco 对整体体积的降低可能有限。
  • 不建议不经测试就全量最高压缩,可能导致解码变慢或兼容性问题。
  • 建议抽样测试 1–2 个区域,比较压缩前后体积、首屏时间、帧率和清晰度。

8.4 glTF / GLB 优化#

如果输出为 .glb 或可从 .b3dm 提取 GLB,可使用 gltf-pipeline:

bash
gltf-pipeline -i model.gltf -o model.glb

Draco 压缩:

bash
gltf-pipeline -i model.gltf -o model_draco.gltf -d

对于现代 Web 三维项目,也可考虑 gltf-transform 做纹理压缩、meshopt、去重等优化。倾斜摄影项目中更应关注纹理大小、瓦片粒度和请求数量,而不是只压缩几何。


8.5 geometricError 调整#

geometricError 决定 LOD 切换时机。常见问题:

现象 可能原因 处理
远处过早加载高清瓦片 geometricError 偏小 增大父节点 geometricError
近处仍模糊 geometricError 偏大或子节点缺失 减小子节点 geometricError,检查 LOD
LOD 跳变明显 层级误差不连续 保证父子误差递减平滑
请求数过多 瓦片过碎或误差过小 合并小瓦片,提高误差

9. Web 服务发布#

9.1 Nginx 发布目录#

示例目录:

text
D:/web/data/osgb_3dtiles/ ├── tileset.json ├── 0/ ├── 1/ └── ...

Nginx 配置示例:

nginx
server { listen 8090; server_name localhost; location /data/osgb_3dtiles/ { alias D:/web/data/osgb_3dtiles/; add_header Access-Control-Allow-Origin * always; add_header Access-Control-Allow-Methods "GET, OPTIONS" always; add_header Access-Control-Allow-Headers "Origin, Range, Accept, Content-Type, Authorization" always; types { application/json json; application/octet-stream b3dm; application/octet-stream i3dm; application/octet-stream pnts; application/octet-stream cmpt; model/gltf-binary glb; model/gltf+json gltf; image/jpeg jpg jpeg; image/png png; image/ktx2 ktx2; } expires 30d; add_header Cache-Control "public, max-age=2592000" always; if ($request_method = OPTIONS) { return 204; } } }

访问测试:

text
http://localhost:8090/data/osgb_3dtiles/tileset.json

9.2 gzip 数据的 Nginx 配置#

如果 .b3dm、.i3dm、.pnts、.cmpt 文件本身已经 gzip 压缩,需要加响应头:

nginx
location ~* \.(b3dm|i3dm|pnts|cmpt)$ { root D:/web; add_header Access-Control-Allow-Origin * always; add_header Content-Encoding gzip always; add_header Cache-Control "public, max-age=2592000" always; default_type application/octet-stream; }

但要注意:

  • 只有文件实际是 gzip 压缩时才添加 Content-Encoding: gzip。
  • 如果只是普通未压缩 b3dm,不要添加该头。
  • 建议不要混合压缩和未压缩文件放在同一目录,除非有明确规则区分。

更稳妥的做法:

text
03_optimized_3dtiles_gzip/ # 所有 tile 内容均 gzip 03_optimized_3dtiles_raw/ # 所有 tile 内容均不 gzip

9.3 Tomcat / Spring Boot 发布#

Spring Boot 静态发布目录示例:

text
src/main/resources/static/3dtiles/osgb/ └── tileset.json

或外部目录映射:

yaml
spring: web: resources: static-locations: - file:D:/web/data/

然后访问:

text
http://localhost:8080/3dtiles/osgb/tileset.json

对于大规模 3D Tiles,不建议把数据打进 Jar 包,建议放外部静态目录,由 Nginx 或对象存储直接发布。


10. CesiumJS 加载示例#

10.1 基础加载#

新版 CesiumJS 推荐使用 Cesium3DTileset.fromUrl:

javascript
const viewer = new Cesium.Viewer('cesiumContainer', { terrain: Cesium.Terrain.fromWorldTerrain() }); const tileset = await Cesium.Cesium3DTileset.fromUrl( 'http://localhost:8090/data/osgb_3dtiles/tileset.json' ); viewer.scene.primitives.add(tileset); await viewer.zoomTo(tileset);

10.2 设置最大屏幕误差#

javascript
const tileset = await Cesium.Cesium3DTileset.fromUrl(url, { maximumScreenSpaceError: 16, maximumMemoryUsage: 1024 });

说明:

  • maximumScreenSpaceError 越小,加载越精细,请求越多。
  • maximumScreenSpaceError 越大,加载越粗略,性能越好。
  • 倾斜摄影通常可从 16 开始测试,必要时调到 8 或 24。

10.3 模型高度调整#

如果模型整体悬浮或下沉,可通过 modelMatrix 做高度偏移:

javascript
function update3dtilesMaxtrix(tileset, heightOffset) { const boundingSphere = tileset.boundingSphere; const cartographic = Cesium.Cartographic.fromCartesian(boundingSphere.center); const surface = Cesium.Cartesian3.fromRadians( cartographic.longitude, cartographic.latitude, 0.0 ); const offset = Cesium.Cartesian3.fromRadians( cartographic.longitude, cartographic.latitude, heightOffset ); const translation = Cesium.Cartesian3.subtract( offset, surface, new Cesium.Cartesian3() ); tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation); } const tileset = await Cesium.Cesium3DTileset.fromUrl(url); viewer.scene.primitives.add(tileset); update3dtilesMaxtrix(tileset, 20);

10.4 模型定位到指定经纬度#

对于无地理坐标的局部模型:

javascript
const tileset = await Cesium.Cesium3DTileset.fromUrl(url); const longitude = 116.391; const latitude = 39.907; const height = 50; const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height); tileset.modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(position); viewer.scene.primitives.add(tileset); viewer.zoomTo(tileset);

如果方向不对,需要叠加旋转矩阵。


10.5 调试开关#

javascript
tileset.debugShowBoundingVolume = true; tileset.debugShowGeometricError = true; tileset.debugShowRenderingStatistics = true;

调试完成后关闭,否则影响性能和展示效果。


11. 质量检查方法#

11.1 文件级检查#

检查输出目录:

bash
find ./output_3dtiles -name "tileset.json" find ./output_3dtiles -name "*.b3dm" | head find ./output_3dtiles -name "*.glb" | head

检查空文件:

bash
find ./output_3dtiles -type f -size 0

检查大文件:

bash
find ./output_3dtiles -type f -size +100M

如果单瓦片超过 100 MB,应考虑重新切片或压缩,否则 Web 端加载体验很差。


11.2 HTTP 检查#

检查 tileset.json:

bash
curl -I http://localhost:8090/data/osgb_3dtiles/tileset.json

检查 b3dm:

bash
curl -I http://localhost:8090/data/osgb_3dtiles/0/0.b3dm

重点看:

text
HTTP/1.1 200 OK Access-Control-Allow-Origin: * Content-Type: application/octet-stream Content-Encoding: gzip # 仅压缩文件需要

11.3 Cesium 端检查#

在浏览器开发者工具中检查:

  1. tileset.json 是否 200。
  2. .b3dm / .glb 是否 200。
  3. 是否有 CORS 错误。
  4. 是否有 Unexpected token、Invalid typed array length 等二进制解析错误。
  5. 是否有纹理 404。
  6. 网络请求是否过多。
  7. 单个请求是否过大。
  8. GPU 内存是否持续升高。

12. 常见问题与处理#

12.1 加载后看不到模型#

可能原因:

  1. tileset.json 路径错误。
  2. 跨域失败。
  3. 模型位置在地球另一侧。
  4. 模型高度异常。
  5. boundingVolume 错误。
  6. 瓦片内容文件 404。
  7. gzip 头错误。

处理:

javascript
viewer.zoomTo(tileset); tileset.debugShowBoundingVolume = true;

同时检查浏览器 Network 面板和 Console 面板。


12.2 模型出现在海上或偏移很远#

原因:

  • 原始 OSGB 是地方坐标或投影坐标。
  • 转换时未设置 EPSG。
  • 经纬度顺序写反。
  • 高斯投影带号错误。
  • CGCS2000 / WGS84 / 地方坐标没有正确转换。

处理:

  1. 确认原始坐标 EPSG。
  2. 确认模型中心点。
  3. 使用已知控制点校正。
  4. 在转换工具中重新设置源坐标系。
  5. 必要时通过 modelMatrix 做平移、旋转、高程修正。

12.3 模型整体悬浮或下沉#

原因:

  • 高程基准不一致。
  • 原始数据为正常高,Cesium 以椭球高显示。
  • 地形服务与模型高程基准不同。
  • 转换时高度偏移错误。

处理:

  • 设置高度偏移。
  • 与地形贴合时,明确 DEM 高程基准。
  • 对展示型项目,可用整体偏移解决。
  • 对测绘精度项目,应进行高程基准转换。

12.4 模型方向旋转不对#

原因:

  • OSGB 局部坐标轴与 Cesium ENU 坐标轴不一致。
  • 转换工具未正确处理 Up Axis。
  • 模型原点和方向缺少元数据。

处理:

  • 在转换工具中设置方向。
  • 前端通过矩阵叠加 Heading/Pitch/Roll。
  • 检查是 X/Y 轴互换,还是 Z 轴方向问题。

示例:

javascript
const position = Cesium.Cartesian3.fromDegrees(116.391, 39.907, 50); const hpr = new Cesium.HeadingPitchRoll( Cesium.Math.toRadians(90), 0, 0 ); const matrix = Cesium.Transforms.headingPitchRollToFixedFrame(position, hpr); tileset.modelMatrix = matrix;

12.5 模型白模或纹理丢失#

原因:

  1. 纹理没有复制到输出目录。
  2. 纹理路径大小写不一致。
  3. 纹理格式浏览器不支持。
  4. 纹理路径中有中文、空格或特殊字符。
  5. 转换工具未正确处理相对路径。

处理:

  • 避免中文路径和特殊字符。
  • 统一路径大小写。
  • 将 .dds 等纹理转换为 .jpg、.png 或 .ktx2。
  • 重新导出时选择“复制纹理”或“嵌入纹理”。

12.6 加载很慢#

原因:

  1. 单瓦片太大。
  2. 瓦片太碎,请求过多。
  3. 纹理过大。
  4. 未开启 HTTP 缓存。
  5. 未使用 gzip / Draco / 纹理压缩。
  6. maximumScreenSpaceError 设置过低。
  7. 服务端带宽不足。

处理:

  • 控制单瓦片 1–10 MB。
  • 合并过小瓦片。
  • 纹理最大尺寸控制在 1024 或 2048。
  • 开启 HTTP 缓存。
  • 测试 gzip / Draco / KTX2。
  • Cesium 中适当增大 maximumScreenSpaceError。
  • 使用 Nginx 直接发布静态数据。

12.7 LOD 闪烁或跳变明显#

原因:

  • geometricError 不合理。
  • LOD 层级缺失。
  • 父子瓦片包围体不连续。
  • 转换工具生成的瓦片树不稳定。
  • 摄像机移动时加载延迟明显。

处理:

  • 调整 geometricError。
  • 增大缓存。
  • 合理设置 Cesium 的 maximumScreenSpaceError。
  • 优化瓦片大小。
  • 减少瓦片数量和服务延迟。

12.8 浏览器报二进制解析错误#

常见报错:

text
Invalid typed array length Invalid magic Unexpected token Failed to load tile

原因:

  • gzip 头错误。
  • b3dm 文件损坏。
  • Content-Type 不合理一般不是致命问题,但 Content-Encoding 错误会致命。
  • 服务器返回了 HTML 错误页,而不是 b3dm。
  • 文件路径区分大小写导致 404。

处理:

bash
curl -I http://localhost:8090/data/osgb_3dtiles/0/0.b3dm

确认状态码是 200,不是 404/500,也不是登录页 HTML。


13. 生产环境建议#

13.1 数据规模建议#

项目规模 建议
< 1 GB 单机桌面工具即可
1–20 GB 桌面工具或服务器命令行均可
20–100 GB 建议服务器批处理,SSD,64 GB 内存
> 100 GB 建议分区转换、分区发布、按需加载
> 500 GB 建议对象存储/CDN/瓦片服务化,避免单目录超大文件数

13.2 输出切片建议#

  1. 不要让单个 .b3dm 过大。
  2. 不要让瓦片过碎。
  3. 尽量使用稳定的层级结构。
  4. 大范围数据按行政区、工程区或网格分块发布。
  5. 多个 tileset 可通过业务图层控制加载,不一定要合成一个巨型 tileset。
  6. 对展示型首页场景,可单独生成轻量版模型。
  7. 对精细浏览场景,保留高清版模型并按需加载。

13.3 发布建议#

优先推荐:

text
Nginx 静态资源发布 + CesiumJS 前端加载 + 业务系统记录 tileset.json 地址和模型元数据

不建议:

  • 把几十 GB 的 3D Tiles 放进后端 Jar 包。
  • 通过 Java Controller 流式转发每个 b3dm。
  • 每次加载都动态计算瓦片内容。
  • 把 OSGB 原始数据直接放到 Web 前端尝试加载。

14. 与 Vue / Vite / Cesium 项目集成#

14.1 封装加载函数#

javascript
const tileset = await Cesium.Cesium3DTileset.fromUrl(url, { maximumScreenSpaceError: options.maximumScreenSpaceError ?? 16, maximumMemoryUsage: options.maximumMemoryUsage ?? 1024 }); if (options.modelMatrix) { tileset.modelMatrix = options.modelMatrix; } viewer.scene.primitives.add(tileset); if (options.flyTo !== false) { await viewer.zoomTo(tileset); } return tileset; }

14.2 图层管理#

建议业务系统维护三维模型图层表:

字段 说明
id 模型 ID
name 模型名称
tileset_url tileset.json 地址
type 倾斜摄影 / 建筑 / BIM / 点云
lon 中心经度
lat 中心纬度
height_offset 高度偏移
heading 旋转角
visible 是否默认显示
max_sse 最大屏幕误差
remark 备注

前端根据表配置动态加载模型,避免把地址和参数写死在代码里。


15. 自动化批处理示例#

15.1 Windows 批处理示例#

bat
@echo off set INPUT=D:\project\00_raw_osgb set OUTPUT=D:\project\02_3dtiles_output set OPT=D:\project\03_optimized_3dtiles echo Start OSGB to 3D Tiles... 3dtiles -f osgb -i %INPUT% -o %OUTPUT% echo Gzip tileset... npx 3d-tiles-tools gzip -i %OUTPUT% -o %OPT% echo Done. pause

15.2 Linux / macOS 脚本示例#

bash
#!/usr/bin/env bash set -e INPUT="/data/project/00_raw_osgb" OUTPUT="/data/project/02_3dtiles_output" OPT="/data/project/03_optimized_3dtiles" echo "Start OSGB to 3D Tiles..." 3dtiles -f osgb -i "$INPUT" -o "$OUTPUT" echo "Gzip tileset..." npx 3d-tiles-tools gzip -i "$OUTPUT" -o "$OPT" echo "Done."

15.3 转换记录文件#

建议每次转换生成 convert_record.md:

markdown
# OSGB 转 3D Tiles 转换记录 - 项目名称: - 原始数据路径: - 原始数据大小: - 原始坐标系: - 中心点: - 转换工具: - 工具版本: - 输出格式: - 输出路径: - 是否 gzip: - 是否 Draco: - 纹理最大尺寸: - geometricError: - 转换时间: - 操作人: - 问题记录:

16. 验收标准#

16.1 数据验收#

项目 标准
文件完整性 tileset.json 和瓦片文件完整,无 0 字节文件
坐标正确性 与底图、影像、矢量边界基本重合
高程正确性 无明显悬浮或下沉
纹理完整性 无大面积白模、黑块、纹理丢失
层级正确性 远近 LOD 切换正常
加载性能 首屏可接受,浏览不卡死
服务访问 HTTP 200,无跨域错误
浏览器兼容 Chrome / Edge 正常加载

16.2 性能验收#

建议测试指标:

指标 建议目标
首次显示时间 小范围 < 5 秒,大范围按项目要求
单瓦片大小 常规 1–10 MB
最大单文件 尽量 < 50 MB
请求失败率 0
帧率 普通办公电脑 > 25 FPS,展示机 > 30 FPS
显存占用 不持续无限增长
LOD 切换 无明显大面积闪烁

17. 推荐实施方案#

对于一般政务内网三维平台,推荐以下实施路线:

17.1 稳定交付路线#

text
OSGB 原始数据 ↓ 桌面工具转换为 3D Tiles 1.0 b3dm ↓ 抽样检查坐标和纹理 ↓ Nginx 静态发布 ↓ CesiumJS 加载 ↓ 按图层表管理模型

优点:

  • 稳定。
  • 可控。
  • 适合项目交付。
  • 便于运维和问题排查。

17.2 自动化处理路线#

text
OSGB 原始数据 ↓ 命令行工具批量转换 ↓ 3d-tiles-tools 分析和 gzip ↓ 自动生成转换记录 ↓ 发布到 Nginx 静态目录 ↓ 前端动态注册图层

优点:

  • 可批处理。
  • 可纳入数据生产流水线。
  • 适合多旗县、多工程区、多期模型数据。

18. 最终目录示例#

text
/opt/3d-data/ ├── xilingol/ │ ├── abaga/ │ │ ├── tileset.json │ │ └── ... │ ├── xwq/ │ │ ├── tileset.json │ │ └── ... │ └── dlx/ │ ├── tileset.json │ └── ... └── nginx.conf

前端图层配置:

json
[ { "id": "abaga-osgb", "name": "阿巴嘎旗倾斜摄影", "url": "http://server:8090/3d-data/xilingol/abaga/tileset.json", "type": "oblique_3dtiles", "maximumScreenSpaceError": 16, "heightOffset": 0, "visible": false } ]

19. 关键注意事项#

  1. OSGB 不能直接作为 CesiumJS 三维瓦片加载,必须转换为 3D Tiles。
  2. tileset.json 是 3D Tiles 的入口文件。
  3. 坐标系统是 OSGB 转换中最容易出错的环节。
  4. 不要把英国 OSGB36 坐标系和 OpenSceneGraph Binary 的 OSGB 文件格式混淆。
  5. gzip 文件必须和 Content-Encoding: gzip 响应头匹配。
  6. 纹理缺失多数是路径、格式、大小写或转换工具配置问题。
  7. 倾斜摄影性能优化优先关注瓦片粒度、纹理大小、请求数量和缓存。
  8. Cesium 新版加载 3D Tiles 推荐使用 Cesium.Cesium3DTileset.fromUrl()。
  9. 大数据不要打包进后端 Jar,应使用 Nginx、对象存储或专门三维服务发布。
  10. 每次转换必须记录参数,方便复现和排错。

20. 参考资料#

  1. OGC 3D Tiles Standard:
    https://www.ogc.org/standards/3dtiles/

  2. OGC 3D Tiles Specification 1.1:
    https://docs.ogc.org/cs/22-025r4/22-025r4.html

  3. Cesium 3D Tiles Specification GitHub:
    https://github.com/CesiumGS/3d-tiles

  4. CesiumJS Cesium3DTileset 官方文档:
    https://cesium.com/learn/cesiumjs/ref-doc/Cesium3DTileset.html

  5. Cesium 3D Tiles Tools:
    https://github.com/CesiumGS/3d-tiles-tools

  6. Cesium glTF Pipeline:
    https://github.com/CesiumGS/gltf-pipeline

  7. Google Draco 3D Graphics Compression:
    https://google.github.io/draco/

  8. Luciad OSGB Format Documentation:
    https://dev.luciad.com/portal/productDocumentation/LuciadFusion/docs/documentation.html?subcategory=lls_osgb

  9. fanvanzh/3dtiles:
    https://github.com/fanvanzh/3dtiles

  10. awesome-3d-tiles 工具资源列表:
    https://github.com/pka/awesome-3d-tiles


21. 一句话总结#

OSGB 转 3D Tiles 的核心不是单纯格式转换,而是把本地层级化倾斜摄影模型重构为带空间索引、LOD、坐标变换和 Web 优化能力的三维瓦片数据,从而让 CesiumJS 能够在浏览器中按需流式加载和高效渲染。