在maptalks中載入三維模型obj,fbx,glb
- 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模型開啟Wie
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檔案載入;精細模型減少內部結構,保留表面減少模型實際大小等,在開發中再進行測試。