一、背景
做三维WebGIS开发的朋友们都知道,我们加载倾斜摄影模型,一般使用cesium加载3dtiles格式的数据很简单,官网和网上都有很多例子,这里也不再详细赘述。但是在使用cesium场景中我们会遇到这样一个问题,在加载整个球的时候其实是影响了性能的,在加载局部小场景的时候我们是不需要加载整个地球的,例如我们在做智慧园区的项目时候,基本上只关注园区及其周边范围。如果加载整个地球无疑对资源开销造成了一定的浪费,我们要尽可能的提升用户的体验,将流畅度提升至最大化。所以我们可以使用three.js来完成,如果单纯的只是用来展示three.js无疑是比较不错的选择,但是如果我们想做一些空间查询、空间分析的话,three就不行了。于是我就想到了mapbox,mapbox地图可以拖拽成一定的倾斜角度,形成2.5d的三维效果,加载渲染速度比cesium快多了,不是说cesium不好,在大场景使用中,cesium还是不错的选择。
使用mapbox中的customLayer,结合three很方便加载进来,mapbox官网例子。官网例子只给出了加载gltf格式模型,对于fbx、obj格式的模型可以仿照该例子同样可以加载进来,但是如果我想加载倾斜摄影模型,找了好久找到了mapbox+deck.gl解决方案,deck.gl官网例子
二、数据处理
对于倾斜摄影数据,大多数是osgb格式的,我们在cesium加载倾斜摄影模型,将数据处理成3dtiles加载进来非常方便。在mapbox中结合deck.gl中的Tile3DLayer也可以轻松加进来,处理成3dtiles格式,我们可以选择如下
推荐使用cesiumlab功能很强大,能处理各种数据,文章最后给大家提供了osgb格式的倾斜摄影模型数据,方便大家测试,能帮到大家我也很高兴,也欢迎交流讨论 QQ 1826356125
三、加载3dtiles
import { MapboxLayer } from "@deck.gl/mapbox"
import { TripsLayer,Tile3DLayer } from "@deck.gl/geo-layers"
import {Tiles3DLoader} from '@loaders.gl/3d-tiles'
const core_1 = require("@math.gl/core")
//添加cesium格式3dtiles
load3DTiles(layerConfig) {
let layer=new MapboxLayer({
id: layerConfig.id,
type: Tile3DLayer,
data: layerConfig.url,
loader: Tiles3DLoader,
onTileError: (err) => {
console.log(err)
},
onTilesetLoad: (tileset) => {
tileset.setProps({ maximumScreenSpaceError: 1 })
const { cartographicCenter, zoom } = tileset;
this.viewState = {
...this.viewState,
longitude: cartographicCenter[0],
latitude: cartographicCenter[1],
zoom
}
let viewState = this.viewState
//设置x、y、z偏移,有些倾斜摄影模型加载进来不在该位置
//需要进行位置的调整,但我在进行旋转、和比例缩放的时候不起作用
//欢迎来指正
let mMtx=new core_1.Matrix4().makeTranslation(1,1,-200)
tileset.modelMatrix=mMtx
this.map.jumpTo({
center: [viewState.longitude, viewState.latitude],
zoom: viewState.zoom,
//bearing: viewState.bearing,
//pitch: viewState.pitch,
});
}
})
return layer
}
let layer=load3DTiles({
id: "3dTiles-xxxxxx",
describe:"倾斜摄影",
url:'http://localhost:8084/3DModel/qxsy/tileset.json',
layerType: "3DTiles"
})
this.map.addLayer(layer)
最终效果
加载发现没有贴地,悬浮了一定高度
向下调整位置
let mMtx=new core_1.Matrix4().makeTranslation(1,1,-200) tileset.modelMatrix=mMtx
源码分析
在deck.gl例子中只给了加载CesiumIonLoader,在线的3dtiles,但是我们想加载自己部署发布的3dtiles,查看源码发现
Tiles3DLoader可以使用
MapboxLayer其实是对mapbox中的customLayer的进一步封装,实例化其实就是customLayer图层
mapbox-layer.js
import { getDeckInstance, addLayer, removeLayer, updateLayer, drawLayer } from './deck-utils';
export default class MapboxLayer {
constructor(props) {
if (!props.id) {
throw new Error('Layer must have an unique id');
}
this.id = props.id;
// mapbox中custom类型图层
this.type = 'custom';
// 3d模式
this.renderingMode = props.renderingMode || '3d';
this.map = null;
this.deck = null;
this.props = props;
}
// mapbox中添加图层触发盖事件 this.map.addLayer(layer)
onAdd(map, gl) {
this.map = map;
//实例化deck
this.deck = getDeckInstance({
map,
gl,
deck: this.props.deck
});
//addLayer → updateLayers
addLayer(this.deck, this);
}
onRemove() {
removeLayer(this.deck, this);
}
setProps(props) {
Object.assign(this.props, props, {
id: this.id
});
if (this.deck) {
updateLayer(this.deck, this);
}
}
render(gl, matrix) {
drawLayer(this.deck, this.map, this);
}
}
deck-utils.js
function updateLayers(deck) {
if (deck.props.userData.isExternal) {
return;
}
const layers = [];
let layerIndex = 0;
deck.props.userData.mapboxLayers.forEach(deckLayer => {
const LayerType = deckLayer.props.type;
// 实例化图层,本案例加载LayerType:Tile3DLayer tile-3d-layer.js
const layer = new LayerType(deckLayer.props, {
_offset: layerIndex++
});
layers.push(layer);
});
deck.setProps({
layers
});
}
tile-3d-layer.js
…
…
tileset-3d.js
相关下载及参考文档
demo代码下载
osgb格式倾斜摄影数据下载
链接:https://pan.baidu.com/s/1_FPxf1niJT2DoD7vGsdd-g
提取码:zwd3
最后打个广告吧,自己花了好几个月写了一个基于mapbox的gis框架,下载地址,能很方便大家学习,也很容易应用到gis展示的项目中,感兴趣加我QQ了解