webgl绘制有几个关键节点?

102 阅读3分钟

接下来通过鼠标点击动态的在画布上添加点,以此了解webgl基础绘制的关键步骤

我们以main函数为切入点来逐个击破

image.png

initShader:初始化着色器

  • 参数vsSource和fsSource是什么?
    • vsSource是顶点着色器变量,下面是它的定义形式 image.png

    • fsSource是片元着色器变量,下面是它的定义形式 image.png

    • initShader函数 image.png 作用:

    1. 创建一个着色器程序对象
    2. webgl上下文启用program对象,将创建的着色器程序对象复制给webgl上下文的程序对象。

createProgram:创建着色器程序对象

image.png

  • 通过loadShader函数加载顶点着色器和片元着色器
  • gl.attachShader是将创建好的着色器attach到我们着色器程序上,然后调用gl.linkProgram方法将program整合起来。
  • getProgramParameter是为了验证program有没有整合成功,如果成功会返回程序对象的基本信息,否则整合失败,删除程序对象和创建的着色器。

loadShader:加载着色器

image.png

  • 参数分别代表gl上下文、着色器类型、着色器代码片段
  • 通过createShader创建一个着色器对象。
  • 通过shaderSource将着色器代码注入着色器对象。
  • 通过compileShader编译着色器对象。
  • 通过getShaderParameter来获取编译后的着色器基本信息,如果编译成功,返回着色器对象,否则删除创建的着色器对象。

☝☝☝以上内容,重要的第一步:初始化着色器程序对象就完成了,接下来我们还是回到main函数👇👇👇

找到着色器变量的存储地址

image.png

  • 参数分别为:着色器程序对象、变量名称。
  • getAttribLocation方法是为了找到着色器程序对象当中的着色器代码定义以attribute为存储限定符的变量的存储地址
  • getUniformLocation方法是为了找到着色器程序对象当中的着色器代码定义的以uniform为存储限定符的的变量的存储地址
  • getAttribLocation和getUniformLocation的区别在于前者用于顶点着色器,后者用于片元着色器。

给变量赋值

image.png

  • vertexAttribnf:其中n可以为1,2,3,4表示变量的个数。
  • 参数:第一个参数表示变量存储地址,后面参数表示变量(个数为n个)。

初始化面板,指定颜色

image.png

点击canvas面板,添加点

image.png

  • 参数解析:

    • ev:浏览器客户区
    • gl:webgl上下文
    • canvas:画布
    • a_Position:顶点位置存储地址
    • u_FragColor:片元颜色存储地址
  • 获取触发点相对浏览器可视区域左上角距离x,y image.png

  • 获取canvas原点的基本信息,rect.left和rect.top分别为canvas坐标原点距离浏览器左上角的距离。 image.png

  • 将触发点坐标转化成webgl的坐标 image.png

  • 剩下的部分其实就是比较简单的步骤,主要是根据不用的象限赋值不同的颜色,然后绘制点,就不细述了。 image.png

源代码片段,拿走不谢~~

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>2Dcanvas</title>
</head>

<body>
    <canvas id="canvas" width="400" height="400"></canvas>
    <script>
        var vsSource = `
            attribute vec4 a_Position;
            attribute float a_PointSize;
            void main() {
                gl_Position = a_Position;
                gl_PointSize = a_PointSize;
            }
        `;

        var fsSource = `
            precision mediump float;
            uniform vec4 u_FragColor;
            void main() {
                gl_FragColor = u_FragColor;
            }
        `;

        function initShaders(gl, vshader, fshader) {
            var program = createProgram(gl, vshader, fshader);
            if (!program) {
                console.log('Failed to create program');
                return false;
            }

            gl.useProgram(program);
            gl.program = program;

            return true;
        }

        /**
         * Create the linked program object
         * @param gl GL context
         * @param vshader a vertex shader program (string)
         * @param fshader a fragment shader program (string)
         * @return created program object, or null if the creation has failed
         */
        function createProgram(gl, vshader, fshader) {
            var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader);
            var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);
            if (!vertexShader || !fragmentShader) {
                return null;
            }

            var program = gl.createProgram();
            if (!program) {
                return null;
            }

            gl.attachShader(program, vertexShader);
            gl.attachShader(program, fragmentShader);

            gl.linkProgram(program);

            var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
            if (!linked) {
                var error = gl.getProgramInfoLog(program);
                console.log('Failed to link program: ' + error);
                gl.deleteProgram(program);
                gl.deleteShader(fragmentShader);
                gl.deleteShader(vertexShader);
                return null;
            }
            return program;
        }

        /**
         * Create a shader object
         * @param gl GL context
         * @param type the type of the shader object to be created
         * @param source shader program (string)
         * @return created shader object, or null if the creation has failed.
         */
        function loadShader(gl, type, source) {
            var shader = gl.createShader(type);
            if (shader == null) {
                console.log('unable to create shader');
                return null;
            }

            // Set the shader program
            gl.shaderSource(shader, source);

            // Compile the shader
            gl.compileShader(shader);

            // Check the result of compilation
            var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
            if (!compiled) {
                var error = gl.getShaderInfoLog(shader);
                console.log('Failed to compile shader: ' + error);
                gl.deleteShader(shader);
                return null;
            }

            return shader;
        }


        var g_points = [];
        var g_colors = [];

        function click(ev, gl, canvas, a_Position, u_FragColor) {
            var x = ev.clientX;
            var y = ev.clientY;
            var rect = ev.target.getBoundingClientRect();
            x = ((x - rect.left) - canvas.height / 2) / (canvas.height / 2);
            y = (canvas.width / 2 - (y - rect.top)) / (canvas.width / 2);
            g_points.push([x, y]);
            if (x >= 0.0 && y >= 0.0) {
                g_colors.push([1.0, 0.0, 0.0, 1.0]);
            } else if (x < 0.0 && y < 0.0) {
                g_colors.push([0.0, 1.0, 0.0, 1.0]);
            } else {
                g_colors.push([0.0, 0.0, 1.0, 1.0]);
            }
            gl.clear(gl.COLOR_BUFFER_BIT);
            var len = g_points.length;
            for (var i = 0; i < len; i++) {
                var rgb = g_colors[i];
                var points = g_points[i];
                gl.vertexAttrib3f(a_Position, points[0], points[1], 0.0);
                gl.uniform4f(u_FragColor, rgb[0], rgb[1], rgb[2], rgb[3]);
                gl.drawArrays(gl.POINTS, 0, 1);
            }
        }

        function main() {
            var canvas = document.getElementById('canvas');
            if (!canvas) {
                return;
            }
            var gl = canvas.getContext('webgl');
            initShaders(gl, vsSource, fsSource);
            var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
            var a_PointSize = gl.getAttribLocation(gl.program, 'a_PointSize');
            var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
            gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
            gl.vertexAttrib1f(a_PointSize, 10.0);
            gl.clearColor(0.5, 0.5, 0.5, 1.0);
            gl.clear(gl.COLOR_BUFFER_BIT);
            canvas.onmousedown = function (ev) {
                click(ev, gl, canvas, a_Position, u_FragColor);
            }
        }

        main();
    </script>
</body>

</html>

以上内容为个人理解,仅用于学习记录,如有任何问题,请指正🤌🤌🤌