- maptalks 是一個基於WebGL的三維地圖js庫,基於maptalks可以快速建立web三維地圖,加載各種地圖數據,生成對應的圖層,加載三維模型等。
- 地圖加載。maptalks支持標准的地圖數據類型,如GeoJson,TileServer等。
GeoJson格式是一種地理信息對象描述文件,可以是本地的,也可以存儲在遠程服務器上,其基本格式如下:
{ "type": "FeatureCollection", "name": "line0706", "crs": { "type": "name", "properties": { "name": "urn:ogc:def:crs:OGC:1.3:CRS84" } }, "features": [ { "type": "Feature", "properties": { "id": 26, "OID": 26, "PID": "1JS2036-1JS2037", "Shape_Length": 215.78135367381537, "linegj": 400.0, "linecz": "球墨鑄鐵" }, "geometry": { "type": "LineString", "coordinates": [ [ 117.139587450494673, 31.980963606892612 ], [ 117.141572764515146, 31.980002698897021 ] ] } }, { "type": "Feature", "properties": { "id": 27, "OID": 27, "PID": "1JS2037-1JS2038", "Shape_Length": 174.33523286131555, "linegj": 400.0, "linecz": "球墨鑄鐵" }, "geometry": { "type": "LineString", "coordinates": [ [ 117.141572764515146, 31.980002698897021 ], [ 117.143128167657636, 31.979157606398935 ] ] } }, { "type": "Feature", "properties": { "id": 28, "OID": 28, "PID": "1JS2038-AJS2720", "Shape_Length": 74.157593232456321, "linegj": 400.0, "linecz": "球墨鑄鐵" }, "geometry": { "type": "LineString", "coordinates": [ [ 117.143128167657636, 31.979157606398935 ], [ 117.143830270406454, 31.978859076104776 ] ] } }, { "type": "Feature", "properties": { "id": 29, "OID": 29, "PID": "1JS2039-DJS504", "Shape_Length": 116.76683212772929, "linegj": 400.0, "linecz": "球墨鑄鐵" }, "geometry": { "type": "LineString", "coordinates": [ [ 117.146490176708213, 31.977233403153686 ], [ 117.147518501281553, 31.9766498062083 ] ] } }, { "type": "Feature", "properties": { "id": 30, "OID": 30, "PID": "1JS2040-1JS2041", "Shape_Length": 346.5596390599348, "linegj": 400.0, "linecz": "球墨鑄鐵" }, "geometry": { "type": "LineString", "coordinates": [ [ 117.148207019802612, 31.976299944711535 ], [ 117.151189187226777, 31.974481644858205 ] ] } } ] }
可以看出,geoJson格式是在Json數據格式的基礎上增加了關於GIS的一些屬性描述信息,
如type:Feature表示是一個地理對象,properties表示對象的屬性值,geometry表示要描述的地理對象,
里面type:LineString表示類型是一個線段, coordinates 表示坐標,后面接着的數組表示一組坐標值,來表示起始點坐標位置。
ArcGISTileLayer:
let ArcGIS_Layer = new maptalks.ArcGISTileLayer('line', { visible: true, urlTemplate: 'http://127.0.0.1:6080/server/rest/services/line/MapServer', });
urlTemplate對應的值就是已經部署在ArcGIS服務器上的地圖服務地址。
- 三維模型。基於maptalks 有一個使用threejs開發 maptalks.threeLayer 庫,可以在maptalks中直接引用,在maptalks中加載三維模型,其實就是使用threejs加載三維模型。
常用的三維模型有以下幾種,obj,fbx,glb。使用同一個模型導出的三種文件格式大小如下圖:
從文件大小看,fbx和glb更有優勢。
使用Windows自帶的3D模型打開文件
obj模型一般情況下包含2-3個文件,obj,mtl,jpg(png), obj 為模型文件,mtl 和 jpg文件為材質文件,obj文件可以通過文本編輯器打開,可以看到里面指定了該obj文件對應的材質文件的名稱。其余的是在三維空間中繪制的點位置。
需要使用材質的位置則指定使用mtl文件中的材質名稱。
在mtl文件中,則可以看到該材質的名稱對應的參數
fbx文件和glb為二進制編碼后的文件,使用文本編輯器打開為亂碼。
從可讀性看,obj文件更占優勢。
- 使用maptalks.threelayer 加載三維模型
threejs針對obj、fbx、glb三種格式的三維模型有專門的示例,針對threejs加載,可以在其官網 https://threejs.org/examples 查看,這里專門講解maptalks 地圖中的加載。
首先,threejs 提供了用於專門解析模型的 js 文件,
需要注意的是:在使用的過程中,需要確認 maptalks.js, maptalks.threelayer.js, 與 OBJLoader.js,MTLLoader.js,FBXLoader.js,GLTFLoader.js所引用three.js 版本一致,否則會出現函數不兼容的情況,無法調用成功。
加載obj的方法為:
new THREE.MTLLoader(manager) .setPath('/js/symap/lib/maptalks/models/obj/ws/') .load('gs.mtl', function (materials) { materials.preload(); new THREE.OBJLoader(manager) .setMaterials(materials) .setPath('/js/symap/lib/maptalks/models/obj/ws/') .load('gs.obj', function (object) { object.traverse(function (child) { if (child instanceof THREE.Mesh) { child.scale.set(0.01, 0.01, 0.01); child.rotation.set(Math.PI * 1 / 2, Math.PI * 1 / 8, 0); } }); _this.getObject3d().add(object); const z = layer.distanceToVector3(50, 50).x; const position = layer.coordinateToVector3( coordinate, z ); _this.getObject3d().position.copy(position); }); });
加載 fbx 的方法為:
var loader = new THREE.FBXLoader(); loader.load('/js/symap/lib/maptalks/models/fbx/beng.fbx', function (object) { object.scale.set(0.002, 0.002, 0.002); object.rotation.set(-Math.PI * 1 / 2, -Math.PI * 1 / 2, 0); _this._mixer = new THREE.AnimationMixer(object); const action = _this._mixer.clipAction(object.animations[0]); if (title.indexOf("測試") > -1) { //速度不為0,顯示運轉 action.stop(); } else { action.play(); } object.traverse(function (child) { if (child.isMesh) { if (child.name == "bengke") { child.material.visible = false; } child.castShadow = true; child.receiveShadow = true; } }); _this.getObject3d().add(object); const z = layer.distanceToVector3(150, 150).x; const position = layer.coordinateToVector3( coordinate, z ); _this.getObject3d().position.copy(position); });
加載 glb 文件的方法為:
var gltfLoader = new THREE.GLTFLoader(manager); const dracoLoader = new THREE.DRACOLoader(manager); gltfLoader.setDRACOLoader(dracoLoader); gltfLoader.setPath('/js/symap/lib/maptalks/models/gltf/'); gltfLoader.load('gssb.glb', function (gltf) { var object = gltf.scene; object.scale.set(0.3, 0.3, 0.3); _this.getObject3d().add(object); object.traverse(function (child) { if (child instanceof THREE.Mesh) { //if (child.name == "bengke") { // child.material.visible = false; //} child.rotation.set(Math.PI * 1 / 2, 0, 0); child.scale.set(0.1, 0.1, 0.1); } }); const z = layer.distanceToVector3(150, 150).x; const position = layer.coordinateToVector3( coordinate, z ); _this.getObject3d().position.copy(position); _this._mixer = new THREE.AnimationMixer(object); var clip = gltf.animations[0]; _this._mixer.clipAction(clip.optimize()).play(); });
在glb的加載中,另外引用了一個 DRACOLoader.js 這是一個js庫可以在模型加載的過程中對模型進行壓縮。
踩坑記錄:
在3D軟件設計模型時,將模型放在(0,0,0)的位置,否則模型加載后不能出現在Scene中,或者不在代碼設定的位置上。
另外對比同一開發環境下單個模型的加載方式對比: 支持
不支持
待測
格式 |
大小 |
多文件 |
可讀性 |
加載速度 |
支持動畫 |
運行壓縮 |
預壓縮 |
備注 |
Obj |
17.36M |
![]() |
![]() |
30ms |
![]() |
![]() |
![]() |
|
fbx |
6.3M |
![]() |
![]() |
21ms |
![]() |
![]() |
![]() |
|
glb |
8.3 |
![]() |
![]() |
25ms |
![]() |
![]() |
![]() |
|
在此次測試中,從加載時間來看,fbx>glb>obj ,綜合網絡搜索結果,glb模型對其它三維GIS軟件(Cesium,CityEngine)的兼容性更好,所以在本項目中使用glb格式的三維模型文件。
下圖為在maptalks中加載的三維模型:
針對模型較大的問題,網上還有其它解決方法,比如DRACOLoader將模型壓縮為drc文件進行加載;大模型拆分小模型然后分別壓縮drc文件加載;精細模型減少內部結構,保留表面減少模型實際大小等,在開發中再進行測試。