做三维GIS的人,八成都有过这种经历:手头倾斜摄影模型全是OSGB格式,好不容易用ContextCapture、大疆智驾(或者其他建模软件)跑完了空三、生成模型,结果甲方一句"要在网页上看",瞬间把整个流程拉回原点。OSGB在本地桌面软件里很流畅,但到了Web端就是怎么都使不上劲。于是问题就落到了一个词上——转换,把OSGB转成3DTiles。
这个话题网上教程不少,但很多都是"CesiumLab点几下就完事",真正遇到坐标偏移、纹理丢失、模型黑屏时,还是得自己查半天。我一直想写一篇能把原理、工具、步骤、坑都串起来的实战文章,正好这两天又帮朋友处理了一批数据,干脆把经验彻底梳理一遍。这篇文章不是那种"下一步、下一步"的流水账,我会把OSGB和3DTiles背后的存储逻辑讲清楚,再完整过一遍工具选型、转换操作、参数优化和常见问题排查,保证你看完不仅能转出能用的数据,还能知道为什么有些数据怎么转都出问题。
1. 先搞清楚:OSGB和3DTiles到底差在哪
1.1 OSGB的成长环境与存储逻辑
OSGB(OpenSceneGraph Binary)其实不是专门的倾斜摄影格式,它脱胎于OpenSceneGraph这个三维渲染引擎的二进制格式。倾斜摄影建模软件(如ContextCapture)之所以偏爱它,是因为它能把模型几何、纹理、LOD层级和节点信息打成一个二进制块,读取效率高,而且保留了完整的金字塔结构。但这里有个关键点:OSGB保存的是相对坐标,每个瓦片都有自己独立的空间参考,配合一个元数据文件(通常叫Metadata.xml)才能拼回完整场景。
这带来一个很实际的问题——OSGB的加载通常依赖专门的本地渲染引擎,比如Skyline、超图、或者基于OSG的二次开发程序。这些程序能直接把OSGB当文件系统遍历,按需读取瓦片。但放到Web上,浏览器里没有OSG运行时,你不可能让Cesium或Three.js再去解析OSGB的二进制内部结构,更没有Node层级管理、LOD调度的那套规则。
1.2 3DTiles凭什么成为WebGIS新宠
3DTiles是Cesium团队在2016年推出的开放规范,解决的就是海量三维数据在Web端高效渲染的问题。它的核心思想是:把三维数据切成分层分块的瓦片集合,每个瓦片包含glTF或B3DM格式的模型内容,并用一个tileset.json描述整棵瓦片树的包围体、几何误差、子节点引用关系。浏览器加载时,根据当前相机位置和视锥体,动态请求合适的瓦片层,从而做到大规模场景的流式加载。
和OSGB相比,3DTiles并不是简单的"格式转换",它定义了一整套调度规范:瓦片包围体可以是包围盒(Box)、包围球(BoundingSphere)或区域(Region);几何误差(GeometricError)决定了哪一层该显示、哪一层该替换;子节点引用允许空间索引按需加载。这些能力是浏览器端高效渲染的基础,也是OSGB本身不具备的。
1.3 为什么说转换不是"改个后缀名"
很多人觉得转换就是把文件头换一下,这是最大的认知误区。OSGB的瓦片结构、坐标基准、纹理引用方式和3DTiles的B3DM/glTF格式完全不同。比如OSGB通常按层级目录存储,每个节点包含多个子块,而3DTiles是把每个瓦片序列化为二进制后嵌入B3DM容器;OSGB的纹理多以JPEG或PNG散落在同级目录,而3DTiles要求纹理内嵌进glTF的buffer中。也就是说,一次真正的转换至少要完成:
- 解析OSGB的节点树,重建3DTiles的瓦片树
- 把OSGB模型的坐标原点转为全球地理坐标或局部坐标体系
- 重新构建LOD层级,生成与3DTiles对应的几何误差
- 将OSGB中的几何数据(顶点、法线、纹理坐标)重组为glTF格式
- 把外部纹理打包进B3DM或glTF内部
所以,转换本质上是一次数据结构的重构。理解了这个底层逻辑,后面遇到各种问题就知道该从哪一层去排查。
2. 转换前的"地基":数据体检与坐标系预处理
2.1 从Metadata.xml里读懂源数据
几乎每套OSGB倾斜模型根目录下都有一个Metadata.xml文件。很多人忽略它,结果转换出来的模型位置不对,回头找原因,才发现源数据是什么坐标系都没搞清楚。
在ContextCapture生成的OSGB数据中,Metadata.xml里通常记录了空间参考系统(SRS)信息。常见的有两种:一种是WGS84地理坐标系,另一种是高斯-克吕格投影坐标系(CGCS2000或西安80等)。打开xml文件,你会看到类似<SRS>EPSG:4326</SRS>或<SRS>EPSG:4547</SRS>这样的标签。EPSG:4326就是经纬度,EPSG:4547代表CGCS2000 / 3-degree Gauss-Kruger zone 37之类的投影坐标系。拿到这行信息,转换工具才能正确理解源数据坐标。
如果Metadata.xml不完整,还可以查看数据目录里的project文件,比如ContextCapture的.xml工程文件。实在不行,只能根据项目范围大致判断坐标系。需要注意,同一片区域可能有多个投影带,中央子午线不同会导致转换结果偏离几十米甚至上百米。
2.2 坐标系不统一,转换完就是摆设
3DTiles在Cesium里默认用的是WGS84经纬度坐标系(EPSG:4326),但Cesium内部会将其转换为地心笛卡尔坐标(ECEF)进行渲染。如果你的OSGB数据是投影坐标,转换工具必须知道原坐标系到WGS84的转换参数,才能把每个顶点正确归位。
实际操作里,我遇到过两种常见问题:
- 源数据是CGCS2000投影坐标,但工具里选了WGS84地理坐标,导致模型整体平移几百米甚至几公里。
- 源数据使用自定义独立坐标系,没有EPSG编码,工具无法自动识别,需要手动指定七参数或已知控制点。
所以转换前务必确认两件事:一是源数据坐标系是否已知且明确,二是转换工具的坐标系设置是否正确。如果源数据是地方独立坐标,建议先在原始软件中做一次坐标转换或重新设置工程坐标系,把数据归到标准坐标系下再切片。
2.3 目录结构和命名规范:别让工具找不到家
另一个看着不起眼却很折磨人的问题是OSGB的目录结构。建模软件输出的OSGB数据通常按Tile_xxx目录层层嵌套,每个Tile目录里包含一个与目录同名的.osgb文件(或L15、L16等层级文件)和若干子目录。有些数据可能被复制到新路径时只拷了模型文件,漏了Metadata.xml,或者子文件缺失。
在转换前,最好检查目录层级是否完整。尤其是ContextCapture输出的Data目录,通常结构如下:
Data/ ├── Tile_0000/ │ ├── Tile_0000.osgb │ ├── Tile_0000/ │ │ ├── Tile_0000.osgb │ │ └── ... │ └── ... ├── Tile_0001/ │ └── ... └── Metadata.xml大部分转换工具要求你指定Data根目录,即包含Metadata.xml的那个目录。如果指定错了层级,工具很可能只看到孤零零的某个瓦片文件,转换出来的是一个"碎片",而不是完整模型。
2.4 原点偏移与中央子午线的坑
倾斜摄影建模时通常会设置一个原点,把模型放在局部坐标下。这个原点在项目设置里一般对应地理位置(经纬度)。当模型导出为OSGB时,局部坐标会通过地理参考转换成投影坐标。但如果你原始工程原点设置错误,或者在后处理阶段挪动过模型,OSGB的世界坐标很可能带着一个巨大的偏置。
转换时,偏置会导致瓦片包围体计算异常,在3DTiles里表现为模型飞到空中、缩成一个点或者完全不显示。这时候不要急着在Cesium里调Camera,先回到源数据检查原点偏移。用QGIS或Global Mapper加载一下OSGB的参考范围,看看是否与真实位置吻合。
另有一个隐蔽的坑:高斯投影的中央子午线。很多地方坐标系采用3度带或6度带,不同带之间在边缘区域有重叠,如果转换工具选错投影带,模型会整体偏移。比如某地区CGCS2000 3度带中央子午线是120度,你选成117度,结果模型会偏移约3度经度对应的距离。所以一定要确认中央子午线的值。
风险自检:转换开始前,最好先在小范围内做一次测试转换,选几个典型的瓦片,转换后用Cesium加载确认位置、朝向、大小都正确,再全量转换。这个习惯能帮你省下大量返工时间。
3. 工具选型:没有万能钥匙,只有适合场景的方案
OSGB转3DTiles的工具并不少,但各自适合的场景差别挺大。我从图形化工具、开源命令行、以及商业GIS平台三个维度分别讲。
3.1 CesiumLab:省心的全流程图形化工具
国内做三维GIS的人基本都用过CesiumLab。它把OSGB转3DTiles封装成了非常直观的界面,功能上支持坐标系选择、LOD层级设置、纹理压缩、合并根节点等。对多数项目来说,CesiumLab是效率最高的选择,因为它把很多容易出错的底层参数都隐藏了,默认值基本能用。
CesiumLab的核心优势在于"快"和"稳"。快是指操作流程短,从加载数据到生成结果只要几步;稳是指它针对ContextCapture生成的OSGB做了大量适配,你不需要关心OSGB内部节点树怎么解析。不足之处是闭源、新版本有授权管理,而且自动处理的黑盒逻辑有时会让你排查问题比较被动。
3.2 开源命令行工具:obj2tiles与3d-tiles-tools
如果项目有批量处理、自动化部署的需求,或者预算有限,就得考虑开源方案。常见的路径是先把OSGB转成OBJ或glTF,再用开源工具转成3DTiles。
- obj2tiles:CesiumGS官方之外比较活跃的转换工具,能把OBJ格式转成3DTiles,支持B3DM和glTF输出。它的原理是把OBJ文件中的顶点、材质、纹理打包为glTF,再按照指定的LOD策略构建瓦片树。它不能直接读OSGB,所以需要先借助其他软件或脚本将OSGB导出为OBJ。
- 3d-tiles-tools:CesiumGS维护的Node.js工具集,主要是对已有3DTiles做优化、抽稀、格式转换和比较,比如生成瓦片索引、压缩纹理、合并根节点等。它一般不负责把OSGB转成3DTiles,但可以用于转换后的优化和调试。
在开源方案中,还有一个小众选择是py3dtiles,它可以把点云、OBJ等转成3DTiles,也能读取部分倾斜模型,但成熟度、文档和社区活跃度都没有前两者高,建议谨慎使用。
3.3 其他商业GIS平台和自研方案
超图SuperMap、ArcGIS Pro等GIS平台也提供了OSGB转3DTiles或三维切片的能力。比如超图的"倾斜摄影模型入库"可以在数据处理后直接生成S3M或3DTiles;ArcGIS Pro的"创建3D Tiles"工具近年来也逐步完善。这类方案适合本来就在用对应平台体系的单位,好处是和平台的数据管理、服务发布深度集成,坏处是授权成本高,处理大批量数据时需要花费较多操作时间。
如果团队有开发能力,也可以基于开源库(如CesiumGS的3d-tiles-generator模块,或Three.js自建的glTF生成工具)自研转换管线。但自研的代价不低,尤其OSGB的解析库本身就不常见,通常需要逆向或借助OSG的C++接口。除非你有大量定制需求,否则我不建议从零开始。
3.4 我这几年的选型倾向
做了这么多项目,我的选择逻辑是:
- 甲方要快速交付、数据量中等(比如一个区县几百G以内)、不需要深度定制的,首选CesiumLab。
- 项目有自动化Pipeline、每月处理多次数据、希望流程可控的,建议通过脚本把OSGB转OBJ再转3DTiles。
- 如果后面还要做地形、影像、点云、倾斜多源数据整合,并且愿意花时间学习,开源工具链值得投入;否则商业平台能帮你省去大量问题。
下面我把工具对比整理成一个表,方便你快速决策。
| 工具/方案 | 输入格式 | 图形化 | 坐标系支持 | 批量处理 | 成本 | 适用人群 |
|---|---|---|---|---|---|---|
| CesiumLab | OSGB等 | 是 | 完善 | 支持任务队列 | 授权 | 项目交付、非开发人员 |
| obj2tiles + 二次开发脚本 | OBJ/glTF | 否 | 需手动处理 | 支持脚本 | 免费开源 | 开发团队、自动化流程 |
| 3d-tiles-tools | 3DTiles | 否 | N/A | 支持 | 免费开源 | 数据优化、后处理 |
| SuperMap/ArcGIS | OSGB等 | 是 | 完善 | 一般 | 高 | 已有平台体系的单位 |
| 自研 | OSGB | 无 | 自定义 | 自定义 | 极高 | 有特殊需求的大团队 |
4. 实战操作:CesiumLab从OSGB到3DTiles完整转换流程
因为CesiumLab是使用率最高的工具,我以它为蓝本,把完整操作流程和参数含义讲清楚。这里的操作步骤是基于较新的3.x版本界面,老版本按钮位置略有差异,但核心参数大同小异。
4.1 第一步:新建数据处理任务并设置输入输出
打开CesiumLab,在左侧功能列表找到"数据处理",选择"通用模型转3DTiles"或"OSGB转3DTiles"(不同版本命名可能不同)。进入界面后:
- 添加数据:选择OSGB数据根目录(包含Metadata.xml的文件夹)。
- 输出路径:指定一个空目录,工具会在其中生成
tileset.json和模型切片文件夹。 - 空间参考:如果源数据Metadata.xml已经正确记录EPSG,工具会自动读取。读取异常时,需要手动选择源坐标系和目标坐标系(一般目标选EPSG:4326即可,Cesium能识别WGS84经纬度)。
这里有个细节:输出坐标系选项,有些版本会让你选"经纬度"或"Web墨卡托"。要在Cesium里用,选"经纬度"即可,因为3DTiles本身支持地理坐标,不需要转成墨卡托。
4.2 第二步:关键参数设置详解
这块是转换质量的灵魂,我逐个说:
LOD层级设置
LOD(Level of Detail)决定了3DTiles瓦片树的金字塔深度。CesiumLab通常提供一个"最大层级"或"保留层级"参数。如果你的OSGB原始数据有15层(常见L15、L16),转换时建议保留全部层级,这样远看近看都有足够的细节。但层级越多,瓦片数量越多,请求数量也越大。如果场景主要用于宏观展示,不需要进入建筑内部,可以适当减少层级,比如保留到12层左右,体积能小不少。
纹理压缩
CesiumLab支持将纹理压缩成WebP或KTX2格式。WebP兼容性好,体积比JPEG小很多;KTX2在GPU上可以直接解压,加载效率更高,但需要Cesium版本支持(1.98以上)。如果你用较老Cesium版本,建议选WebP。压缩率一般可以设为0.7~0.8,肉眼几乎看不出差别,文件体积能减少一半甚至更多。
坐标原点与模型置平
在转换参数里,通常会看到"模型原点"或"中心点坐标"选项。作用是把模型的中心设置到某一个地理坐标上,有些场景下需要贴地处理。如果数据本身已经带地理参考,这个参数不用改;如果源数据是自定义工程坐标,可以手动输入一个已知控制点的经纬度来定位模型。
空间索引与包围体
新版CesiumLab可能会提供包围体类型的选择,如"包围盒"或"包围球"。默认选包围盒就行,包围球在某些大场景LOD调度时更灵活,但计算稍微复杂。不建议随意改,除非你对Cesium调度很熟。
4.3 第三步:执行转换与过程监控
参数设置完后,点击"开始处理"进入任务队列。CesiumLab会显示处理进度、当前处理的瓦片目录、耗时预估。数据量大的情况下,转换时间可能从几十分钟到几小时不等,这取决于IO性能和源数据大小。
转换过程中我建议盯着三个地方:
- CPU利用率:如果一直是100%,说明工具在正常榨干性能;如果波动很大,可能是IO瓶颈。
- 输出目录增长速度:观察tileset的临时目录是否持续有文件产出,若长时间无变化,多半卡在某个坏瓦片上。
- 日志信息:CesiumLab一般在日志里输出"处理Tile_xxx"的信息,如果反复卡同一个Tile,那基本可以断定该瓦片文件损坏或坐标异常。
4.4 第四步:验证命令行输出的tileset.json与数据大小
转换结束后,先别急着到处部署。到输出目录检查一下:
tileset.json是否存在且非空- 目录下是否有与LOD层级对应的
Lxx子目录 - 用文本编辑器打开
tileset.json,确认root节点的boundingVolume数值是否正常(不应为全0或超大值) - 用浏览器直接加载该tileset,绕过后端服务,确认能显示
一个正常的tileset.json大概长这样(简略版):
{ "asset": { "version": "1.1", "generator": "CesiumLab" }, "geometricError": 98304.0, "root": { "boundingVolume": { "box": [123.45, 45.67, 100.0, 89, 0, 0, 0, 56, 0, 0, 0, 78] }, "geometricError": 1024.0, "refine": "REPLACE", "children": [...] } }如果你看到root的boundingVolume里数值全是0,说明源数据坐标解析失败,需要返回上一步检查坐标系设置。
5. 开源之路:用命令行工具完成转换和批处理
如果你的场景需要自动化,图形化工具就有点力不从心了。下面我讲讲怎么用开源工具链搭一条可复用的转换流程。
5.1 obj2tiles的基本原理与依赖环境
obj2tiles是NASA团队开源的一个工具,主要使用Node.js和gulp构建流水线。它的工作流程是:读取OBJ文件,使用ObjectToTiles对象模型,生成一个包含LOD的3DTiles瓦片树。因为它依赖Node.js,所以你需要先安装Node环境和npm。
由于obj2tiles缺少对OSGB的直接支持,常规做法是先用其他工具把OSGB转成OBJ。比如:
- 在ContextCapture中重新导出OBJ/FBX(适合原始工程还在的情况)
- 使用第三方转换插件(如上帝之眼、模型转换器)将OSGB转OBJ
- 通过Assimp库写脚本解析OSGB再导出OBJ
这一步虽然绕,但好处是OBJ格式无比通用,后续不只可以转3DTiles,还能转glTF、FBX等,适合多种用途。
5.2 一条命令完成单个模型转换
安装好obj2tiles后,通常通过gulp任务或直接调用node脚本。假设你已经把一个瓦片目录合并成一个大的whole_model.obj,并生成了对应的whole_model.mtl和纹理文件夹,就可以执行类似命令:
node node_modules/obj2tiles/obj2tiles.js ./data/whole_model.obj --output ./output_tiles --tilesetName tileset.json具体参数名可能随版本变化,可能是-o或--output,也可能是--maxLod等。使用前先查一下项目README。执行完成后,输出目录里会生成一个完整的3DTiles切片集合。
需要注意的是,obj2tiles默认只支持WGS84坐标(经度、纬度、高度),所以你的OBJ文件坐标必须是经纬度。这就是前面说的预处理环节很重要的原因——如果源数据是投影坐标,你需要先转换坐标,或者用脚本对每个顶点做坐标转换。
5.3 批量转换:bash脚本与Python调用
当你有多栋楼、多个村庄需要分别转换时,批处理就成了刚需。如果你把每个模型单元都导出为独立的OBJ文件,可以用一个bash循环搞定:
for f in /data/models/*.obj; do base=$(basename "$f" .obj) mkdir -p "/output/$base" node node_modules/obj2tiles/obj2tiles.js "$f" --output "/output/$base" --tilesetName tileset.json done如果你更喜欢Python,也可以直接用subprocess调用Node命令。这样可以同时集成数据下载、坐标转换、结果校验等环节,形成完整的ETL流程。实际上,我在项目里通常还会在批处理脚本最后加一步:解析生成的tileset.json,统计瓦片数量和数据体积,生成一份质量报告,方便交付时说明数据情况。
5.4 开源方案常见的编译和依赖问题
开源工具用起来最头疼的问题就是环境安装。obj2tiles依赖的很多npm包(比如gulp、gltf-pipeline等)在编译原生模块时可能失败,尤其是在Windows上。我的经验是:
- 尽量用Node.js LTS版本,避免最新版不兼容旧依赖
- 如果安装失败,先尝试删除
node_modules重新执行npm install - 遇到node-gyp编译错误,需要先安装Python和Visual Studio Build Tools(Windows)
- 某些内置的COLLADA2GLTF或gltf-pipeline工具需要单独安装,按照README一步一步来
这些坑在文档里往往写得不够细,需要自己踩几轮。如果你赶项目,建议还是用CesiumLab;如果是为了以后自动化省时间,开源工具链值得投入。
6. 踩坑实录:转换后模型加载出现坐标漂移、纹理丢失、黑屏怎么办
我在社区里见过大量类似提问:"转换后Cesium加载模型偏移了几百米","模型变成了白色没有纹理","加载以后一片黑屏"。这些问题的根源往往都出在转换参数和源数据质量上。我把排查链路完整写出来,方便你照着定位。
6.1 坐标漂移的根源排查链路
坐标漂移是OSGB转3DTiles排名第一的坑。典型表现是模型不在预期位置,有的偏东南,有的偏西北,有的高度直接飞天。要排查,按下面顺序来:
- 检查Metadata.xml:确认源数据坐标系是否被工具正确识别。如果EPSG编码缺失或错误,工具可能会默认按地理坐标处理,而源数据实际上是投影坐标,结果必偏。
- 检查转换日志中的中心点:CesiumLab等工具通常在日志中输出"模型中心点坐标",把它和源工程设置的真实中心点对比。若差值在几十米内,可能是中央子午线问题;若差值很大,则可能是坐标系完全不对。
- 在Cesium中打印实际加载位置:在Cesium的
tileset.readyPromise回调中,读取tileset.boundingSphere.center,转成经纬度后与真实位置对比。这样能准确判断偏了多少、往哪个方向偏。 - 用局部坐标小数据集做对照:切一小块已知位置的OSGB数据,转换后在Cesium中加载,看位置是否正确。如果对,说明是全量数据里某些瓦片的坐标问题;如果不对,则是整体参数问题。
这个链路从源头到结果逐步锁定,通常能在10分钟内找到问题所在。
6.2 纹理丢失与模糊:贴图路径和压缩惹的祸
纹理丢失有两种情况:完全没贴图(模型变白)和贴图花屏/模糊。完全没贴图的原因通常是:
- 转换工具没有找到OSGB引用的外部纹理文件(JPEG/PNG),路径被改变或文件名大小写不一致
- OBJ格式的MTL文件引用了相对路径,但OBJ文件位置改变后纹理路径失效
贴图花屏或模糊则可能是纹理压缩参数设置过高,比如WebP压缩率调到0.1,细节损失严重;或者转换时使用了不支持的纹理格式,Cesium无法正确解码。
排查时可以先打开Cesium的开发者工具(F12),查看Network面板中是否有明显失败的图片资源请求。然后回到转换工具,调低压缩率重新测试一小块数据。如果纹理恢复正常,说明是压缩参数问题;如果依旧花屏,就要检查源纹理是否损坏。
另外注意:如果OSGB模型里的纹理是CRN格式(一种压缩纹理),很多转换工具如果只做解码不解压,输出的3DTiles可能无法正常显示。这种情况需要先用原始建模软件重新导出纹理,或者换用支持CRN解码的转换工具。
6.3 加载黑屏或白模:LOD层级与bbox的问题
有时候模型加载后整个场景区域一片空白,旋转视角可能突然出现部分模型,但很快消失。这多半是瓦片调度异常导致的。常见原因:
- tileset.json里的
geometricError设置不合理,导致Cesium认为当前层级足以显示,但又找不到对应瓦片内容 - 根节点
boundingVolume的包围盒坐标与实际模型位置不匹配,视锥剔除时把模型剔掉了 - 瓦片文件名或路径与tileset.json中的URI不一致,加载失败
我的排查思路是:先用Cesium的debugShowBoundingVolume属性打开包围盒可视化。如果能看到包围盒在正确位置,但模型内容不出来,说明瓦片内容读取异常;如果包围盒都不在视线内,说明坐标就已经错了。
const tileset = await Cesium.Cesium3DTileset.fromUrl('./tileset.json'); tileset.debugShowBoundingVolume = true;如果定位到是LOD层级问题,可以尝试把root的geometricError调大或调小,或者将refine从REPLACE改为ADD(同一区域多层叠加显示),看是否能恢复渲染。但这只是临时排查手段,最终的修复还是要回到转换参数设置。
6.4 排查流程总结:从数据源头到浏览器控制台
我把上面三类问题的排查逻辑总结一个套路,遇到问题按顺序执行:
- 用Global Mapper或QGIS查看原始OSGB范围,确认源数据位置是否合理。
- 转换前先在工具里用"预览"或"普通模式"小范围测试,确认输出能否正确加载。
- 检查生成的tileset.json中包围体数值和几何误差是否正常。
- 用Cesium加载并开启Debug模式,分别查看
boundingVolume、show、geometricError的数值,判断问题出在调度还是内容。 - 若内容异常,检查纹理请求、瓦片文件能否直接访问,以及文件路径是否含有中文或特殊字符。
大部分问题在这几步后都能定位到根因。剩下的少数情况,则可能是转换工具的Bug,这时候不妨换一个工具交叉验证。
7. 转换之后的进阶话题:单体化、属性挂接与性能调优
能成功加载模型只是第一步,真实项目中往往还要做单体化、属性查询、空间分析。这部分内容虽然不属于"转换"本身,但如果不提前思考,转换出来的数据可能无法满足后续业务要求,我顺带讲讲。
7.1 三种常见单体化思路:切割、ID绑定、动态叠加
倾斜摄影模型本质上是连续的Mesh,建筑和地表没有逻辑边界。要实现对某栋楼的点击、高亮、属性查询,必须做单体化。常见的三种思路:
物理切割单体化:在建模软件或后处理软件中,用建筑轮廓线把模型裁开,每个建筑单独成为一个对象。这样做出来的效果最精确,交互最好,但会破坏模型整体性,且切割边缘可能出现破面和空洞。
ID绑定单体化:在转换或建模阶段,给不同建筑区域赋予不同ID(例如在OBJ顶点颜色里写入建筑编号),然后在前端根据ID拆分拾取。这种方案对数据预处理要求高,很多转换工具不直接支持。
动态叠加单体化:在Cesium中加载原始3DTiles,同时叠加建筑轮廓的GeoJSON、多边形实体,拾取时命中叠加的多边形代替模型本身。这种方法最简单,还能把属性挂到多边形上,用来做点击查询完全够用,视觉上没有切割痕迹,是我比较推荐的做法。
7.2 给3DTiles挂属性:从建模阶段就要考虑
如果你希望3DTiles瓦片本身带有属性(比如建筑名称、楼层、面积),就需要在建模阶段输出属性关联信息。多数OSGB数据是没有属性信息的,除非你在原始软件里做了分对象建模或者通过插件导入了shp属性。
另一种可行方案是,通过空间关系把外部数据库属性与模型关联:把建筑范围shp和倾斜模型叠加,用空间查询判断每个瓦片的boundingVolume与哪个建筑多边形相交,再把属性表写入瓦片的batchTable或挂到前端Feature上。这属于较高级的后处理,需要一定开发量,但能真正让3DTiles支持属性查询。
7.3 Cesium加载优化:请求数、显存和调度策略
即使转换成功,Web端加载性能也可能不理想。优化方向有三个:
合并瓦片、减少请求数:数据转换时如果瓦片过于细碎,浏览器会发起大量资源请求,造成卡顿。合并根节点或子节点能显著减少请求数量,CesiumLab里有"根节点合并"选项,可以把很多小瓦片合并成大瓦片。代价是单瓦片文件变大,加载首帧会更慢,需要权衡。
纹理压缩:正如前面说的,转成KTX2或WebP能大幅降低显存占用。我在实际项目里,同样一份数据用WebP压缩后显存占用降低了约40%,帧率提升明显。
优先加载策略:如果模型范围很大,可以在Cesium中设置maximumScreenSpaceError,提高这个值会让Cesium在更远距离加载低精度瓦片,从而减少加载量。也可以在3DTiles中有意减少LOD层级,让最高层在视角近到一定程度时才加载。
这些都是转换时就能顺手设定的参数,如果你把转换和后续加载当作一个整体来考虑,后面优化起来会轻松很多。
最后再说一句实际体会:无论用哪个工具,转完之后先保留原始OSGB数据和参数配置,别急着清理。倾斜摄影数据处理通常不是一个单向流程,很可能会因为需求变化要重新转换、调整范围或者修正坐标系。我吃过亏,所以现在都会把源数据、转换日志、参数截图打包归档,每次重转时按需调参,几年下来省了不少时间。如果你正准备做一次OSGB转3DTiles,不妨也从今天开始养成这个习惯。