2022-11-02 webgl绘制圆形点

一、原理

1.绘制圆形点,计算到圆心的距离


image.png

2.绘制球背面剔除

  //开启背面剔除
  gl.enable(gl.CULL_FACE)

3.开启多边形偏移解决球遮挡点问题


image.png

二、效果

image.png

三、代码

 //顶点着色器
    var VSHADER_SOURCE = /*glsl*/`
        attribute vec2 a_Uv;
        attribute vec4 a_Position;
        uniform mat4 u_MvpMatrix; 
        varying vec2 v_Uv;

        void main(){ 
            vec4 clip_Position=u_MvpMatrix*a_Position;
            gl_Position=clip_Position;
            v_Uv=a_Uv;

        }`;

    //片元着色器
    var FSHADER_SOURCE = /*glsl*/`
        #ifdef GL_ES
        precision mediump float;
        #endif
        uniform sampler2D u_Texture;
        
        varying vec2 v_Uv;

        void main(){
          
            vec4 baseColor=texture2D(u_Texture,vec2(fract(1.00-v_Uv.x),v_Uv.y));
          
            gl_FragColor=baseColor;
       
        }`;


    var point_VShader =/*glsl*/`
        attribute vec3 a_Position;
        uniform mat4 u_ViewMatrix;
        uniform mat4 u_ProjectMatrix;
        void main(){
            gl_Position=u_ProjectMatrix*u_ViewMatrix*vec4(a_Position,1.0);
            gl_PointSize=10.0;
        }
    `


    var point_FShader =/*glsl*/`
     #ifdef GL_ES
        precision mediump float;
        #endif
        void main(){
            float dist=distance(gl_PointCoord,vec2(0.5));
            if(dist>0.5){
                discard;
            }
            gl_FragColor=vec4(1.0,0.0,0.0,1.0);
        }
    `

    //声明js需要的相关变量
    var canvas = document.getElementById("canvas");
    var gl = getWebGLContext(canvas);
    //设置视角矩阵的相关信息(视点,视线,上方向)
    var viewMatrix = new Matrix4();



    //设置透视投影矩阵
    var projMatrix = new Matrix4();
    projMatrix.setPerspective(30, canvas.width / canvas.height, 0.1, 10);

    const rotateViewMatrix = new Matrix4()


    let value = 4

    var currentAngle = [0, 0]

    var program, pointProgram
    async function main() {
        if (!gl) {
            console.log("你的浏览器不支持WebGL");
            return;
        }

        program = createProgram(gl, VSHADER_SOURCE, FSHADER_SOURCE)

        if (!program) {
            console.error('创建着色器程序失败')
            return
        }

        gl.program = program
        gl.useProgram(program)

        getVariableLocation()

        //绘制球形
        const sphereGeometry = new SphereGeometry(gl, 1, 180, 90)
        const sphere = sphereGeometry.create()
        //绘制纹理
        const texture = Texture2D.initTexture(gl, './image/earth.jpg', 0)

        pointProgram = createProgram(gl, point_VShader, point_FShader)
        if (!pointProgram) {
            console.error('创建点着色器失败!')
            return
        }
        gl.program = pointProgram
        gl.useProgram(pointProgram)

        getVariableLocation()

        const arr = []

        cities.forEach(city => {
            const p = Cartertion3FromDegrees(1, city.value[0] * 1, city.value[1] * 1, 0)
            arr.push(p.x, p.y, p.z)
        })

        // const p1=Cartertion3FromDegrees(1,116,40,0)
        // const p2=Cartertion3FromDegrees(1,-100,40,0)
        const data = new Float32Array(arr)

        //

        // console.log(p,p1,p2)
        const point_positionBuffer = initArrayBuffer(gl, data, 3, gl.FLOAT, gl.position)



        //

        var tick = function () {
            //设置底色
            gl.clearColor(0.0, 0.0, 0.0, 1.0);
            viewMatrix.setLookAt(0, 0, value, 0, 0, 0, 0, 1, 0);
            rotateViewMatrix.setRotate(currentAngle[1], 1, 0, 0)
            rotateViewMatrix.rotate(currentAngle[0], 0, 1, 0)
            viewMatrix.multiply(rotateViewMatrix)

            draw(gl, sphere, point_positionBuffer)
            requestAnimationFrame(tick)
        }
        tick()


        registerMouseEvent()
    }

    /**
     * 
     * 注册鼠标事件
     * */
    function registerMouseEvent() {
        //是否按下
        let isDown = false
        let last_X = 0, last_Y = 0
        canvas.onmousedown = function (e) {
            //获取当前鼠标位置
            const x = e.clientX, y = e.clientY
            //获取canvas边界范围
            const bound = e.target.getBoundingClientRect()

            if (bound.left < x && bound.right > x && bound.top < y && bound.bottom > y) {

                last_X = x
                last_Y = y
                isDown = true
            }

        }

        canvas.onmousemove = function (e) {
            // console.log('鼠标移动',e)
            const x = e.clientX, y = e.clientY
            if (isDown) {

                const offset_X = x - last_X
                const offset_Y = y - last_Y
                currentAngle[0] += offset_X / 10
                currentAngle[1] += offset_Y / 10



            }
            last_X = x
            last_Y = y
        }


        canvas.onmouseup = function (e) {
            isDown = false

        }


        canvas.onwheel = function (e) {

            if (e.wheelDeltaY === 120) {
                value += 0.1
            } else {
                value -= 0.1
            }

        }
    }

    function draw(gl, sphere, point_positionBuffer) {

        gl.useProgram(program)
        gl.program = program
        //设置模型矩阵的相关信息
        var modelMatrix = new Matrix4();

        var mvpMatrix = new Matrix4()
        mvpMatrix.set(projMatrix)

        mvpMatrix.multiply(viewMatrix.multiply(modelMatrix));


        //将试图矩阵传给u_ViewMatrix变量
        gl.uniformMatrix4fv(gl.program.mvpMatrix, false, mvpMatrix.elements);

        //开启隐藏面清除
        gl.enable(gl.DEPTH_TEST);
        //开启背面剔除
        gl.enable(gl.CULL_FACE)
        //开启多边形偏移
        gl.enable(gl.POLYGON_OFFSET_FILL)
        //计算偏移量
        /*
        void WINAPI glPolygonOffset(
            GLfloat factor,
            GLfloat units
        );
        */
        gl.polygonOffset(5.0, 1.0)

        //清空颜色和深度缓冲区
        gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);


        const arrayBuffers = sphere.arrayBuffers
        arrayBuffers.forEach(arrayBuffer => {
            if (arrayBuffer) {
                writeAttributeVariable(gl, arrayBuffer.attribute, arrayBuffer)
            }
        });

        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, sphere.indexBuffer);

        const length = sphere.length

        //绘制图形
        gl.drawElements(gl.TRIANGLES, length, gl.UNSIGNED_SHORT, 0);

        gl.useProgram(pointProgram)
        gl.program = pointProgram
        //将试图矩阵传给u_ViewMatrix变量
        gl.uniformMatrix4fv(gl.program.viewMatrix, false, viewMatrix.elements);
        gl.uniformMatrix4fv(gl.program.projectMatrix, false, projMatrix.elements);

        writeAttributeVariable(gl, point_positionBuffer.attribute, point_positionBuffer)
        gl.drawArrays(gl.POINTS, 0, 360)

    }



    function toRadian(degree) {
        return degree * Math.PI / 180
    }

    //经纬度转世界坐标
    function Cartertion3FromDegrees(r, lon, lat, height) {
        const theta = toRadian(90 - lat)
        const phi = toRadian(180 - lon)
        const x = r * Math.sin(theta) * Math.cos(phi)
        const y = r * Math.cos(theta)
        const z = r * Math.sin(theta) * Math.sin(phi)
        return { x, y, z }
    }

你可能感兴趣的:(2022-11-02 webgl绘制圆形点)