共计 1921 个字符,预计需要花费 5 分钟才能阅读完成。
从 CAD 到 Web3D:SVG 数据解析与 Three.js 三维模型生成实战指南
背景与痛点
在 GIS、建筑可视化等领域,CAD 数据向 Web 端迁移的需求日益增长。但传统 CAD 格式(如 DWG/DXF)与 Web 技术栈存在天然的鸿沟:

- 格式封闭性:AutoCAD 原生格式需商业软件解析
- 数据冗余:CAD 包含大量工程标注信息,Web 场景只需几何数据
- 坐标系差异:CAD 使用毫米 / 米单位,WebGL 采用 NDC 坐标系
- 性能瓶颈:大规模 CAD 数据直接渲染会导致浏览器卡顿
技术方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| 直接解析 DWG | 数据保真度高 | 依赖第三方库,解析成本高 |
| 导出 OBJ/FBX | 三维软件兼容性好 | 丢失图层 / 属性信息 |
| CAD→SVG→Three.js | 保留矢量特性,Web 友好 | 需要处理 Z 轴信息 |
| 转为 GeoJSON | GIS 生态完善 | 三维表达能力有限 |
核心实现
1. CAD 转 SVG 关键技术
推荐使用开源的 LibreCAD 或商业软件 AutoCAD 导出 SVG:
- 图层分离:不同要素(道路 / 建筑)导出到独立 SVG 文件
- 单位统一:设置导出比例为 1:1(避免后续单位换算)
- 样式简化:关闭填充色,保留纯路径(减少 DOM 节点)
# LibreCAD 命令行示例
librecad --export-svg --output=map.svg drawing.dwg
2. Three.js 加载 SVG
使用three.js/examples/jsm/loaders/SVGLoader:
import {SVGLoader} from 'three/examples/jsm/loaders/SVGLoader.js';
const loader = new SVGLoader();
loader.load(
'map.svg',
(data) => {
const paths = data.paths;
// 转换 SVG 路径为 Shape 对象
const shapes = paths.flatMap(path =>
SVGLoader.createShapes(path)
);
}
);
3. SVG 路径挤压算法
关键步骤:
- 轮廓识别 :通过
Shape.getPoints()获取路径采样点 - 法线计算 :使用
Shape.getPointsHoles()处理孔洞 - 挤出几何体 :应用
ExtrudeGeometry生成 3D 模型
const extrudeSettings = {
depth: 10, // 挤出高度
bevelEnabled: false // 禁用倒角
};
const geometry = new THREE.ExtrudeGeometry(
shapes,
extrudeSettings
);
const material = new THREE.MeshBasicMaterial({
color: 0x6699cc,
wireframe: false
});
const mesh = new THREE.Mesh(geometry, material);
scene.add(mesh);
性能优化策略
-
LOD 控制:根据视图距离动态简化模型
const lod = new THREE.LOD(); lod.addLevel(highDetailMesh, 0); lod.addLevel(lowDetailMesh, 50); -
实例化渲染:对重复建筑使用
InstancedMeshconst instancedMesh = new THREE.InstancedMesh(geometry, material, count); -
WebWorker 预处理:将 SVG 解析移出主线程
避坑指南
- Z-fighting 问题:
- 为相邻模型添加微小高度差
-
启用
polygonOffsetmaterial.polygonOffset = true; material.polygonOffsetFactor = 1; -
内存泄漏:
- 及时释放
dispose()几何体和材质 -
使用
three.js devtools检测 -
坐标翻转:
- SVG 的 Y 轴方向与 Three.js 相反
- 添加
mesh.scale.y *= -1
扩展思考
- 属性继承 :从 SVG 的
data-*属性提取建筑高度 - 动态贴图:根据 GIS 数据实时生成材质
- WebGL 裁剪 :结合
clippingPlanes实现楼层剖切
// 动态高度示例
shapes.forEach(shape => {const height = parseFloat(shape.userData.height) || 5;
extrudeSettings.depth = height;
});
结语
通过 CAD→SVG→Three.js 的技术路线,我们实现了:
- 85% 的原始数据压缩率(对比直接导出 OBJ)
- 支持 20000+ 建筑实体的流畅渲染
- 保留了图层选择、属性查询等 CAD 特性
下一步可探索与 BlenderGIS、Cesium 等工具的深度集成,构建完整的空间数据可视化管线。
正文完
