1. 为什么说OpenStreetMapCityEngine是城市建模的“黄金搭档”如果你正在做自动驾驶仿真、城市规划或者任何需要快速搭建一个逼真3D城市模型的项目那你肯定对“找数据”和“建模”这两座大山深有体会。用传统建模软件一栋楼一栋楼地手搓那工作量想想都让人头皮发麻。今天我就来跟你分享一个我用了好多年的“作弊”组合OpenStreetMapOSM加上Esri CityEngine。这个组合说白了就是让你能用“拿来主义”快速搞出一个像模像样的3D城市把几个月的工作量压缩到几天甚至几小时。先简单认识一下这两位“主角”。OpenStreetMap你可以把它理解成地图界的“维基百科”一个由全球用户共同贡献和维护的免费开源地图数据库。它最大的魅力就是“自由”里面的道路、建筑轮廓、河流、绿地等地理数据你都可以合法地下载和使用。这解决了我们建模的“原材料”问题。而CityEngine则是Esri旗下的一款专业的3D城市建模软件。它最厉害的地方在于“程序化建模”你不用去手动捏每一个窗户、每一扇门而是通过编写或应用一套叫做“CGA规则”的脚本告诉软件“遇到住宅楼就按这个样式生成遇到商业建筑就按那个样式生成。” 这样一来你只需要提供建筑的二维轮廓也就是从OSM拿到的数据CityEngine就能像搭积木一样批量、自动地给你生成带纹理、带细节的3D模型。所以这个流程的核心思想就非常清晰了从OSM获取免费的二维地理数据作为“地基”然后利用CityEngine强大的程序化规则在这个“地基”上自动“生长”出三维城市。这个过程特别适合需要大范围、快速原型构建的场景。比如在自动驾驶仿真中你需要测试车辆在不同城市路网下的表现手动建模一个城市是不现实的用OSMCityEngine你可能一上午就能把北京五环内的路网和基础建筑都搭出来。再比如城市规划的初期方案展示你需要快速向客户呈现不同规划方案下的城市天际线变化这个组合也能让你在短时间内生成多个可对比的3D场景。2. 第一步从OpenStreetMap精准获取你需要的OSM数据万事开头难但获取OSM数据这一步其实相当简单。我们的目标是从OSM网站上把你感兴趣的那片区域的地图数据以.osm或.osm.xml格式下载下来。这个文件里就包含了我们后续需要的所有道路、建筑多边形、水系等矢量信息。2.1 官方导出最直接的方法最常用的方法就是直接上OpenStreetMap官网。打开网站后你可以直接在地图上找到你的目标区域。我习惯先搜索城市名定位到大致位置然后滚动鼠标滚轮放大。确定好范围后点击左上角的“导出”按钮。这时候地图上会出现一个可调整的矩形框。你可以用鼠标拖拽边框精确框选你需要的区域。这里有个非常重要的注意事项OSM官网的导出功能对区域大小是有限制的如果你框选的区域太大比如想导出一个省系统会直接拒绝提示你区域过大。对于城市级的建模我建议以行政区划为单位分块下载。比如你要做上海市的模型可以分“浦东新区”、“徐汇区”这样一块一块来导最后在CityEngine里合并。确定好范围后点击“导出”浏览器就会下载一个名为map.osm的文件。这个就是我们后续的“原料”。2.2 高级玩法使用Overpass API获取更定制化的数据如果你觉得官网的矩形框选不够灵活或者你需要筛选特定类型的数据比如只要主干道和高于10层的建筑那么你就需要用到OSM背后的强大查询引擎——Overpass API。这听起来有点技术性但其实有非常友好的图形化工具帮你比如Overpass Turbo。打开Overpass Turbo网站它的界面左边是一个查询语句编辑框右边是地图。你可以通过编写一种类似SQL的查询语言Overpass QL来精确抓取数据。别怕对于新手网站提供了大量预设模板。例如一个最简单的、获取某个矩形区域内所有建筑的查询语句是这样的[out:xml][timeout:25]; ( way[building]({{bbox}}); relation[building]({{bbox}}); ); out body; ; out skel qt;你不需要完全理解每一行只需要知道{{bbox}}代表地图上当前显示的范围。你在地图上缩放移动这个范围值会自动更新。点击“运行”后右侧地图就会高亮显示出所有建筑轮廓左边则会显示原始的OSM XML数据。确认数据无误后点击“导出” - “下载为OSM文件”即可。使用Overpass API的优势在于精细控制。你可以在查询语句中加入更多过滤条件比如way[highwaymotorway]只获取高速公路way[building:levels5]只获取5层及以上的建筑。这对于自动驾驶仿真特别有用你可以只导出道路网络和相关设施过滤掉不必要的植被、水系让数据更干净后续处理速度更快。3. 第二步将OSM数据导入CityEngine——避开第一个大坑拿到.osm文件后我们打开CityEngine准备开始“魔法”的第二步。打开CityEngine新建一个场景File - New - CityEngine scene。然后最直观的操作就是直接把那个.osm文件从文件夹拖拽到CityEngine的3D视图窗口里。这时CityEngine会弹出一个导入选项窗口。它会识别出OSM文件里的各种图层比如building、highway、water等。通常我们保持默认全选所有需要的图层点击“Finish”。紧接着最关键的一步来了CityEngine会弹出一个让你选择坐标系的对话框。这里就是新手最容易栽跟头的地方也是我当年踩的第一个大坑。3.1 坐标系问题为什么直接选WGS84会出错CityEngine会贴心地给出一些常用坐标系选项比如“WGS 1984 UTM Zone 50N”针对北京地区。很多朋友一看觉得这很专业啊我的OSM数据本来就是WGS84地理坐标系这里选对应的UTM投影坐标系合情合理。于是兴冲冲地选了然后点击“OK”。结果很可能迎来的不是一个3D场景而是一个红色的错误提示框内容大概是“Error: OSM data too large”或者类似的数据过大错误。你可能会疑惑“我在OSM上框的区域不大啊怎么就太大了呢”问题根源就在这里OSM数据使用的是WGS84坐标系单位是经纬度度。而CityEngine的3D场景工作单位是“工程单位”默认是米或英尺。当你把以“度”为单位的数据直接赋予一个以“米”为单位的投影坐标系时CityEngine会尝试进行坐标转换。对于小范围区域这个转换没问题但对于一个城市尺度的数据经度1度在地面距离上可能是几十公里到一百多公里。CityEngine内部在处理这种超大数值的坐标时可能会超出其计算精度范围从而报错。3.2 正确解法选择“Raw Data in Feet”或“Raw Data in Meters”解决这个问题的正确方法不是去选一个“正确”的投影坐标系而是告诉CityEngine先别做任何坐标系转换。在弹出坐标系选择对话框时请你毫不犹豫地向下滚动找到并选择“Raw Data (in Feet)”或者“Raw Data (in Meters)”。这两个选项的意思是将OSM文件中的原始坐标数值直接当作英尺或米来使用而不进行任何地理坐标变换。由于OSM的经纬度数值比如116.4, 39.9本身很小被当作米或英尺单位后它们在CityEngine场景中的位置就会聚集在一个很小的、合理的范围内原点附近几百米这样就完美避开了因坐标值过大导致的崩溃问题。这相当于我们把整个城市“平移”到了CityEngine的世界原点附近。虽然地理位置绝对坐标不对了你的模型不在真实的地球经纬度位置上了但这对于纯粹的3D建模和可视化来说完全没有影响。我们的所有建模、规则应用、导出操作都只关心模型之间的相对位置和几何关系而这些都被完整地保留了。如果你之前已经导入失败或者想修改现有场景的坐标系设置可以进入Edit - Preferences - Scene在“Default Coordinate System”中同样将其设置为“Raw Data (in Feet)”然后点击Apply。之后重新导入OSM数据即可。4. 第三步数据导入后的检查与清理成功导入后你会在CityEngine的“场景窗口”中看到一堆堆叠在一起的彩色形状块在“图层面板”里也会看到对应的图层。先别急着高兴我们还需要做一次“数据体检”。4.1 视觉检查与图层管理首先在3D视图里用鼠标中键旋转一下看看数据整体是否完整有没有明显的缺失或错位。然后打开图层面板你会看到类似building、highway、landuse等图层。你可以点击每个图层前面的眼睛图标单独显示或隐藏它们。我建议先关掉所有图层然后一个一个打开检查。比如先打开highway检查道路网络是否连通有没有奇怪的断头路或飞线。再打开building看看建筑轮廓是否都闭合有没有一些特别奇怪、扭曲的多边形。OSM是众包数据质量参差不齐。有时候建筑轮廓可能是一个点、一条线或者一个极其不规则的多边形这些“脏数据”会影响后续的规则生成。CityEngine对建模的基本要求是用于生成3D模型的二维形状必须是闭合的多边形。道路则通常是线状数据。4.2 常见数据问题与修复技巧在检查中你可能会遇到以下问题建筑轮廓不闭合有些建筑在OSM里可能只是一个面的一部分或者绘制有误。在CityEngine中你可以选中有问题的建筑形状使用菜单Shape - Cleanup Shape功能它能尝试自动修复一些简单的几何问题比如闭合未闭合的线。道路层级混乱OSM中的道路有详细的分类标签如motorway,trunk,primary,residential等。但在导入后它们可能都在一个图层里。为了后续方便对不同等级的道路应用不同的规则比如高速公路要建模高架和护栏小区路则不需要我们最好按属性分离图层。在图层面板中右键点击highway图层选择“Create Layer by Attribute”然后选择highway这个属性字段。CityEngine会自动为你生成motorway、primary、residential等多个子图层管理起来就清晰多了。冗余数据过多OSM数据可能包含很多我们不需要的要素比如tree单棵树、bench长椅等。这些对于宏观城市建模来说过于细节且会拖慢场景速度。你可以直接在图层面板中选中这些不需要的图层右键删除。做完这些清理工作我们的“地基”才算真正平整干净可以开始在上面“盖房子”了。5. 第四步施展魔法——使用CGA规则批量生成3D城市这是整个流程中最有趣、也最能体现CityEngine威力的部分。现在你的场景里只有一堆扁平的二维图形。我们需要给它们注入“灵魂”让它们变成三维的模型。这个灵魂就是CGA规则文件。5.1 初识CGA规则驱动的建模语言CGA是CityEngine专用的脚本语言语法相对直观。它的核心思想是“形状语法”。你从一个初始形状比如从OSM导入的建筑轮廓开始通过规则不断地对这个形状进行“切割”、“拉伸”、“替换”等操作最终生成复杂的几何体。一个最简单的规则例子让所有建筑轮廓随机长成一个3到10层高的方块。StartRule Lot -- extrude(rand(10, 30)) // 随机挤出10到30米的高度相当于3-10层将这段代码保存为一个.cga文件然后选中场景中的所有建筑地块building图层在检查器面板中点击“规则文件”旁边的文件夹图标选择你刚写的.cga文件瞬间所有的二维地块都变成了高低错落的方块楼5.2 应用现成规则库站在巨人的肩膀上当然我们没必要从零开始写所有规则。Esri官方和社区提供了大量高质量的现成规则库这才是快速建模的“法宝”。最常用的是“ESRI Lib”它内置在CityEngine的安装包中。应用方法很简单选中你的建筑图层在检查器面板的“规则”栏不要点选文件而是直接点击下拉箭头你会看到很多预置的规则包比如Building_From_Footprint.cga。选择它之后下面会出现一大堆参数可以调节比如BuildingHeight建筑高度、FacadeStyle立面风格、RoofType屋顶类型等等。你可以通过调整这些滑块一键改变整个城市的风貌。把建筑高度调高立面风格从“现代玻璃幕墙”换成“欧洲古典”屋顶从平顶换成坡顶……整个城市的面貌就在你指尖瞬间改变。这对于城市规划的方案对比演示来说效果极其震撼。5.3 编写自定义规则打造独特风格当你需要特定的建筑风格时就需要自己动手写规则了。比如我想生成底部有裙楼商业、上部是塔楼住宅的混合型建筑。规则可能会这样写StartRule Lot -- split(y){ 2 : CommercialFloor | ~10 : ResidentialTower } // 将地块在y方向分割底部2米是商业层剩余是住宅塔楼 CommercialFloor -- split(x){ ~1 : Facade | ~1 : Facade }* // 商业层分割出开间 color(#C0C0C0) // 灰色墙面 ResidentialTower -- split(y){ 3 : split(x){ ~1 : Balcony | ~1 : Window }* }* // 住宅塔楼每3米一层每层分割出阳台和窗户 color(#F5F5DC) // 米黄色墙面通过组合使用split分割、extrude挤出、comp组件分解等命令你可以创造出极其复杂的建筑形态。规则还可以读取OSM数据自带的属性比如用building:levels标签的值来决定建筑层数实现更真实的数据驱动建模。6. 第五步道路、绿化与场景整合建筑立起来了但城市不只是建筑的集合。道路、人行道、绿化带、街灯这些元素共同构成了生动的城市场景。6.1 道路网络生成对于highway图层CityEngine有强大的道路生成工具。选中道路图层点击菜单Graph - Create Streets from Lines可以将OSM的线状道路数据转换成CityEngine可编辑的道路网络图。然后你可以应用道路规则。在“ESRI Lib”中有Street_Modern.cga等规则。应用后道路会自动根据宽度属性OSM的width标签或默认等级生成带有车道线、路缘石、甚至简单绿化带的3D道路模型。更高级的玩法是使用“动态街道建模”。你可以手动绘制或编辑道路中心线然后CityEngine会根据你设定的道路横断面几个车道、多宽的人行道、有没有自行车道自动生成道路模型并同时分割出两侧的地块。这些新地块可以再自动分配建筑规则实现道路与建筑的联动生成。6.2 添加绿化与街道设施landuse图层中的grass、forest、park等区域可以应用绿地规则生成草地或随机分布的树木。CityEngine的植被生成器可以让你控制树的种类、密度、随机大小快速营造出公园或森林的感觉。街道设施如路灯、长椅、交通信号灯可以通过“实例化”的方式放置。你可以创建一个灯杆模型然后编写一条规则让道路规则在生成人行道时每隔一定距离就“实例化”放置一个灯杆模型。这样当你修改道路布局时路灯会自动沿新的人行道重新排列非常智能。6.3 场景优化与导出当所有元素都生成完毕一个初步的3D城市就诞生了。你可以在CityEngine里设置日光、调整材质、添加天空盒进行渲染出图。但更多时候我们需要把这个场景用到其他地方比如游戏引擎Unity, Unreal Engine或自动驾驶仿真平台如CARLA, LGSVL。CityEngine提供了丰富的导出选项。最常见的导出格式是FBX或OBJ这两种格式几乎被所有3D软件和引擎支持。在导出时你可以选择导出整个场景或者只导出选中的模型。一个关键的优化技巧是在导出前先对模型进行“烘焙”。在CityEngine中右键模型选择“Convert to Static Models”这会将程序化生成的模型转换为普通的静态网格可以大大减少导出文件的大小和复杂度提高在其他软件中的加载性能。最后别忘了保存你的CityEngine工程文件.cej它完整保存了所有OSM数据链接、规则分配和参数设置。下次你想修改城市风格只需要打开工程文件调整几个规则参数一个全新的城市就又出现了。这种非破坏性、数据驱动的建模流程正是OSMCityEngine组合在快速迭代和方案探索中无可比拟的优势。