zoukankan      html  css  js  c++  java
  • 初级入门 --- web GL绘制点

    万丈高楼平地起。

    01基础知识

    一、相关术语

    • 图元 :WebGL 能够绘制的基本图形元素,包含三种:线段三角形
    • 片元:可以理解为像素,像素着色阶段是在片元着色器中。
    • 裁剪坐标系:裁剪坐标系是顶点着色器中的 gl_Position 内置变量接收到的坐标所在的坐标系。
    • 设备坐标系:又名 NDC 坐标系,是裁剪坐标系各个分量对 w 分量相除得到的坐标系,特点是 x、y、z 坐标分量的取值范围都在 【-1,1】之间,可以将它理解为边长为 2 的正方体,坐标系原点在正方体中心。

    二、GLSL



    • gl_Position:内置变量,用来设置顶点的裁剪坐标系坐标,包含 X, Y, Z,W 四个坐标分量。顶点着色器接收到这个坐标之后,对它进行透视除法,即将各个分量同时除以 W,转换成 NDC 坐标,NDC 坐标每个分量的取值范围都在【-1, 1】之间,GPU 获取这个属性值作为顶点的最终位置进行绘制。
    • gl_PointSize:内置变量,用来设置顶点大小。只有在绘制图元是的时候才会生效。
    • gl_FragColor:片元(像素)颜色,包含 R, G, B, A 四个颜色分量,且每个分量的取值范围在【0,1】之间,GPU 获取这个值作为像素的最终颜色进行着色。
    • gl_FragColor:内置变量,用来设置像素颜色。
    • attribue 变量:只能在顶点着色器中定义。
    • uniform 变量:既可以在顶点着色器中定义,也可以在片元着色器中定义。
    • 最后一种变量类型 varing 变量:它用来从顶点着色器中往片元着色器传递数据。使用它我们可以在顶点着色器中声明一个变量并对其赋值,经过插值处理后,在片元着色器中取出插值后的值来使用。
    • vec4:4 维向量,包含四个浮点元素的容器类型,vec 是 vector(向量)的单词简写,vec4 代表包含 4 个浮点数的向量。此外,还有 vec2vec3 等类型,代表包含2个或者3个浮点数的容器。
    • precision:精度设置限定符,使用此限定符设置完精度后,之后所有该数据类型都将沿用该精度,除非单独设置。
    • 运算符:向量的对应位置进行运算,得到一个新的向量。
      • vec * 浮点数:vec2(x, y) * 2.0 = vec(x * 2.0, y * 2.0)。
      • vec2 * vec2:vec2(x1, y1) * vec2(x2, y2) = vec2(x1 * x2, y1 * y2)。
      • 加减乘除规则基本一致。但是要注意一点,如果参与运算的是两个 vec 向量,那么这两个 vec 的维数必须相同。


    GLSL 中 gl_Position 所接收的坐标所在坐标系是裁剪坐标系 ,不同于我们的浏览器窗口坐标系。所以当我们赋予 gl_Position 位置信息的时候,需要对其进行转换才能正确显示。


    三、JAVASCRIPT程序如何向连接着色器程序


    • createShader:创建着色器对象
    • shaderSource:提供着色器源码
    • compileShader:编译着色器对象
    • createProgram:创建着色器程序
    • attachShader:绑定着色器对象
    • linkProgram:链接着色器程序
    • useProgram:启用着色器程序


    四、JAVASCRIPT如何往着色器中传递数据


    • getAttribLocation:找到着色器中的 attribute 变量地址。
    • getUniformLocation:找到着色器中的 uniform 变量地址。
    • vertexAttrib2f:给 attribute 变量传递两个浮点数。
    • uniform4f:给uniform变量传递四个浮点数。


    五、WebGL 绘制函数


    • drawArrays: 用指定的图元进行绘制。

    gl.drawArrays 是执行绘制的 API,上面示例中的第一个参数 gl.POINTS 代表我们要绘制的是点图元,第二个参数代表要绘制的顶点的起始位置,第三个参数代表顶点绘制个数。


    六、WebGL 图元


    • gl.POINTS: 将绘制图元类型设置成点图元

    02代码

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>WebGL 绘制点</title>
    <script type="x-shader/x-vertex" id="vertexShader">
    //设置浮点数精度为中等精度
    precision mediump float;
    // 接收点在canvas坐标系上的坐标(x,y)
    attribute vec2 a_Position;
    // 接受canvas 的宽高尺寸
    attribute vec2 a_Screen_Size;
    void main(){
    //start 将屏幕坐标系转化为裁剪坐标(裁剪坐标系)
    vec2 position = (a_Position / a_Screen_Size) * 2.0 - 1.0;
    position = position * vec2(1.0, -1.0);
    gl_Position = vec4(position, 0.0, 1.0);
    //end 将屏幕坐标系转化为裁剪坐标(裁剪坐标系)
    //声明要绘制的点的大小。
    gl_PointSize = 10.0;
    }
    </script>
    <script type="x-shader/x-fragment" id="fragmentShader">
    //设置浮点数精度为中等精度
    precision mediump float;
    //接收 JavaScript 传过来的颜色值(RGBA)。
    uniform vec4 u_Color;
    void main(){
    //将普通的颜色表示转化为 WebGL 需要的表示方式,即将【0-255】转化到【0,1】之间。
    vec4 color = u_Color / vec4(255, 255, 255, 1);
    gl_FragColor = color;
    }
    </script>
    </head>
    <body>
    <canvas id="canvas"></canvas>
    </body>
    </html>
    <script>
    function createShaderFromScript(gl, mode, id) {
    // 获取着色器源码
    var shaderSource = document.getElementById(id).innerHTML;
    // 创建着色器对象
    var shader = gl.createShader(mode);
    // 将源码分配给着色器对象
    gl.shaderSource(shader,shaderSource);
    // 编译着色器
    gl.compileShader(shader);

    return shader;
    }
    function createProgram(gl, vertexShader, fragmentShader) {
    var program = gl.createProgram();
    // 将顶点着色器挂载在着色器程序上。
    gl.attachShader(program, vertexShader);
    //将片元着色器挂载在着色器程序上。
    gl.attachShader(program, fragmentShader);
    //链接着色器程序
    gl.linkProgram(program);

    return program;
    }

    var canvas = document.getElementById('canvas');
    var gl = canvas.getContext('webgl') || canvas.getContext("experimental-webgl");

    <!--region 创建着色器对象-->
    var vertexShader = createShaderFromScript(gl, gl.VERTEX_SHADER, 'vertexShader');
    var fragmentShader = createShaderFromScript(gl, gl.FRAGMENT_SHADER, 'fragmentShader')
    <!--endregion-->



    <!--region 创建着色器程序-->
    //创建着色器程序
    let program = createProgram(gl, vertexShader, fragmentShader);

    // 使用刚刚创建好的着色器程序
    gl.useProgram(program);
    <!--endregion-->

    //找到顶点着色器中的变量a_Position
    var a_Position = gl.getAttribLocation(program, 'a_Position');
    //找到顶点着色器中的变量a_Screen_Size
    var a_Screen_Size = gl.getAttribLocation(program, 'a_Screen_Size');
    //找到片元着色器中的变量u_Color
    var u_Color = gl.getUniformLocation(program, 'u_Color');
    //为顶点着色器中的 a_Screen_Size 传递 canvas 的宽高信息
    gl.vertexAttrib2f(a_Screen_Size, canvas.width, canvas.height);
    //存储点击位置的数组。
    var points = [];
    function randomColor(){
    return {
    r: Math.ceil(Math.random() * 255),
    g: Math.ceil(Math.random() * 255),
    b: Math.ceil(Math.random() * 255),
    a: Math.ceil(Math.random()),
    };
    }
    canvas.addEventListener('click',e=>{
    var x = e.pageX;
    var y = e.pageY;

    var color = randomColor();

    points.push({x,y,color});
    gl.clearColor(0, 0, 0, 1.0);
    //用上一步设置的清空画布颜色清空画布。
    gl.clear(gl.COLOR_BUFFER_BIT);

    for (let i = 0; i < points.length; i++) {
    let color = points[i].color;
    gl.uniform4f(u_Color, color.r, color.g, color.b, color.a);
    //为顶点着色器中的 a_Position 传递顶点坐标。
    gl.vertexAttrib2f(a_Position, points[i].x, points[i].y);

    // 绘制点
    gl.drawArrays(gl.POINTS, 0, 1);
    }
    })

    //设置清空画布颜色为黑色。
    gl.clearColor(0.0,0.0,0.0,1.0);
    //用上一步设置的清空画布颜色清空画布。
    gl.clear(gl.COLOR_BUFFER_BIT);

    </script>


    vec2 position = (a_Position / a_Screen_Size) * 2.0 - 1.0

    上面这句代码用来将浏览器窗口坐标转换成裁剪坐标,之后通过透视除法,除以 w 值(此处为 1 )转变成设备坐标(NDC坐标系)。这个算法首先将(x,y) 转化到【0, 1】区间,再将 【0, 1】之间的值乘以 2 转化到 【0, 2】区间,之后再减去 1 ,转化到 【-1, 1】之间的值,即 NDC 坐标

  • 相关阅读:
    把git项目放到个人服务器上
    关于fcitx无法切换输入法的问题解决
    博客变迁通知
    (欧拉回路 并查集 别犯傻逼的错了) 7:欧拉回路 OpenJudge 数据结构与算法MOOC / 第七章 图 练习题(Excercise for chapter7 graphs)
    (并查集) HDU 1856 More is better
    (并查集 不太会) HDU 1272 小希的迷宫
    (并查集 注意别再犯傻逼的错了) HDU 1213 How Many Tables
    (最小生成树 Kruskal算法) 51nod 1212 无向图最小生成树
    (并查集) HDU 1232 畅通工程
    (最小生成树 Prim) HDU 1233 还是畅通工程
  • 原文地址:https://www.cnblogs.com/yaoyinglong/p/12250865.html
Copyright © 2011-2022 走看看