高德地图自定义图层+regl实现发光多边形

642 阅读1分钟

企业微信截图_20221011182451.png 先看看效果图

实现多边形发光效果+中间半透明纹理

实现原理

使用高德GLCustomLayer自定义图层+webgl shader 渲染

主要发光算法比较简单就是当前的点到边线的距离

上代码

  var map = new AMap.Map('container', {
        center: [121.3435, 31.5120],
        zooms: [2, 20],
        zoom: 10.3,
        viewMode: '3D',
        mapStyle: "amap://styles/dark"
      //  pitch: 50,
    });


    var regl;
    var draw;
    // 数据转换工具
    var customCoords = map.customCoords;
    console.log(customCoords);
    // 数据使用转换工具进行转换,这个操作必须要提前执行(在获取镜头参数 函数之前执行),否则将会获得一个错误信息。
    let coords = [
        [116.52, 39.79],
        [116.56, 39.79],
        [116.56, 39.77],
        [116.52, 39.77],
    ];
    coords = suzhou;
    coords.forEach((coord,index) =>{
        // new AMap.Marker({
        //     content:'index'+index,
        //     position:coord,
        //     map,
        // })
    })
    var data = customCoords.lngLatsToCoords(coords);
    //data = [[0,0],[0,1],[1,1],[1,0]]
    let u_resolution = [document.body.clientWidth,document.body.clientHeight];
    let point_params = {};

    var texture = null;
    // 创建 GL 图层
    var gllayer = new AMap.GLCustomLayer({
        // 图层的层级
        zIndex: 100,
        // 初始化的操作,创建图层过程中执行一次。
        init: (gl) => {
            // var ext = gl.getExtension('OES_texture_float');
            // console.log(ext);

            // console.log(available_extensions);
            regl = createREGL({
                gl,
              //  extensions:['OES_texture_float'],

            });
            console.log(gl);
            const im = new Image();
            im.crossOrigin = "anonymous";
            im.src = "bg1.png";
            im.onload = function (){
                let points1  = data.map((item,index) => {
                    let next = data[index+1]?data[index+1]:data[0];
                    return [
                        item[0],
                        item[1],
                        next[0],
                        next[1],
                    ]
                })
              //  points1.push(...[-1,0,0,0])
                points1.forEach((p,index) =>{
                    point_params['colors['+index+']'] = p;
                })
                if(points1.length < 1000){
                    points1.push(
                        [-1,-1,-1,-1]
                    )
                }
                window.points1 = points1;
                draw = regl({
                    frag: `
                    precision mediump float;
                    uniform vec4 color;
                                    uniform mat4 mvp;
                                    uniform vec4 colors[1000];
     uniform sampler2D texture;
                     varying vec2 vUv;
                      uniform vec2 u_resolution;

float dist(vec2 pt1, vec2 pt2, vec2 testPt)
{
    if(dot(testPt - pt1,pt2-pt1) <=0.){
     return length(testPt - pt1);
    }
    if(dot(testPt - pt2,pt1-pt2) <=0.){
        return length(testPt - pt2);
     }
  vec2 lineDir = pt2 - pt1;
  vec2 perpDir = vec2(lineDir.y, -lineDir.x);
  vec2 dirToPt1 = pt1 - testPt;
  return abs(dot(normalize(perpDir), dirToPt1));
}
    void main() {

vec2 st =  gl_FragCoord.xy/u_resolution;
float  dis = 0.;

st =  gl_FragCoord.xy/u_resolution;

dis = 0.;
 for(int i=0;i<1000;i++){
if(colors[i].x == -1.0 && colors[i].y == -1.0){
    break;
}
  vec4 c_mvp = mvp * vec4(colors[i].xy, 0, 1);
 vec2 point = (c_mvp.xy/c_mvp.w+1.0)/2.0;

  vec4 c_mvp1 = mvp * vec4(colors[i].zw, 0, 1);
 vec2 point1 = (c_mvp1.xy/c_mvp1.w+1.0)/2.0;
point.x = point.x * u_resolution.x;
point.y = point.y * u_resolution.y;

point1.x = point1.x * u_resolution.x;
point1.y = point1.y * u_resolution.y;

  float dis_tmp = dist(point,point1,gl_FragCoord.xy);
        if(dis_tmp>0.){
           if(dis == 0.){
                dis = dis_tmp;
            }else{
                dis =  min(dis_tmp,dis);
            }

        }
 }


            if(dis > 15.){
                dis = 1.;
            }else {
                dis = smoothstep(0.,1.,dis/15.0);
            }


  vec4 c_mvp = mvp * vec4(colors[0].xy, 0, 1);
 vec2 point = (c_mvp.xy/c_mvp.w+1.0)/2.0;
 point.x = point.x * u_resolution.x;
point.y = point.y * u_resolution.y;

            vec4 vx = texture2D(texture,mod(gl_FragCoord.xy-point,64.)/64.);
            vec4 color = vec4(vx.xyz,.5);
            if(dis < 1.){
                color = vec4( .1,.88,.9, dis);
            }
             if(dis > 0.9 && dis < 1.0){
                color = vec4( .1,.88,.9, 1.0);
            }
                       gl_FragColor = color;
                    }`,
                    vert: `
                    precision mediump float;
                 uniform vec2 aspectRatio;
                 attribute vec2 position;
                 attribute vec2 uv;
                    varying vec2 vUv;
                    varying vec4 v_position;
                    uniform mat4 mvp;
                    void main() {
                        vUv = uv;
                        gl_Position = mvp * vec4(position, 0, 1);
                        v_position = gl_Position;
                        gl_PointSize = 40.;
                    }`,
                    attributes: {
                        position: data,
                        uv: regl.buffer([[0.0, 1.0,],[0.0, 0.0],[1.0,1.0],[1.0,0.0]]),
                    },
                    elements:earcut(data.flat()),
                    blend:{
                        enable: true,
                        func: {
                            srcRGB: 'src alpha',
                            srcAlpha: 1,
                            dstRGB: 'one minus src alpha',
                            dstAlpha: 1
                        },
                        equation: {
                            rgb: 'add',
                            alpha: 'add'
                        },
                        color: [0, 0, 0, 0]
                    },
                    //  primitive: 'points',
                    uniforms: {
                        color: [0.2, 0.4, 0.7, 1],
                        mvp: regl.prop('mvp'),
                        texture: regl.texture({
                            width :64,
                            height:64,
                            wrapS:'repeat',
                            wrapT:'repeat',
                            data:im,flipY:true
                        }),

                        ...point_params,
                        u_resolution:u_resolution,
                    },
                })

            }
        },
        render: () => {
            // 这里必须执行!!重新设置 three 的 gl 上下文状态。
            regl._refresh();
            if(draw){
                let mvpMatrix = customCoords.getMVPMatrix();
 
                draw({
                    mvp: mvpMatrix
                });
            }

        },
    });
    map.add(gllayer);

代码说明

主要核心代码: mvp是高德的视图矩阵,转成point的屏幕坐标,colors为边框数组

  vec4 c_mvp = mvp * vec4(colors[0].xy, 0, 1);
 vec2 point = (c_mvp.xy/c_mvp.w+1.0)/2.0;
 point.x = point.x * u_resolution.x;
point.y = point.y * u_resolution.y;