将多个 B3DM 文件合并成一个单一的 3D 模型(如 glTF、OBJ、FBX 等),需要提取每个 B3DM 中的模型数据并整合到同一坐标系中。以下是详细步骤和工具方案:
1. 核心流程
- 提取每个 B3DM 的 glTF/GLB 模型
- 合并所有 glTF 模型
- **调整坐标系(地理空间 → 局部坐标系)**
- **导出为单一格式(如 GLB、FBX)**
2. 具体步骤
步骤 1:批量提取 B3DM 中的 GLB 文件
使用 3d-tiles-tools
解包所有 B3DM 文件(参考前文批量处理脚本):
# 批量解包示例(Linux/macOS/Windows WSL)
for file in *.b3dm; do
3d-tiles-tools b3dmToGlb -i "$file" -o "${file%.b3dm}.glb"
done
步骤 2:合并多个 GLB 文件
方法 1:使用 Blender 手动合并
- 导入所有 GLB 文件 :
- 打开 Blender,依次点击
File > Import > glTF
,导入所有解包后的.glb
文件。
- 打开 Blender,依次点击
- 调整模型位置 :
- 如果 B3DM 模型原本位于不同地理坐标,需手动将它们移动到同一坐标系(可能需要 BlenderGIS 插件支持)。
- 合并网格 :
- 全选所有模型(
A
键),按Ctrl+J
合并为一个对象。
- 全选所有模型(
- 导出为单一文件 :
- 点击
File > Export
,选择目标格式(如 GLB、FBX)。
- 点击
**方法 2:编程合并(Python + pygltflib)**
from pygltflib import GLTF2
import numpy as np
import os
output_gltf = GLTF2()
merged_mesh = {"primitives": []}
for glb_file in os.listdir("output_glb"):
if glb_file.endswith(".glb"):
gltf = GLTF2().load(os.path.join("output_glb", glb_file))
# 提取模型数据并合并(需处理顶点、索引、材质等)
for primitive in gltf.meshes.primitives:
# 合并顶点、索引(需调整索引偏移)
merged_mesh["primitives"].append(primitive)
output_gltf.meshes = [merged_mesh]
output_gltf.save("merged_model.glb")
方法 3:使用 glTF Pipeline 工具
# 安装 glTF 工具链
npm install -g gltf-pipeline
# 合并多个 GLB 文件(需自定义逻辑)
gltf-pipeline -i model1.glb model2.glb -o merged.glb
3. 地理坐标对齐
若 B3DM 文件包含地理坐标(WGS84 经纬度),需将其转换为同一局部坐标系:
方法 1:BlenderGIS 插件
- 安装 BlenderGIS 插件。
- 导入 GLB 文件后,使用插件功能将模型从地理坐标移至原点:
- 选择模型,点击
BlenderGIS > Geo > Set Origin to Geometry
。
- 选择模型,点击
**方法 2:编程处理(PyProj)**
import pyproj
from pygltflib import GLTF2
transformer = pyproj.Transformer.from_crs("EPSG:4326", "EPSG:3857") # WGS84 → Web Mercator
gltf = GLTF2().load("model.glb")
positions = gltf.meshes.primitives.attributes["POSITION"]
# 将顶点坐标从经纬度转换为局部坐标(示例)
for i in range(len(positions)):
lon, lat, height = positions[i]
x, y = transformer.transform(lat, lon)
positions[i] = [x, y, height]
gltf.save("transformed_model.glb")
4. 优化合并后的模型
-
简化网格 :使用 Blender 的
Decimate
修改器减少面数。 -
合并材质:在 Blender 中合并重复材质,减少 Draw Call。
-
压缩纹理 :使用
glTF-Transform
工具压缩纹理:gltf-transform compress merged.glb compressed.glb
**5. 完整脚本示例(自动化合并)**
import os
from pygltflib import GLTF2
import numpy as np
def merge_glb(input_dir, output_path):
merged_gltf = GLTF2()
merged_vertices = []
merged_indices = []
index_offset = 0
for file in os.listdir(input_dir):
if file.endswith(".glb"):
gltf = GLTF2().load(os.path.join(input_dir, file))
for primitive in gltf.meshes.primitives:
# 提取顶点和索引
vertices = gltf.get_data_from_accessor(primitive.attributes["POSITION"])
indices = gltf.get_data_from_accessor(primitive.indices)
# 合并数据
merged_vertices.extend(vertices)
merged_indices.extend([idx + index_offset for idx in indices])
index_offset += len(vertices)
# 创建新 GLB
merged_gltf.add_mesh(vertices=merged_vertices, indices=merged_indices)
merged_gltf.save(output_path)
merge_glb("output_glb", "merged_model.glb")
6. 注意事项
- 坐标一致性:确保所有模型在合并前处于同一坐标系,否则会出现位置错乱。
- 内存限制:合并极大规模模型可能导致内存不足,建议分批处理。
- 属性保留 :合并后可能丢失 B3DM 的批量属性(如
BATCH_ID
),需提前提取。
通过上述方法,您可以将多个 B3DM 文件合并为一个通用 3D 模型文件。如果需要处理地理坐标或优化性能,建议优先使用 Blender 或 Python 脚本。