0
点赞
收藏
分享

微信扫一扫

Mapbox3D特效(立体闪光墙)

外贸达人小峻先森 2022-01-14 阅读 33

我写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动画做。我也算是半个新手吧。有些错误的地方也很欢迎大家指出问题所在


举报

相关推荐

0 条评论