在mapbox-gl过程中,当现有的图层无法所需要的效果的时候,可以尝试使用自定义图层去实现新的效果展示。
而要用mapbox-gl 实现自定图层,可以先了解官方对CustomLayerAPI的说明:
https://docs.mapbox.com/mapbox-gl-js/api/properties/#customlayerinterface
基于说明和案例我们可以了解到CustomLayer上可以以webgl的方式实现,也能够以html5 canvas形式去实现,官方分别提供了两个示例:
canvas渲染方式:
https://docs.mapbox.com/mapbox-gl-js/example/custom-style-layer/
webgl渲染方式:
https://docs.mapbox.com/mapbox-gl-js/example/custom-style-layer/
所以作为webgl常用框架的three.js也是可以作为CustomLayer的实现方式之一,下面便是通过结合three.js在mapbox gl 地图中添加圆柱体自定义图层。
// 当前圆柱体地理位置,及展示在three.js所需参数
var modelOrigin = [126.62085557479679, 45.744408841143745];
var modelAltitude = 0;
var modelRotate = [Math.PI / 2, 0, 0];
var modelScale = 5.41843220338983e-8;
let modelTransform = {
translateX: minemap.MercatorCoordinate.fromLngLat(modelOrigin, modelAltitude).x,
translateY: minemap.MercatorCoordinate.fromLngLat(modelOrigin, modelAltitude).y,
translateZ: minemap.MercatorCoordinate.fromLngLat(modelOrigin, modelAltitude).z,
rotateX: modelRotate[0],
rotateY: modelRotate[1],
rotateZ: modelRotate[2],
scale: modelScale
};
var customLayer = {
id: '3dmodel',
type: 'custom',
renderingMode: '3d',
onAdd: function (map, gl) {
// 添加圆柱体形状
let cylinder = new THREE.CylinderGeometry( 5, 5, 20, 32 );
// 添加材质
this.materials = new THREE.MeshBasicMaterial({
color: '#fdff6e',
side: THREE.DoubleSide,
});
this.cylinderMesh = new THREE.Mesh(cylinder, this.materials);
// 创建
this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
// 创建场景
this.scene = new THREE.Scene();
// 创建光线
var directionalLight = new THREE.DirectionalLight(0xffffff);
directionalLight.position.set(0, -50, 100).normalize();
this.scene.add(directionalLight);
// gltf加载器
this.scene.add(this.cylinderMesh);
// s获取Mapbox GL JS map canvas到three.js中
this.map = map;
this.renderer = new THREE.WebGLRenderer({
canvas: this.map.getCanvas(),
context: gl,
});
this.renderer.autoClear = false;
},
render: function (gl, matrix) {
// 矩阵坐标转换
var rotationX = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(1, 0, 0), modelTransform.rotateX);
var rotationY = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 1, 0), modelTransform.rotateY);
var rotationZ = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0, 0, 1), modelTransform.rotateZ);
var m = new THREE.Matrix4().fromArray(matrix);
var l = new THREE.Matrix4().makeTranslation(modelTransform.translateX, modelTransform.translateY, modelTransform.translateZ)
.scale(new THREE.Vector3(modelTransform.scale, -modelTransform.scale, modelTransform.scale))
.multiply(rotationX)
.multiply(rotationY)
.multiply(rotationZ);
this.camera.projectionMatrix.elements = matrix;
this.camera.projectionMatrix = m.multiply(l);
this.renderer.state.reset();
this.renderer.render(this.scene, this.camera);
//渲染
this.map.triggerRepaint();
}
};
map.on('load', function (params) {
map.addLayer(customLayer);
})
当然诸如three.js能实现的其他的三维效果,也可以在mapbox gl通过自定义图层添加到地图中。