契机
团队的项目有部分需求涉及到在城市规划和建设中数据的可视化展示,将设备、数据、城市区域等元素通过GIS形式的融合,呈现出较为吸引眼球的效果。
最近因项目需要,期望在地图上面叠加一层3D建筑模型。现有的团队技术框架是使用高德地图的GIS服务,因此需要在高德地图的基础上做文章,经过一番艰难的尝试最终实现如图所示的效果。
技术方案
高德地图确实提供了加载3D模型的一些方案,开发者可以调用api建立几何模型,或者使用高德自带插件GltfLoader加载自建的gltf模型。前者缺乏可视化编辑工具,仅适用于创建简单模型; 后者可适用于加载复杂的自建模型,如高德提供的例子JSAPI glTF模型。
我们可以使用专业的建模工具3DMax,C4D等导出obj文件,再将obj文件转换为gltf格式,然后再使用GltfLoader将模型加载到地图指定位置,之后不可避免地做些缩放、旋转、位置等调整以匹配到适合GIS地图的位置。
实现步骤
准备模型文件
这里以3DMax2016为例,将建模模型导出为.obj文件(附带.mtl材质文件和各种贴图文件),导出设置如图所示。再使用cesium.js官方提供的转换工具obj2gltf将obj文件转换为适合高德地图的gltf文件。
这其中有几个踩过的坑需要注意,否则有非常大的概率会出现模型无法加载或者加载后显示异常的情况:
1.高德地图似乎无法支持.tga格式的材质贴图,一旦模型中包含该贴图的路径,则加载后模型无法显示,因此在导出obj和mtl文件后务必将.tga格式的路径删除或转换成png格式;
2.导出的mtl文件内声明的所有贴图路径后缀名均为小写,比如.jpg,如果对应的贴图后缀名为大写即.JPG,需要将其修改与mtl文件声明的一致,否则部署后可能出现贴图无法获取的情况; 必须导出.gltf格式的文件,高德地图当前无法加载二进制格式.glb;
3.请使用以下指令导出.gltf文件,其中-t的作用是将导出的gltf文件于贴图文件拆分开,如果不添加-t参数的话将会导出一个以64base形式内嵌所有贴图的gltf文件,只有一个文件,而这个文件里面的贴图路径高德地图根本无法解析,加载失败且报出类似undefined的错误;
obj2gltf -i model.obj -o model.gltf -t
4.如果不想自己安装obj2gltf,也可以使用高德提供的转换工具,但仅支持上传5M以下的模型压缩包;
代码编写
1.初始化地图和图层
// 创建地图实例
var map = new AMap.Map("container", {
viewMode: '3D',
pitch: 60,
rotation: 11.4,
zoom: 16,
zooms:[3,20],
center: [113.533247, 22.794298],
mapStyle: 'amap://styles/grey',
showIndoorMap: false,
features:['bg','road','building']
});
// 环境光
map.AmbientLight = new AMap.Lights.AmbientLight([1,1,1],1);
// 平行光
map.DirectionLight = new AMap.Lights.DirectionLight([1,0,-0.5],[1,1,1],0.5);
// 创建Object3DLayer图层
var object3Dlayer = new AMap.Object3DLayer();map.add(object3Dlayer);
2.加载模型
var sourceList = [{
name: '棕榈水岸',
url: '../data/gltf/ns/zlsa/zlsa.gltf', //
position: [113.524818,22.792584],
scale: 7.3,
height: 0
},{
name: '供电局',
url: '../data/gltf/ns/gdj/gdj.gltf', //
position: [113.527976,22.796998],
scale: 7.3,
height: 0
}];
map.plugin(['AMap.GltfLoader'], function () {
loadModel()
})
// 加载模型
function loadModel () {
var gltfObj = new AMap.GltfLoader()
for (var i = 0; i < sourceList.length; i++) {
// 逐个加载模型
(function (count) {
var model = sourceList[count]
gltfObj.load(model.url, function (gltfObj) {
console.log('加载成功')
gltfObj.setOption({
position: new AMap.LngLat(model.position[0], model.position[1]), // 必须
scale: model.scale, // 非必须,默认1
height: model.height, // 非必须,默认0
scene: 0, // 非必须,默认0
})
gltfObj.rotateX(90)
gltfObj.rotateZ(0)
object3Dlayer.add(gltfObj)
})
})(i)
}
}
存在的问题
初次尝试加载了2.24平台公里的地块,大约16个模型,做出来的页面操作起来还是有卡顿。
看来高德地图对大型复杂的gltf模型的支持并不太友好,我在所有模型里随机挑了1个小区模型。如图所示,3万多个面,291个贴图,高德地图表示无法承受。查看了官方示例,其操作顺畅的原因应该是选用了相对优化的城市模型,模型贴图做了设计上的简化,和展UV处理,即将多个贴图合成一张;然而对于自建的建筑模型,当前并没有找到靠谱的自动展UV合并贴图方法,目前的优化手段只能删减模型细节和压缩贴图文件。
为此问题专门提工单给高德地图的客服人员,得到的答复貌似也是无法解决。看来需要等版本更新,在此之前,估计只能到其他技术平台寻找解决方案。