在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文件加载;精细模型减少内部结构,保留表面减少模型实际大小等,在开发中再进行测试。

原文地址:https://www.cnblogs.com/googlegis/p/13963519.html