我写WebGIS也有两三年了,最开始呢是用Cesium去进行开发的。熟悉Cesium的人应该都或多或少有这样的想法吧:Cesium只是个玩具罢了。效率也不怎么样。所以在去年的时候我开始接触Mapbox。公司呢提出的需求更多的是偏向三维的。所以我就想尽办法去用Mapbox做特效。今天呢就先给我最近写的立体闪光墙分享出来,以后有空再陆续整理吧 。话不多说,先看效果。
我先唠叨几句啊哈哈哈。这个东西也没有多难,更多的是需要熟悉WebGL。大概呢就是Mapbox中的customlayer,大家可以看他的api,api中明确说明了onAdd和render方法。方法中内置了地图的 gl上下文。我对webgl不太熟悉,所以为了图方便,我选择了three.js
话不多说直接上代码
//设置点位
let positions = [] ;
//传入参数
let anypoint = [[114.58,28.61],[114.58,28.58],[114.64,28.60],[114.58,28.61]]
let height = 10000
let afterheight = 0 ;
let points =[];
//点位集合
anypoint.forEach((item:any)=>{
//使用mapbox自带的方法来转换坐标
points.push(mapboxgl.MercatorCoordinate.fromLngLat(item, 0));//转变坐标
})
for(let i = anypoint.length -1 ; i >=0 ; i--){
//把所有点位按顺序放入数组
points.push(mapboxgl.MercatorCoordinate.fromLngLat(anypoint[i], height))
//转换高度
afterheight = mapboxgl.MercatorCoordinate.fromLngLat(anypoint[i], height).z
}
//终点就是起点,将起点存入终点位置
points.push(mapboxgl.MercatorCoordinate.fromLngLat(anypoint[0], 0))
//0' <-1'
// | ^
// v |
//0=> 1
//大概顺序呢就是0=>1=>1'=>0'=>0 (画一面墙)
// points.push({x: 0.7890850166666666, y: 0.4106084487442257, z: 0} );
// points.push({x: 0.7911307583333334, y: 0.4146309617209688, z: 0});
// points.push({x: 0.7911307583333334, y: 0.4146309617209688, z: 0.028629787752927818});
// points.push({x: 0.7890850166666666, y: 0.4106084487442257, z: 0.028629787752927818});
// points.push({x: 0.7890850166666666, y: 0.4106084487442257, z: 0});
// let height = 0.028629787752927818
//处理点位数据,拆分三角面
for (let i = 0, j = positions.length, t = uvs.length; i < points.length-1; i++) {
let left = points[i]
let right = points[i + 1]
positions[j++] = left.x
positions[j++] = left.y
positions[j++] = 0
positions[j++] = right.x
positions[j++] = right.y
positions[j++] = 0
positions[j++] = left.x
positions[j++] = left.y
positions[j++] = afterheight
positions[j++] = left.x
positions[j++] = left.y
positions[j++] = afterheight
positions[j++] = right.x
positions[j++] = right.y
positions[j++] = 0
positions[j++] = right.x
positions[j++] = right.y
positions[j++] = afterheight
}
//开始创建形状
let geometry = new THREE.BufferGeometry()
geometry.addAttribute('position',new THREE.BufferAttribute(new Float32Array(positions), 3))
//创建图层
let WallLayer = {
id:'WallLayer01',//图层ID
type:'custom',//必须写详情看api
renderingMode:'2d',//同上
onAdd:(map:any,gl:any)=>{
//创建相机
let camera = new THREE.Camera();
//创建场景
let scene = new THREE.Scene();
//使用地图的gl上下文
let renderer = new THREE.WebGLRenderer({
canvas: map.getCanvas(),
context: gl,
antialias: true
})
//创建灯光
let light = new THREE.PointLight(0xfca4c5)
light.position.set(0, 250, 0)
scene.add(light)
// 创建材质 图自取 在下面
var texture = new THREE.TextureLoader().load(红色墙体材质);
// 设置阵列
texture.wrapS = THREE.RepeatWrapping;
texture.wrapT = THREE.RepeatWrapping;
// uv两个方向纹理重复数量
texture.repeat.set(1,3);
this.texture = texture
//设置材质
var material = new THREE.MeshBasicMaterial({
map: texture,
transparent:true,
});
//创建
let mesh = new THREE.Mesh(geometry, material)
//添加到场景
scene.add(mesh)
//设置不清楚canvas上其他内容
renderer.autoClear = false
//下面还会用到,我就直接用this了,你们也可以直接创建全局变量
this.camera = camera ;
this.scene = scene
this.renderer = renderer ;
this.matrtial = material;
this.mesh = mesh ;
this.map = map
},
render:(gl:any,matrix:any)=>{
//设置相机矩阵
var m = new THREE.Matrix4().fromArray(matrix);
this.camera.projectionMatrix = m
this.renderer.state.reset()
this.renderer.render(this.scene, this.camera)
this.map.triggerRepaint();
//设置纹理动画向上偏移
requestAnimationFrame(()=>{this.texture.offset.y -= 0.03 })
}
}
viewer.addLayer(WallLayer);
感谢以下各位所发文章
[1]:THREE shader实现高性能的动画(一)— 重复贴图箭头动画
[2]: Threejs纹理对象Texture阵列、偏移、旋转(纹理动画)
[3]: 感谢大哥的图,哈哈哈哈
小记:会写webgl的可以直接使用着色器,使用uv动画做。我也算是半个新手吧。有些错误的地方也很欢迎大家指出问题所在