简介这是一款面向三维GIS与Web可视化开发者的格式转换工具专门解决倾斜摄影模型、Shapefile矢量面数据及通用三维模型向3D Tiles体系转换的难题。工具支持Smart3D产出的OSGB倾斜摄影数据、带高度字段的Shapefile生成3D Tiles也支持OSG/OBJ/FBX/3DS等通用模型转出glTF/glb并能将b3dm还原为glb供调试使用。压缩包共179个文件以dll运行库、gfs规则文件、csv坐标参数及少量exe主程序为主整体约12.05MB解压即用。资源还提供源码获取渠道便于二次开发已吸引3222人学习参考适合需要批量转换三维数据、构建自定义3D Tiles场景的开发者直接套用。1. 倾斜摄影与SHP转3D Tiles两个方向一条管线倾斜摄影建模讨不讨好就看能不能被 Cesium 一类的 Web 引擎直接吃进去原生的 OSGB 目录结构和 SHP 矢量文件谁都没法在浏览器里直接调度。反直觉的是看起来更轻的 SHP 转换往往比倾斜摄影更容易翻车矢量数据要自己决定高度、自己处理坐标系、自己设计属性承载而倾斜摄影的转换工具已经替你干完了大部分重活。下面把两条线拆开讲倾斜摄影走 OSGB→b3dm 的切片管线SHP 走 shp→GeoJSON→拉伸体→b3dm 的属性化管线最后合并进同一场景。适合 GIS 开发、三维可视化工程师和数据生产人员照着搭也适合正在评估转换工具的团队用来判断哪条路适合自己。2. 倾斜摄影转3D Tiles工具选择、LOD思路与三个必调参数2.1 先看清 OSGB 目录里到底有什么倾斜摄影成果不是孤立的一个模型文件而是一棵按空间格子组织的瓦片树。磁盘上最常见的长相是这样的Data/ Tile_000_000/ Tile_000_000.xml Tile_000_000.osgb Tile_001_000/ Tile_001_000.xml Tile_001_000.osgb每个 Tile 文件夹里的 XML 记录该瓦片的包围盒和子瓦片引用OSGB 本体是带 LOD 的二进制场景图。转换工具做的第一件事就是遍历这棵树把每个节点的三角网和纹理拆出来再按 3D Tiles 的需求重建索引。这个过程的计算量不在建模本身而在纹理压缩和顶点重排所以转换耗时基本和三角面数量线性相关也和纹理尺寸直接挂钩。2.2 用现成工具跑通最小转换命令倾斜摄影转 3D Tiles 的成熟工具链里开源侧常见 osgb23dtiles商业侧常见 CesiumLab 和 SuperMap iServer。它们转换思路一致以 OSGB 的 Data 目录为输入输出一块一块的 b3dm 瓦片和一个 tileset.json。本地机器的典型命令长这样osgb23dtiles -i /data/Terrain/Data -o /output/terrain_3dtiles \ --threads 8 --max-level 12 --min-level 3 \ --texture jpg --georeference epsg:4547参数含义如下-i指向含 XML 的 Data 目录不是上一级工程-o指定输出目录--threads控制 CPU 并发16 核机器建议 812--max-level和--min-level是保留的 LOD 层级区间--texture jpg把 png 纹理重压成 jpg 以缩小体积--georeference传入源数据坐标系转换时把地方坐标换算到目标框架。各家工具参数名有差异但语义基本就是这五个维度。提示第一次跑不要直接用全量数据裁一个小区块先看输出等 tileset.json 能正常加载再放开范围否则排错时间都花在加载等待上。2.3 LOD、纹理和坐标三个必调点LOD 层级决定了最高精度的抽稀程度。城市级大范围数据如果保留到 15 级以上单瓦片三角形数虽少但瓦片数量会爆炸渲染调度压力大812 级用于城市远景已经够用。实际取舍参考下表使用场景max-level单瓦片纹理说明全市域底图1012512×512首屏加载快拉近略糊重点片区详查15182048×2048细节好瓦片数量多移动端10256×256兼顾流量和帧率纹理会占掉大半输出体积。能把 80% 场景控制在 512 纹理整个目录体积能比默认小一半以上代价是近距离贴图模糊。克制的做法是近地细节单独保留一层高清其余全部降采样。坐标系是最隐蔽的坑。输出 tileset.json 后打开根节点看 transform 的平移部分如果数值是几十万、几百万那种大数说明源数据是投影坐标Cesium 默认按 WGS84 经纬度解释模型会飞到海里。解决办法是转换时指定--georeference或在输出后修改 tileset.json 中 transform 的平移值为当地经纬度弧度值。肉眼判断错位的标准是加载后模型离地球表面几百公里优先怀疑坐标系而不是数据范围如果偏差只有几米通常要检查投影带中央经线是否写对。3. SHP转3D Tiles从面到体的四步流水线3.1 为什么 SHP 不能直接进 3D TilesSHP 是二维要素集3D Tiles 里的 b3dm 是三维网格加属性表。二者的语义差SHP 只有边界线和属性没有任何高度和厚度的概念。所谓 SHP 转 3D Tiles本质上是用软件替它补齐几何语义给了高度面变成柱体给了符号点变成标签给了贴地线变成地面 polyline。所以转换前必须先回答三个问题哪个字段当高度底座落在哪属性传给谁。3.2 处理 SHP 的最小 Python 流水线在本地把 SHP 转成后续工具能认的 GeoJSON是最灵活的一条路。下面这段代码覆盖读、转坐标、清洗、写出的完整过程import geopandas as gpd gdf gpd.read_file(parcels.shp, encodingutf-8) # 统一到 WGS84避免输出文件里混着投影坐标 if gdf.crs and gdf.crs.to_epsg() ! 4326: gdf gdf.to_crs(EPSG:4326) # 清理空几何和无效记录不然后面会生成破洞 gdf gdf[~gdf.geometry.is_empty gdf.geometry.is_valid] gdf.to_file(parcels.geojson, driverGeoJSON)重点在to_crs(EPSG:4326)和is_valid过滤很多 shp 多边形自相交直接拉伸会在三维里产生飞面和重影清洗后再转换能在源头消灭问题。属性字段在 GeoJSON 里原样保留后面的 Batch Table 就靠它们。字段较多的原始 shp 建议先做一层取舍把无关 CAD 属性丢掉减少生成时 batch 表体积这一步也能顺手把中文属性名替换成英文键名。3.3 拉伸成体的几何运算获得 GeoJSON 之后把 Polygon 变成柱体的过程叫拉伸。高度来自属性字段例如楼层数×3.0屋顶贴片厚度。核心几何运算如下def extrude_polygon(coords, height3.0): 把外环坐标拉伸成体返回顶点和三角面索引 verts [[x, y, 0] for x, y in coords] [ [x, y, height] for x, y in coords ] faces [] n len(coords) for i in range(n - 1): a, b i, (i 1) % (n - 1) faces.extend([ [a, a n, b n], [a, b n, b] ]) return verts, faces这段代码生成的是侧面顶底面需要单独处理实际使用中不要手写这一步交给支持 GeoJSON 拉伸的转换器或 Cesium ion 的 shp 导入通道更稳。脚本适合做批量预处理。生成体之后检查法线朝向拉伸体的面法线朝里在 Cesium 里看起来就是黑的最常见的表现是白模渲染成黑模。3.4 外边界提取、渔网分割和字段映射三个高频需求只保留外边界线是转换高频需求因为很多面带空洞和岛屿拉伸后模型内部交叠。取外环的写法import geopandas as gpd gdf_outline gpd.GeoDataFrame( geometrygdf.geometry.exterior, crsgdf.crs, datagdf.drop(columnsgeometry) ) gdf_outline.to_file(outline.geojson, driverGeoJSON)字段映射决定了属性能不能在 Cesium 里正常显示。GeoJSON 属性键名尽量用英文字段中文放值里否则某些引擎生成 Batch Table 时键名会乱码。具体映射关系可以整理成下表转换前逐项确认原始字段示例映射目标用途FID1021batchid唯一标识CENG6height拉伸高度USE住宅property弹窗属性JZRQ2021property档案字段遇到全市域、全省域范围时推荐先用渔网分割把大范围 SHP 按 1km×1km 或 5km×5km 格网切块逐块转换最后在 Cesium 里多个 tileset 并行加载。这样做的原因是超大 GeoJSON 单次转 b3dm 容易内存溢出切割后单文件加载时间从分钟级降到秒级也方便后续按分区更新数据。4. 倾斜模型和SHP白模合并层级组织与单体化属性4.1 为什么合并时要把两者分开加载倾斜摄影和 SHP 白模的体量与调度方式差异太大。倾斜摄影一个城市可能有几万个瓦片SHP 可能只有几百个要素放在同一个 tileset.json 里SHP 的瓦片会被按倾斜摄影的八叉树反复切分浪费存储且加载时机难控制。常见做法是两条 tileset 并列分别加载、分别控制显隐在业务层拼成一栋一栋可点选的数字孪生底座。各自加载的代码只有几行const osgbTiles await Cesium.Cesium3DTileset.fromUrl(/data/osgb/tileset.json); const shpTiles await Cesium.Cesium3DTileset.fromUrl(/data/shp/tileset.json); viewer.scene.primitives.add(osgbTiles); viewer.scene.primitives.add(shpTiles);分开加载还有个好处可以单独设置style例如让 SHP 白模半透明露出倾斜模型的地表纹理出问题时也能分别隐藏定位。4.2 SHP 数据做 Cesium 3D Tiles 单体化的关键单体化是 Cesium 3D Tiles 里被问得最多的场景。前提是 b3dm 里有 batch 表把每个楼对应的三角面索引和一个属性 id 绑起来。SHP 转 3D Tiles 时要素的唯一标识字段会被写入 batchid点击拾取时Cesium 通过 batchid 反查属性。最简单的拾取代码如下const handler new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); handler.setInputAction(function (movement) { const picked viewer.scene.pick(movement.position); if (Cesium.defined(picked)) { const ids picked.id.getPropertyIds(); console.log(ids.length, ids); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK);如果这里拿不到属性优先检查 batch 表生成环节如果拿到但高亮面不完整检查 glTF 的 batchid 是否覆盖全部三角面。这条链路就是点选楼栋弹属性窗的核心数字孪生平台里几乎必改。4.3 两种数据的 LOD 层级匹配合并后要解决显示问题倾斜模型拉近时细节丰富SHP 白模拉近时会看到明显的直角和纹理缺失。让两者在视觉上统一常见做法是 SHP 白模不做多级 LOD直接一个层级靠maximumScreenSpaceError控制切换倾斜模型保留 812 级 LOD。这样远景时白模自动简化近景时白模顶住细节不会出现两套 LOD 互相打架的闪烁。参考设置如下数据类型LOD 策略maximumScreenSpaceError适用阶段倾斜模型812 级810正式发布SHP 白模单层16调试单体化4.4 高度基准不一致时的处理SHP 拉伸体的高度基准如果和倾斜摄影不一致最常见的现象是楼体悬空或陷入地表。处理习惯按倾斜模型先行SHP 后置先转完倾斜摄影再从倾斜模型中采样地面高程把采样结果回填到 SHP 属性字段再执行拉伸。采样点按每栋楼 35 个点取平均比单点可靠数据量大时按网格聚合采样避免在每栋楼上都算一遍。没有 DEM 时也可以从倾斜模型点云抽但抽出的点要平滑否则屋顶和地面会出现阶梯状破面。5. 出图前的验证技巧包围盒、属性拾取与遮挡缝隙5.1 用调试开关快速定位飞包与错位拿到转换结果后先用空页面只加载 tileset打开debugShowBoundingVolume做初步体检tileset.debugShowBoundingVolume true; tileset.debugShowContentBoundingVolume true;绿色包围盒分布均匀说明瓦片树层级正确某块包围盒远离主体说明该瓦片 transform 错误包围盒互相穿插严重说明 LOD 层级没切分好。调试完记得把这两个值设回 false否则会产生额外 draw call拉低帧率。5.2 属性拾取与单体化的自测方法自测单体化时写一个拾取函数把每次点击到的属性和 batchId 打印出来viewer.screenSpaceEventHandler.setInputAction(function (click) { const picked viewer.scene.pick(click.position); if (Cesium.defined(picked)) { console.log(picked.id.batchId, picked.id.getPropertyIds()); } }, Cesium.ScreenSpaceEventType.LEFT_CLICK);测试覆盖 5 个片区每片点 10 栋样本要包含边界、空洞和转角楼。个别栋点不出属性大概率是 batchid 索引对不齐全部点不出问题在 Batch Table 本身或 glTF 里没写 batchid。用这个结论做排查能省掉大量来回沟通。5.3 晃动缝隙与单体化高亮的一处优化最后处理缝隙问题SHP 白模与倾斜模型之间容易露缝尤其在屋檐外挑处。处理技巧是给白模侧面做 0.20.5 米内缩使白模边缘略微收进倾斜模型内部视觉上不见缝也不会因面片重叠产生明显闪面。调整量用属性表加一个inset字段控制不写死在代码里。配合渔网分割的增量更新策略每次只重建变化区域的白模瓦片保留其他区域不动。全部调整完成后在目标机器上做一次多分辨率访问测试分别记录 2km、500m、50m 三个视距下的 FPS 和请求量把 50m 视距下 FPS 低于 30 的瓦片区域重新生成后再收尾上线。本文还有配套的精品资源点击获取