美文网首页
webgl 学习笔记

webgl 学习笔记

作者: _旁观者_ | 来源:发表于2021-11-24 14:05 被阅读0次

    webgl 介绍

    区别
    • webgl 是在传统的html文件的系统上,添加了 GLSLes(主要是编写着色器的配置)
    • webgl通过 js赋值给着色器数据,着色器主要是编写绘制图形需要的配置项

    webgl 代码的主要部分和一些需要知道的概念介绍


    学习新语言,需要了解语法和一些概念,下面是我总结的一些东西

    着色器

    • 着色器是webgl 中的绘制图形的主要部分,每个着色器都是由顶点着色器 片元着色器组成
    • 顶点着色器 主要负责设置元素的位置信息,尺寸大小(还可以在着色器中添加一些逻辑判断,本质上着色器语法为 opengl 语法)
    • 片元着色器 用于设置物体范围内的颜色插值(以设置片元的颜色为标准,设置像素的颜色值)(还可以在着色器中添加一些逻辑判断,本质上着色器语法为 opengl 语法)
    // 最简单的代码片段参考
    // gl 中 定义变量的方法 attribute 和 uniform
    // attribute 定义的是和 顶点 着色器 相关的变量
    // uniform 定义的是 对于所有顶点 都相同的数据
    // attribute(存储限定符) vec4(类型) a_Position(变量)
    var VSHADER_SOURCE = 
      'attribute vec4 a_Position;\n' + // attribute 定义一个 数据类型为 vec4 变量 名称为 a_Position
      'void main() {\n' +
      '  gl_Position = a_Position;\n' + // 设置 位置坐标
      '  gl_PointSize = 10.0;\n' + // 设置尺寸大小
      '}\n'; 
    
    // Fragment shader program
    var FSHADER_SOURCE = 
      'void main() {\n' +
      '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // 设置片元着色器 填充颜色
      '}\n';
    

    缓冲区对象

    缓冲区作用

    个人认为缓冲区对象的主要作用: 一次性提取数据,提高数据的处理速度

    • 创建缓冲区对象的具体步骤
    1 创建缓冲区对象
    2 将缓冲区分配给对应需要的缓冲区类型(有多个缓冲区类型)
    3 给缓冲区对象中写入需要的数据
    4 把缓冲区和着色器中的变量绑定(可以理解为赋值)
    5 开启缓冲区的访问权限
    
    • 代码逻辑
    // 将多个顶点的数据  保存在缓存区对象中
    // 缓冲区传给 着色器
    function initVertexBuffers(gl) {
      var vertices = new Float32Array([
        0.0, 0.5,   -0.5, -0.5,   0.5, -0.5
      ]); // 定义数据
      var n = 3; // 点的个数
    
      // 1 创建缓冲区对象
      var vertexBuffer = gl.createBuffer();
      if (!vertexBuffer) {
        console.log('Failed to create the buffer object');
        return -1;
      }
    
      // 2 将缓冲区对象绑定到目标
      gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    
      // 3 向缓冲区对象写入数据
      // 参数3 的作用是 表示程序将如何使用存储在缓冲区对象的数据 (做优化操作)
      gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
    
      // 获取变量
      var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
      if (a_Position < 0) {
        console.log('Failed to get the storage location of a_Position');
        return -1;
      }
    
      /**
       * 4 把缓冲区和着色器中的变量绑定(可以理解为赋值)
       * 将缓冲区对象 分配给(赋值给) a_Position 变量
       * 参数含义
       * 参数1 a_Position 赋值的变量
       * 参数2 指定缓冲区中每个顶点的分量个数
       * 参数3 指定数据类型 gl.FLOAT 是其中一种类型
       * 参数4 表明是否将非浮点型数据 归一化成 [0,1] 或 [-1,1]
       * 参数5 指定相邻的两个顶点间的字节数
       * 参数6 指定从第几个数据位置开始(偏移数)
      */
      gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
    
      // 5 开启访问权限 
      //开启a_Position,为了使着色器能够访问 a_Position 变量
      // 连接 a_Position 变量 与分配给他的缓冲区对象
      gl.enableVertexAttribArray(a_Position);
    
      return n;
    }
    

    纹理映射

    纹理贴图.png
    纹理贴图的原理就是把把图片中对应的像素值(gaba) 映射到三维物体的表面
    • 创建纹理对象的具体步骤
    1 创建纹理对象
    2 开启纹理对象
    3 对纹理单元绑定 纹理对象
    4 设置纹理参数
    5 配置纹理图像 --> 将纹理图像分配给纹理对象
    6 将纹理单元赋值给着色器中的变量
    7 着色器变量 调用 texture2D 取出片元对应的颜色值
    
    • 代码具体实现
    // 1 创建一个纹理对象
    var texture = gl.createTexture();   
    // 2 开启 0号纹理单元
    gl.activeTexture(gl.TEXTURE0);
    // 3 向 EXTURE_2D 绑定纹理对象
    gl.bindTexture(gl.TEXTURE_2D, texture);
    // 4配置纹理参数 (设置样式)
    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
    // 5 配置纹理图像 --> 将纹理图像分配给纹理对象
    gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
    // 6 将 0 号纹理传递给着色器
     gl.uniform1i(u_Sampler, 0);
    
    //  创建片元着色器
    var FSHADER_SOURCE =
      // '#ifdef GL_ES\n' +
      'precision mediump float;\n' +
      // '#endif\n' +
      'uniform sampler2D u_Sampler;\n' + // 6 定义取样器 用来接收 纹理图
      'varying vec2 v_TexCoord;\n' +
      'void main() {\n' +
      '  gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' + // 6 提取纹理颜色值栅格化片元着色器
      '}\n';
    
    

    矩阵对象

    可以看做一系列变化关系的集合的统一表达方式(用于设置图形变换旋转、缩放,设置视图顶点坐标)

    平移矩阵.png
    • 用于表示 顶点位置、颜色数据、物体变化数据、视图投影矩阵等
    • 多个矩阵可以合并

    光线

    用于模拟现实场景下的光照因素

    • 光线分类
    1 平行光源(太阳)
    2 点光源(灯泡)
    3 环境光(物体周围均匀分布的光线)
    
    • 反射类型(光照下的物体表面颜色)


      漫反射.png
      环境光.png
      归一化.png
    1 漫反射计算: 漫反射 = 入射光线颜色*物体表面颜色*cos(a) 
    1 环境反射: 环境反射 = 入射光线颜色*物体表面颜色
    
    • 代码参考
    // 顶点着色器
    var VSHADER_SOURCE =
      'attribute vec4 a_Color;\n' + // 定义顶点的 颜色 变量
      'attribute vec4 a_Normal;\n' + // 定义法向量的变量、
      'uniform vec3 u_LightColor;\n' +     // 定义漫反射的光照颜色 变量
      'uniform vec3 u_LightDirection;\n' + // 定义漫反射的光照方向 变量
      'uniform vec3 u_AmbientLight;\n' +   // 定义环境光的变量
      'varying vec4 v_Color;\n' + // 要传给片元着色器的变量
      'void main() {\n' +
         // 计算 cos 值 = 漫反射的方向向量 * 法向量
      '  float nDotL = max(dot(u_LightDirection, a_Normal), 0.0);\n' +
         // 计算漫反射后的物体颜色
      '  vec3 diffuse = u_LightColor * a_Color.rgb * nDotL;\n' +
         // 计算环境光的物体颜色
      '  vec3 ambient = u_AmbientLight * a_Color.rgb;\n' +
         // 计算最终的物体颜色
      '  v_Color = vec4(diffuse + ambient, a_Color.a);\n' + 
      '}\n';
    
    // 片元着色器
    var FSHADER_SOURCE =
      '#ifdef GL_ES\n' +
      'precision mediump float;\n' + // 设置数据精度
      '#endif\n' +
      'varying vec4 v_Color;\n' +
      'void main() {\n' +
      '  gl_FragColor = v_Color;\n' +
      '}\n';
    
    

    视图矩阵

    由 观察者位置, 目标位置, 观察者上方向位置组成的 视图矩阵

    视图矩阵原理
    定义视图矩阵.png
    • 代码
    // 包括 观察者(x y z)坐标,目标点(x y z)坐标,观察者上方向(x y z)坐标
    viewMatrix.setLookAt(0.20, 0.25, 0.25, 0, 0, 0, 0, 1, 0); // 设置视图矩阵的api
    

    可视空间矩阵

    观察者可以看到区域范围,下面两个选择设置一个即可

    • 盒状可视空间


      盒状.png
    // 参数依次为 近裁剪面左边界、近裁剪面右边界、近裁剪面上边界、近裁剪面下边界、近裁剪面位置、远裁剪面位置
    projMatrix.setOrtho(-1.0, 1.0, -1.0, 1.0, g_near, g_far); // 设置盒装可视空间
    
    • 四棱锥/金字塔 可视空间(又叫透视投影矩阵)


      透视投影矩阵.png
      透视投影矩阵1.png
    // 参数依次是  可视空间的夹角(观察者顶面和底面的夹角),近裁剪面的宽高比,近裁剪面位置,远裁剪面的位置
    viewProjectionMatrix.setPerspective(30.0, canvas.width / canvas.height, 1.0, 100.0);// 设置透视投影矩阵(更真实,近处大 远处小)
    

    隐藏面消除功能

    gl.enable(gl.DEPTH_TEST);//开启隐藏面消除功能
    gl.clear( gl.DEPTH_BUFFER_BIT); // 清除深度缓冲区
    

    立体图形绘制

    立方体绘制原理.png
    webgl 没有提供绘制三维图形的方法,只能通过二维绘制的api来实现
    • 方法一 通过绘制多个三角形来拼成3d图形
      立方体6个面,每个面需要两个三角形来组成,所以需要的 定点数 =6(6个面) * 3(每个三角形需要3的顶点) * 2(每个面需要两个三角形)
      通过拼接三角形需要36个顶点
    • 方法二 通过 gl.drawElements() 方式索引顶点坐标来绘制立方体
      索引的方式来绘制立方体.png
      调用 gl.drawElements() 方法前需要做以下准备
      1创建 顶点坐标 并存放到 缓冲区中
      2 创建 顶点坐标对应的 索引坐标(通过索引坐标来获取顶点坐标来绘制3d图形)
      3 创建缓冲区 并绑定到 gl.ELEMENT_ARRAY_BUFFER 缓冲区类型上
      4 将 索引坐标 绑定到 gl.ELEMENT_ARRAY_BUFFER 缓冲区 上
      5 调用 gl.drawElements() 绘制3d图形
      下面是简单的代码逻辑
    
      // 1创建 顶点坐标 并存放到 缓冲区中
      // 将缓冲区对象 绑定到 gl.ARRAY_BUFFER
    // Create a cube
      //    v6----- v5
      //   /|      /|
      //  v1------v0|
      //  | |     | |
      //  | |v7---|-|v4
      //  |/      |/
      //  v2------v3
      var verticesColors = new Float32Array([
        // 8个顶点位置 和 颜色值
         1.0,  1.0,  1.0,     1.0,  1.0,  1.0,  // v0 White
        -1.0,  1.0,  1.0,     1.0,  0.0,  1.0,  // v1 Magenta
        -1.0, -1.0,  1.0,     1.0,  0.0,  0.0,  // v2 Red
         1.0, -1.0,  1.0,     1.0,  1.0,  0.0,  // v3 Yellow
         1.0, -1.0, -1.0,     0.0,  1.0,  0.0,  // v4 Green
         1.0,  1.0, -1.0,     0.0,  1.0,  1.0,  // v5 Cyan
        -1.0,  1.0, -1.0,     0.0,  0.0,  1.0,  // v6 Blue
        -1.0, -1.0, -1.0,     0.0,  0.0,  0.0   // v7 Black
      ]);
      var vertexColorBuffer = gl.createBuffer();
      var indexBuffer = gl.createBuffer();
      if (!vertexColorBuffer || !indexBuffer) {
        return -1;
      }
      gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
      gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
      var FSIZE = verticesColors.BYTES_PER_ELEMENT;
      var a_Position = gl.getAttribLocation(gl.program, 'a_Position'); // 获取 变量
      if(a_Position < 0) {
        console.log('Failed to get the storage location of a_Position');
        return -1;
      }
      gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
      gl.enableVertexAttribArray(a_Position);
      var a_Color = gl.getAttribLocation(gl.program, 'a_Color'); // 获取 变量
      if(a_Color < 0) {
        console.log('Failed to get the storage location of a_Color');
        return -1;
      }
      gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
      gl.enableVertexAttribArray(a_Color);
    
      // 2 创建 顶点坐标对应的 索引坐标(通过索引坐标来获取顶点坐标来绘制3d图形)
      // 这个就是索引坐标
      var indices = new Uint8Array([
        0, 1, 2,   0, 2, 3,    // front
        0, 3, 4,   0, 4, 5,    // right
        0, 5, 6,   0, 6, 1,    // up
        1, 6, 7,   1, 7, 2,    // left
        7, 4, 3,   7, 3, 2,    // down
        4, 7, 6,   4, 6, 5     // back
     ]);
    
      // 3 创建缓冲区 并绑定到 `gl.ELEMENT_ARRAY_BUFFER` 缓冲区类型上
      // 将缓冲区对象 绑定到 gl.ELEMENT_ARRAY_BUFFER(gl.ELEMENT_ARRAY_BUFFER 管理具有索引结构的三维数据模型)
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
      // 4 将 索引坐标 绑定到 `gl.ELEMENT_ARRAY_BUFFER` 缓冲区 上
      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
      // 5 绘制 立方体
      gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_BYTE, 0);
    

    通过 gl.drawElements 方法绘制 需要的是 8个顶点,相比第一种减少了数据的创建

    雾化

    雾化公式.png
    雾化因子.png

    基本开发流程

    • 创建着色器对象
    • 创建canvas元素,并获取canvas 的 dom 元素
    • 通过canvas 获取 webgl 的绘图上下文对象
    • 初始化着色器,包括设置着色器的 定点位置,颜色值,视图投影矩阵,向量矩阵,纹理对象,光线对象值等的设置(是webgl中的最重要的开发部分)
    • 设置canvas背景色
    • 清除canvas 中的颜色缓冲区和深度缓冲区
    • webgl 绘图(包含许多绘图api)


    代码案例


    • 案例1 通过js控制绘制元素的颜色,代码大致实现原理

    主要注意的是 可以通过 js 来动态赋值着色器中的变量

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Hello Point (2)</title>
      </head>
    
      <body onload="main()">
        <canvas id="webgl" width="400" height="400">
        Please use a browser that supports "canvas"
        </canvas>
    
        <script src="../../lib/webgl-utils.js"></script>
        <script src="../../lib/webgl-debug.js"></script>
        <script src="../../lib/cuon-utils.js"></script>
        <script>
          // 顶点着色器
          // gl 中 定义变量的方法 attribute 和 uniform
          // attribute 定义的是和 顶点 着色器 相关的变量
          // uniform 定义的是 对于所有顶点 都相同的数据
          // attribute(存储限定符) vec4(类型) a_Position(变量)
          var VSHADER_SOURCE = 
            'attribute vec4 a_Position;\n' + // attribute 定义一个 数据类型为 vec4 变量 名称为 a_Position
            'void main() {\n' +
            '  gl_Position = a_Position;\n' + // 设置 位置坐标
            '  gl_PointSize = 10.0;\n' + // 设置尺寸大小
            '}\n'; 
    
          // 片元着色器
          var FSHADER_SOURCE = 
            'void main() {\n' +
            '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + // 设置片元着色器 填充颜色
            '}\n';
    
          function main() {
            // 获取dom元素
            var canvas = document.getElementById('webgl');
    
            // 获取gl上下文对象
            var gl = getWebGLContext(canvas);
            if (!gl) {
              console.log('Failed to get the rendering context for WebGL');
              return;
            }
    
            // 初始化着色器 返回程序对象
            if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
              console.log('Failed to intialize shaders.');
              return;
            }
    
            // 拿到 gl 中定义的坐标 a_Position
            // 获取 attribute 存储变量的位置
            var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
            if (a_Position < 0) {
              console.log('Failed to get the storage location of a_Position');
              return;
            }
    
            // a_Position 赋值
            // 将 位置数据 传给 attribute 变量
            gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
    
            // 设置背景色
            gl.clearColor(0.0, 0.0, 0.0, 1.0);
    
            // 清空颜色缓冲区
            gl.clear(gl.COLOR_BUFFER_BIT);
              
            // 画图
            gl.drawArrays(gl.POINTS, 0, 1);
          }
        </script>
      </body>
    </html>
    
    
    • 案例2 通过缓冲区对象来设置顶点位置 颜色信息
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Draw Multiple Points</title>
      </head>
    
      <body onload="main()">
        <canvas id="webgl" width="400" height="400">
        Please use a browser that supports "canvas"
        </canvas>
    
        <script src="../../lib/webgl-utils.js"></script>
        <script src="../../lib/webgl-debug.js"></script>
        <script src="../../lib/cuon-utils.js"></script>
        <script>
          // Vertex shader program
          //  缓冲区对象 一次性的向着色器传多个顶点数据 
          /**
           * 创建缓存区对象 步骤
           * 1 创建缓存区对象 gl.createBuffer()
           * 2 绑定缓冲区对象 gl.bindBuffer()
           * 3 将数据写入缓冲区对象 gl.bufferData()
           * 4 将缓冲区对象分配给一个attribute变量 gl.vertexAttribPointer()
           * 5 开启attribute变量 gl.enableVertexAttribArray()
           * */ 
    
    
          var VSHADER_SOURCE =
            'attribute vec4 a_Position;\n' +
            'void main() {\n' +
            '  gl_Position = a_Position;\n' +
            '  gl_PointSize = 10.0;\n' +
            '}\n';
    
          // Fragment shader program
          var FSHADER_SOURCE =
            'void main() {\n' +
            '  gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' +
            '}\n';
    
          function main() {
            // Retrieve <canvas> element
            var canvas = document.getElementById('webgl');
    
            // Get the rendering context for WebGL
            var gl = getWebGLContext(canvas);
            if (!gl) {
              console.log('Failed to get the rendering context for WebGL');
              return;
            }
    
            // 初始化着色器
            if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
              console.log('Failed to intialize shaders.');
              return;
            }
    
            // 设置 顶点位置
            var n = initVertexBuffers(gl);
            if (n < 0) {
              console.log('Failed to set the positions of the vertices');
              return;
            }
    
            // 设置背景色
            gl.clearColor(0, 0, 0, 1);
    
            // 清空 颜色缓冲区
            gl.clear(gl.COLOR_BUFFER_BIT);
    
            // 画个点
            // 参数1: gl.POINTS 代表绘制点 还有其他的绘制方法(后面说)
            // 参数2: 0 表示从起始位置开始
            // 参数3: 1 绘制几个
            gl.drawArrays(gl.POINTS, 0, n);
          }
    
          // 创建顶点 缓冲区对象
          // 将多个顶点的数据  保存在缓存区对象中
          // 缓冲区传给 着色器
          function initVertexBuffers(gl) {
            var vertices = new Float32Array([
              0.0, 0.5,   -0.5, -0.5,   0.5, -0.5
            ]);
            var n = 3; // 点的个数
    
            // 创建缓冲区对象
            var vertexBuffer = gl.createBuffer();
            if (!vertexBuffer) {
              console.log('Failed to create the buffer object');
              return -1;
            }
    
            // 将缓冲区对象绑定到目标
            gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
            // 向缓冲区对象写入数据
            // 参数3 的作用是 表示程序将如何使用存储在缓冲区对象的数据 (做优化操作)
            gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
    
            // 获取变量
            var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
            if (a_Position < 0) {
              console.log('Failed to get the storage location of a_Position');
              return -1;
            }
            /**
             * 将缓冲区对象 分配给(赋值给) a_Position 变量
             * 参数含义
             * 参数1 a_Position 赋值的变量
             * 参数2 指定缓冲区中每个顶点的分量个数
             * 参数3 指定数据类型 gl.FLOAT 是其中一种类型
             * 参数4 表明是否将非浮点型数据 归一化成 [0,1] 或 [-1,1]
             * 参数5 指定相邻的两个顶点间的字节数
             * 参数6 指定从第几个数据位置开始(偏移数)
            */
            gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
    
            // 开启a_Position,为了使着色器能够访问 a_Position 变量
            // 连接 a_Position 变量 与分配给他的缓冲区对象
            gl.enableVertexAttribArray(a_Position);
    
            return n;
          }
    
        </script>
      </body>
    </html>
    
    
    • 案例3 模型矩阵 视图矩阵 投影矩阵开启深度缓冲区
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Perspective Projection</title>
      </head>
    
      <body onload="main()">
        <canvas id="webgl" width="400" height="400">
        Please use a browser that supports "canvas"
        </canvas>
    
        <script src="../../lib/webgl-utils.js"></script>
        <script src="../../lib/webgl-debug.js"></script>
        <script src="../../lib/cuon-utils.js"></script>
        <script src="../../lib/cuon-matrix.js"></script>
        <script>
          // 顶点着色器
          var VSHADER_SOURCE =
            'attribute vec4 a_Position;\n' +
            'attribute vec4 a_Color;\n' +
            'uniform mat4 u_ViewMatrix;\n' +
            'uniform mat4 u_ProjMatrix;\n' +
            'varying vec4 v_Color;\n' +
            'void main() {\n' +
            '  gl_Position = u_ProjMatrix * u_ViewMatrix * a_Position;\n' +
            '  v_Color = a_Color;\n' +
            '}\n';
    
          // 片元着色器
          var FSHADER_SOURCE =
            '#ifdef GL_ES\n' +
            'precision mediump float;\n' +
            '#endif\n' +
            'varying vec4 v_Color;\n' +
            'void main() {\n' +
            '  gl_FragColor = v_Color;\n' +
            '}\n';
    
          function main() {
            // 获取dom 元素
            var canvas = document.getElementById('webgl');
    
            // 获取 gl 上线文
            var gl = getWebGLContext(canvas);
            if (!gl) {
              console.log('Failed to get the rendering context for WebGL');
              return;
            }
    
            // 初始化着色器
            if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
              console.log('Failed to intialize shaders.');
              return;
            }
    
            // 初始化 着色器 函数调用
            var n = initVertexBuffers(gl);
            if (n < 0) {
              console.log('Failed to set the vertex information');
              return;
            }
    
            // 设置背景颜色
            gl.clearColor(0, 0, 0, 1);
    
            // 获取矩阵变量
            var u_ViewMatrix = gl.getUniformLocation(gl.program, 'u_ViewMatrix');
            var u_ProjMatrix = gl.getUniformLocation(gl.program, 'u_ProjMatrix');
            if (!u_ViewMatrix || !u_ProjMatrix) { 
              console.log('Failed to get the storage location of u_ViewMatrix and/or u_ProjMatrix');
              return;
            }
    
            var viewMatrix = new Matrix4(); // 创建 矩阵对象
            var projMatrix = new Matrix4();  // 创建 矩阵对象
    
            // 计算视图矩阵
            viewMatrix.setLookAt(0, 0, 5, 0, 0, -100, 0, 1, 0);
            projMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100); // 设置 投影矩阵 数据
            // 赋值
            gl.uniformMatrix4fv(u_ViewMatrix, false, viewMatrix.elements);
            gl.uniformMatrix4fv(u_ProjMatrix, false, projMatrix.elements);
    
            // 清空颜色缓冲区
            gl.clear(gl.COLOR_BUFFER_BIT);
    
            // 画图
            gl.drawArrays(gl.TRIANGLES, 0, n);
          }
    
          function initVertexBuffers(gl) {
            var verticesColors = new Float32Array([
              // 位置 颜色数据
              0.75,  1.0,  -4.0,  0.4,  1.0,  0.4, // 后面的
              0.25, -1.0,  -4.0,  0.4,  1.0,  0.4,
              1.25, -1.0,  -4.0,  1.0,  0.4,  0.4, 
    
              0.75,  1.0,  -2.0,  1.0,  1.0,  0.4, // 中间的
              0.25, -1.0,  -2.0,  1.0,  1.0,  0.4,
              1.25, -1.0,  -2.0,  1.0,  0.4,  0.4, 
    
              0.75,  1.0,   0.0,  0.4,  0.4,  1.0,  // 前面的
              0.25, -1.0,   0.0,  0.4,  0.4,  1.0,
              1.25, -1.0,   0.0,  1.0,  0.4,  0.4, 
    
              // Three triangles on the left side
            -0.75,  1.0,  -4.0,  0.4,  1.0,  0.4, // 后面的
            -1.25, -1.0,  -4.0,  0.4,  1.0,  0.4,
            -0.25, -1.0,  -4.0,  1.0,  0.4,  0.4, 
    
            -0.75,  1.0,  -2.0,  1.0,  1.0,  0.4, // 中间的
            -1.25, -1.0,  -2.0,  1.0,  1.0,  0.4,
            -0.25, -1.0,  -2.0,  1.0,  0.4,  0.4, 
    
            -0.75,  1.0,   0.0,  0.4,  0.4,  1.0,  // 前面的 
            -1.25, -1.0,   0.0,  0.4,  0.4,  1.0,
            -0.25, -1.0,   0.0,  1.0,  0.4,  0.4, 
            ]);
            var n = 18; // Three vertices per triangle * 6
    
            // 创建 缓冲区对象
            var vertexColorbuffer = gl.createBuffer();  
            if (!vertexColorbuffer) {
              console.log('Failed to create the buffer object');
              return -1;
            }
    
            // 将缓冲区对象 绑定到 gl.ARRAY_BUFFER
            gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorbuffer);
            gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
    
            var FSIZE = verticesColors.BYTES_PER_ELEMENT;
    
            // 获取 变量
            var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
            if(a_Position < 0) {
              console.log('Failed to get the storage location of a_Position');
              return -1;
            }
            gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
            gl.enableVertexAttribArray(a_Position);
    
            // 获取 变量
            var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
            if(a_Color < 0) {
              console.log('Failed to get the storage location of a_Color');
              return -1;
            }
    
            gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
            gl.enableVertexAttribArray(a_Color);
    
            return n;
          }
    
        </script>
      </body>
    </html>
    
    
    • 案例4 添加纹理贴图
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Draw quad with texture</title>
      </head>
    
      <body onload="main()">
        <canvas id="webgl" width="400" height="400">
        Please use a browser that supports "canvas"
        </canvas>
    
        <script src="../../lib/webgl-utils.js"></script>
        <script src="../../lib/webgl-debug.js"></script>
        <script src="../../lib/cuon-utils.js"></script>
        <script src="../../lib/cuon-matrix.js"></script>
        <script>
          // TexturedQuad.js (c) 2012 matsuda and kanda
          // 创建顶点着色器
          var VSHADER_SOURCE =
            'attribute vec4 a_Position;\n' +
            'attribute vec2 a_TexCoord;\n' +
            'varying vec2 v_TexCoord;\n' +
            'void main() {\n' +
            '  gl_Position = a_Position;\n' +
            '  v_TexCoord = a_TexCoord;\n' +
            '}\n';
    
          //  创建片元着色器
          var FSHADER_SOURCE =
            // '#ifdef GL_ES\n' +
            'precision mediump float;\n' +
            // '#endif\n' +
            'uniform sampler2D u_Sampler;\n' + // 定义取样器 用来接收 纹理图
            'varying vec2 v_TexCoord;\n' +
            'void main() {\n' +
            '  gl_FragColor = texture2D(u_Sampler, v_TexCoord);\n' +
            '}\n';
    
          function main() {
            // 获取dom 元素
            var canvas = document.getElementById('webgl');
    
            // 获取 gl 上下文对象
            var gl = getWebGLContext(canvas);
            if (!gl) {
              console.log('Failed to get the rendering context for WebGL');
              return;
            }
    
            // 初始化对象
            if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
              console.log('Failed to intialize shaders.');
              return;
            }
    
            // 函数调用
            var n = initVertexBuffers(gl);
            if (n < 0) {
              console.log('Failed to set the vertex information');
              return;
            }
    
            // 设置颜色
            gl.clearColor(0.0, 0.0, 0.0, 1.0);
    
            // 设置纹理
            if (!initTextures(gl, n)) {
              console.log('Failed to intialize the texture.');
              return;
            }
          }
    
          function initVertexBuffers(gl) { // 将纹理坐标和顶点坐标对应上
            var verticesTexCoords = new Float32Array([
              // 顶点坐标, 纹理坐标
              -0.5,  0.5,   0.0, 1.0,
              -0.5, -0.5,   0.0, 0.0,
              0.5,  0.5,   1.0, 1.0,
              0.5, -0.5,   1.0, 0.0,
            ]);
            var n = 4; // The number of vertices
    
            // 创建 缓冲区对象
            var vertexTexCoordBuffer = gl.createBuffer();
            if (!vertexTexCoordBuffer) {
              console.log('Failed to create the buffer object');
              return -1;
            }
    
            // 将缓冲区对象 分配给 gl.ARRAY_BUFFER
            gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);
    
            var FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;// 每个数据所占的字节
            //获取着色器 对象 变量
            var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
            if (a_Position < 0) {
              console.log('Failed to get the storage location of a_Position');
              return -1;
            }
            gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);
            gl.enableVertexAttribArray(a_Position);  // 开启缓冲区对象访问权限 使 着色器能访问到变量的值
    
            // 获取着色器 对象 变量
            var a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord');
            if (a_TexCoord < 0) {
              console.log('Failed to get the storage location of a_TexCoord');
              return -1;
            }
            // 赋值
            gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
            gl.enableVertexAttribArray(a_TexCoord);  // 开启缓冲区对象访问权限 使 着色器能访问到变量的值
    
            return n;
          }
    
          function initTextures(gl, n) { // 配置和加载纹理
            var texture = gl.createTexture();   // 创建一个纹理对象
            if (!texture) {
              console.log('Failed to create the texture object');
              return false;
            }
    
            // 获取着色器 对象 变量(取样器)
            var u_Sampler = gl.getUniformLocation(gl.program, 'u_Sampler');
            if (!u_Sampler) {
              console.log('Failed to get the storage location of u_Sampler');
              return false;
            }
            var image = new Image();  // 创建 图片对象
            if (!image) {
              console.log('Failed to create the image object');
              return false;
            }
            // 注册图像加载事件响应函数
            image.onload = function(){ loadTexture(gl, n, texture, u_Sampler, image); };
            // 图片路径(赋值后 浏览器开始加载)
            image.src = '../../resources/sky.JPG';
    
            return true;
          }
    
          function loadTexture(gl, n, texture, u_Sampler, image) { // 对纹理开始处理
            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); // 对纹理图像进行y轴反转
            // 开启 0号纹理单元
            gl.activeTexture(gl.TEXTURE0);
            // 向 EXTURE_2D 绑定纹理对象
            gl.bindTexture(gl.TEXTURE_2D, texture);
    
            // 配置纹理参数 (设置样式)
            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
            // 配置纹理图像 --> 将纹理图像分配给纹理对象
            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
            
            // 将 0 号纹理传递给着色器
            gl.uniform1i(u_Sampler, 0);
            
            gl.clear(gl.COLOR_BUFFER_BIT);   // 清空颜色缓冲区
    
            gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); // 绘制矩形
          }
    
        </script>
      </body>
    </html>
    
    
    • 案例5 立方体绘制
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Hello cube</title>
      </head>
    
      <body onload="main()">
        <canvas id="webgl" width="400" height="400">
        Please use a browser that supports "canvas"
        </canvas>
    
        <script src="../../lib/webgl-utils.js"></script>
        <script src="../../lib/webgl-debug.js"></script>
        <script src="../../lib/cuon-utils.js"></script>
        <script src="../../lib/cuon-matrix.js"></script>
        <script>
          // 顶点着色器
          var VSHADER_SOURCE =
            'attribute vec4 a_Position;\n' +
            'attribute vec4 a_Color;\n' +
            'uniform mat4 u_MvpMatrix;\n' +
            'varying vec4 v_Color;\n' +
            'void main() {\n' +
            '  gl_Position = u_MvpMatrix * a_Position;\n' +
            '  v_Color = a_Color;\n' +
            '}\n';
    
          // 片元着色器
          var FSHADER_SOURCE =
            '#ifdef GL_ES\n' +
            'precision mediump float;\n' +
            '#endif\n' +
            'varying vec4 v_Color;\n' +
            'void main() {\n' +
            '  gl_FragColor = v_Color;\n' +
            '}\n';
    
          function main() {
            // 获取dom 元素
            var canvas = document.getElementById('webgl');
    
            // 获取 gl 上线文
            var gl = getWebGLContext(canvas);
            if (!gl) {
              console.log('Failed to get the rendering context for WebGL');
              return;
            }
    
            // 初始化着色器
            if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
              console.log('Failed to intialize shaders.');
              return;
            }
    
            // 初始化 着色器 函数调用
            var n = initVertexBuffers(gl);
            if (n < 0) {
              console.log('Failed to set the vertex information');
              return;
            }
    
            // 设置背景颜色
            gl.clearColor(0.0, 0.0, 0.0, 1.0);
            gl.enable(gl.DEPTH_TEST); // 开启隐藏面消除功能
    
            // 获取着色器 变量
            var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
            if (!u_MvpMatrix) { 
              console.log('Failed to get the storage location of u_MvpMatrix');
              return;
            }
    
            // 创建矩阵对象
            var mvpMatrix = new Matrix4();
            mvpMatrix.setPerspective(30, 1, 1, 100); // 设置 投影矩阵
            mvpMatrix.lookAt(3, 3, 7, 0, 0, 0, 0, 1, 0);// 视图模型矩阵
    
            // 赋值
            gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);
    
            // 清空颜色缓冲区 和 深度缓冲区
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    
            // 绘制 立方体
            gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
          }
    
          function initVertexBuffers(gl) {
            // Create a cube
            //    v6----- v5
            //   /|      /|
            //  v1------v0|
            //  | |     | |
            //  | |v7---|-|v4
            //  |/      |/
            //  v2------v3
            var verticesColors = new Float32Array([
              // 8个顶点位置 和 颜色值
              1.0,  1.0,  1.0,     1.0,  1.0,  1.0,  // v0 White
              -1.0,  1.0,  1.0,     1.0,  0.0,  1.0,  // v1 Magenta
              -1.0, -1.0,  1.0,     1.0,  0.0,  0.0,  // v2 Red
              1.0, -1.0,  1.0,     1.0,  1.0,  0.0,  // v3 Yellow
              1.0, -1.0, -1.0,     0.0,  1.0,  0.0,  // v4 Green
              1.0,  1.0, -1.0,     0.0,  1.0,  1.0,  // v5 Cyan
              -1.0,  1.0, -1.0,     0.0,  0.0,  1.0,  // v6 Blue
              -1.0, -1.0, -1.0,     0.0,  0.0,  0.0   // v7 Black
            ]);
    
            // 6个面
            var indices = new Uint8Array([
              0, 1, 2,   0, 2, 3,    // front
              0, 3, 4,   0, 4, 5,    // right
              0, 5, 6,   0, 6, 1,    // up
              1, 6, 7,   1, 7, 2,    // left
              7, 4, 3,   7, 3, 2,    // down
              4, 7, 6,   4, 6, 5     // back
          ]);
    
            // 创建缓冲区对象
            var vertexColorBuffer = gl.createBuffer();
            var indexBuffer = gl.createBuffer();
            if (!vertexColorBuffer || !indexBuffer) {
              return -1;
            }
    
            // 将缓冲区对象 绑定到 gl.ARRAY_BUFFER
            gl.bindBuffer(gl.ARRAY_BUFFER, vertexColorBuffer);
            gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
    
            var FSIZE = verticesColors.BYTES_PER_ELEMENT;
            // 获取 变量
            var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
            if(a_Position < 0) {
              console.log('Failed to get the storage location of a_Position');
              return -1;
            }
            gl.vertexAttribPointer(a_Position, 3, gl.FLOAT, false, FSIZE * 6, 0);
            gl.enableVertexAttribArray(a_Position);
            // 获取 变量
            var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
            if(a_Color < 0) {
              console.log('Failed to get the storage location of a_Color');
              return -1;
            }
            gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 6, FSIZE * 3);
            gl.enableVertexAttribArray(a_Color);
    
            // 将缓冲区对象 绑定到 gl.ELEMENT_ARRAY_BUFFER(gl.ELEMENT_ARRAY_BUFFER 管理具有索引结构的三维数据模型)
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
    
            return indices.length;
          }
    
        </script>
      </body>
    </html>
    
    
    • 案例6 光照
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Point lighted cube (with animation)</title>
      </head>
    
      <body onload="main()">
        <canvas id="webgl" width="400" height="400">
        Please use a browser that supports "canvas"
        </canvas>
    
        <script src="../../lib/webgl-utils.js"></script>
        <script src="../../lib/webgl-debug.js"></script>
        <script src="../../lib/cuon-utils.js"></script>
        <script src="../../lib/cuon-matrix.js"></script>
        <script>
          // 顶点着色器
          var VSHADER_SOURCE =
            'attribute vec4 a_Position;\n' + // 顶点位置
            'attribute vec4 a_Color;\n' + // 顶点颜色
            'attribute vec4 a_Normal;\n' + // 法向量
            'uniform mat4 u_MvpMatrix;\n' + // 视图 投影矩阵
            'uniform mat4 u_ModelMatrix;\n' +    // 模型矩阵
            'uniform mat4 u_NormalMatrix;\n' +   // 用来变换 法向量的矩阵
            'uniform vec3 u_LightColor;\n' +     // 光线颜色
            'uniform vec3 u_LightPosition;\n' +  // 光线方向
            'uniform vec3 u_AmbientLight;\n' +   // 环境光
            'varying vec4 v_Color;\n' + // 传给片元着色器的
            'void main() {\n' +
            '  gl_Position = u_MvpMatrix * a_Position;\n' +
              // 计算位置变换后的 方向量 并 归一化
            '  vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));\n' +
              // 计算顶点坐标
            '  vec4 vertexPosition = u_ModelMatrix * a_Position;\n' +
              // 计算光线方向并且归一化 (点光源的光线方向 = 点光线坐标 - 顶点坐标)
            '  vec3 lightDirection = normalize(u_LightPosition - vec3(vertexPosition));\n' +
              // 计算 cos 值 = 漫反射的方向向量 * 法向量
            '  float nDotL = max(dot(normal, lightDirection), 0.0);\n' +
              //  计算漫反射后的物体颜色
            '  vec3 diffuse = u_LightColor * a_Color.rgb * nDotL;\n' +
              // 计算环境光的物体颜色
            '  vec3 ambient = u_AmbientLight * a_Color.rgb;\n' +
              // 计算最终的物体颜色
            '  v_Color = vec4(diffuse + ambient, a_Color.a);\n' + 
            '}\n';
    
          // Fragment shader program
          var FSHADER_SOURCE =
            '#ifdef GL_ES\n' +
            'precision mediump float;\n' +
            '#endif\n' +
            'varying vec4 v_Color;\n' +
            'void main() {\n' +
            '  gl_FragColor = v_Color;\n' +
            '}\n';
    
          function main() {
            // 获取dom元素
            var canvas = document.getElementById('webgl');
    
            // 获取gl 上下文
            var gl = getWebGLContext(canvas);
            if (!gl) {
              console.log('Failed to get the rendering context for WebGL');
              return;
            }
    
            // 初始化着色器
            if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
              console.log('Failed to intialize shaders.');
              return;
            }
    
            // 着色器赋值
            var n = initVertexBuffers(gl);
            if (n < 0) {
              console.log('Failed to set the vertex information');
              return;
            }
    
            // 设置背景颜色
            gl.clearColor(0.0, 0.0, 0.0, 1.0);
            gl.enable(gl.DEPTH_TEST); // 开启隐藏面消除功能
    
            // 获取着色器 变量
            var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
            var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
            var u_NormalMatrix = gl.getUniformLocation(gl.program, 'u_NormalMatrix');
            var u_LightColor = gl.getUniformLocation(gl.program, 'u_LightColor');
            var u_LightPosition = gl.getUniformLocation(gl.program, 'u_LightPosition');
            var u_AmbientLight = gl.getUniformLocation(gl.program, 'u_AmbientLight');
            if (!u_MvpMatrix || !u_NormalMatrix || !u_LightColor || !u_LightPosition || !u_AmbientLight) { 
              console.log('Failed to get the storage location');
              return;
            }
    
            var vpMatrix = new Matrix4();   // 视图 投影矩阵
            vpMatrix.setPerspective(30, canvas.width/canvas.height, 1, 100);// 设置设置透视投影矩阵
            vpMatrix.lookAt(6, 6, 14, 0, 0, 0, 0, 1, 0);// 设置视图模型矩阵
    
            // 设置光颜色
            gl.uniform3f(u_LightColor, 1.0, 1.0, 1.0);
            // 设置光方向
            gl.uniform3f(u_LightPosition, 2.3, 4.0, 3.5);
            // 设置环境光
            gl.uniform3f(u_AmbientLight, 0.2, 0.2, 0.2);
    
            var currentAngle = 0.0;  // 当前角度
            var modelMatrix = new Matrix4();  // 模型变换矩阵
            var mvpMatrix = new Matrix4();    // 视图 投影矩阵
            var normalMatrix = new Matrix4(); // 计算法向量的矩阵
    
            var tick = function() {
              currentAngle = animate(currentAngle);  // 更新旋转角度
    
              // 设置旋转角度
              modelMatrix.setRotate(currentAngle, 0, 1, 0); // Rotate around the y-axis
              // 更新到 着色器 上
              gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements);
    
              // 视图 投影矩阵 更新 并 赋值到 着色器上
              mvpMatrix.set(vpMatrix).multiply(modelMatrix);
              gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);
    
              // 根据模型矩阵 计算出用来转化法向量的矩阵
            // 将 normalMatrix 设置为 modelMatrix 的 逆转置矩阵,(用于计算 物体 旋转或平移变换后的 法向量)
              normalMatrix.setInverseOf(modelMatrix);
              normalMatrix.transpose();// 对自身进行转置操作,并将自身设为转置后的结果(用于计算 物体 旋转或平移变换后的 法向量)
              gl.uniformMatrix4fv(u_NormalMatrix, false, normalMatrix.elements);
    
              // 清空颜色缓冲区 和 深度缓冲区
              gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
    
              // 画图
              gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
    
              requestAnimationFrame(tick, canvas); // 循环调用
            };
            tick();
          }
    
          function initVertexBuffers(gl) {
            // Create a cube
            //    v6----- v5
            //   /|      /|
            //  v1------v0|
            //  | |     | |
            //  | |v7---|-|v4
            //  |/      |/
            //  v2------v3
            // 顶点
            var vertices = new Float32Array([
              2.0, 2.0, 2.0,  -2.0, 2.0, 2.0,  -2.0,-2.0, 2.0,   2.0,-2.0, 2.0, // v0-v1-v2-v3 front
              2.0, 2.0, 2.0,   2.0,-2.0, 2.0,   2.0,-2.0,-2.0,   2.0, 2.0,-2.0, // v0-v3-v4-v5 right
              2.0, 2.0, 2.0,   2.0, 2.0,-2.0,  -2.0, 2.0,-2.0,  -2.0, 2.0, 2.0, // v0-v5-v6-v1 up
              -2.0, 2.0, 2.0,  -2.0, 2.0,-2.0,  -2.0,-2.0,-2.0,  -2.0,-2.0, 2.0, // v1-v6-v7-v2 left
              -2.0,-2.0,-2.0,   2.0,-2.0,-2.0,   2.0,-2.0, 2.0,  -2.0,-2.0, 2.0, // v7-v4-v3-v2 down
              2.0,-2.0,-2.0,  -2.0,-2.0,-2.0,  -2.0, 2.0,-2.0,   2.0, 2.0,-2.0  // v4-v7-v6-v5 back
            ]);
    
            // 颜色
            var colors = new Float32Array([
              1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0,     // v0-v1-v2-v3 front
              1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0,     // v0-v3-v4-v5 right
              1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0,     // v0-v5-v6-v1 up
              1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0,     // v1-v6-v7-v2 left
              1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0,     // v7-v4-v3-v2 down
              1, 0, 0,   1, 0, 0,   1, 0, 0,  1, 0, 0     // v4-v7-v6-v5 back
          ]);
    
            // 法向量
            var normals = new Float32Array([
              0.0, 0.0, 1.0,   0.0, 0.0, 1.0,   0.0, 0.0, 1.0,   0.0, 0.0, 1.0,  // v0-v1-v2-v3 front
              1.0, 0.0, 0.0,   1.0, 0.0, 0.0,   1.0, 0.0, 0.0,   1.0, 0.0, 0.0,  // v0-v3-v4-v5 right
              0.0, 1.0, 0.0,   0.0, 1.0, 0.0,   0.0, 1.0, 0.0,   0.0, 1.0, 0.0,  // v0-v5-v6-v1 up
            -1.0, 0.0, 0.0,  -1.0, 0.0, 0.0,  -1.0, 0.0, 0.0,  -1.0, 0.0, 0.0,  // v1-v6-v7-v2 left
              0.0,-1.0, 0.0,   0.0,-1.0, 0.0,   0.0,-1.0, 0.0,   0.0,-1.0, 0.0,  // v7-v4-v3-v2 down
              0.0, 0.0,-1.0,   0.0, 0.0,-1.0,   0.0, 0.0,-1.0,   0.0, 0.0,-1.0   // v4-v7-v6-v5 back
            ]);
    
            // 索引值
            var indices = new Uint8Array([
              0, 1, 2,   0, 2, 3,    // front
              4, 5, 6,   4, 6, 7,    // right
              8, 9,10,   8,10,11,    // up
              12,13,14,  12,14,15,    // left
              16,17,18,  16,18,19,    // down
              20,21,22,  20,22,23     // back
          ]);
    
            // 给着色器变量 赋值
            if (!initArrayBuffer(gl, 'a_Position', vertices, 3, gl.FLOAT)) return -1;
            if (!initArrayBuffer(gl, 'a_Color', colors, 3, gl.FLOAT)) return -1;
            if (!initArrayBuffer(gl, 'a_Normal', normals, 3, gl.FLOAT)) return -1;
    
            // 缓冲区对象置空
            gl.bindBuffer(gl.ARRAY_BUFFER, null);
    
            // 创建缓冲区对象
            var indexBuffer = gl.createBuffer();
            if (!indexBuffer) {
              console.log('Failed to create the buffer object');
              return false;
            }
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);// 将缓冲区对象 绑定到 gl.ELEMENT_ARRAY_BUFFER(gl.ELEMENT_ARRAY_BUFFER 管理具有索引结构的三维数据模型)
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
    
            return indices.length;
          }
    
          function initArrayBuffer(gl, attribute, data, num, type) {
            // 创建一个 缓冲区对象
            var buffer = gl.createBuffer();
            if (!buffer) {
              console.log('Failed to create the buffer object');
              return false;
            }
            // 将缓冲区对象分配给 gl.ARRAY_BUFFER
            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
            gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
            // 获取变量
            var a_attribute = gl.getAttribLocation(gl.program, attribute);
            if (a_attribute < 0) {
              console.log('Failed to get the storage location of ' + attribute);
              return false;
            }
            gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
            // 开启访问权限
            gl.enableVertexAttribArray(a_attribute);
    
            return true;
          }
    
          // 每次旋转的角度值
          var ANGLE_STEP = 30.0;
          // 上次时间值
          var g_last = Date.now();
          function animate(angle) {
            // 获取当前时间
            var now = Date.now();
            var elapsed = now - g_last;
            g_last = now;
            // 计算应该旋转的角度
            var newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0;
            return newAngle %= 360;
          }
    
        </script>
      </body>
    </html>
    
    
    • 雾化效果
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <title>Fog</title>
      </head>
    
      <body onload="main()">
        <canvas id="webgl" width="400" height="400">
        Please use a browser that supports "canvas"
        </canvas>
        <p>&uarr;&darr;: Increase/decrease the fog distance</p></p>
    
        <script src="../../lib/webgl-utils.js"></script>
        <script src="../../lib/webgl-debug.js"></script>
        <script src="../../lib/cuon-utils.js"></script>
        <script src="../../lib/cuon-matrix.js"></script>
        <script>
          // 顶点着色器
          var VSHADER_SOURCE =
            'attribute vec4 a_Position;\n' + // 设置顶点
            'attribute vec4 a_Color;\n' + // 颜色变量
            'uniform mat4 u_MvpMatrix;\n' + // 视图投影矩阵
            'uniform mat4 u_ModelMatrix;\n' + // 
            'uniform vec4 u_Eye;\n' +     // 观察者位置 视点
            'varying vec4 v_Color;\n' + // 颜色
            'varying float v_Dist;\n' + // 顶点与 视点的距离
            'void main() {\n' +
            '  gl_Position = u_MvpMatrix * a_Position;\n' + // 计算物体顶点位置
            '  v_Color = a_Color;\n' +
              // 计算顶点与 视点的距离
            '  v_Dist = distance(u_ModelMatrix * a_Position, u_Eye);\n' +
            '}\n';
    
          // 片元着色器
          var FSHADER_SOURCE =
            '#ifdef GL_ES\n' +
            'precision mediump float;\n' + // 设置精度
            '#endif\n' +
            'uniform vec3 u_FogColor;\n' + // 雾的颜色
            'uniform vec2 u_FogDist;\n' +  // 雾化的起点和终点
            'varying vec4 v_Color;\n' + // 传过来的变量
            'varying float v_Dist;\n' + // 传过来的变量
            'void main() {\n' +
              // 计算雾化因子 u_FogDist.y:雾化终点  v_Dist:顶点与 视点的距离  u_FogDist.x:雾化起点   clamp api:把第一个参数的值 限制在第二三的区间中(0,1)
            '  float fogFactor = clamp((u_FogDist.y - v_Dist) / (u_FogDist.y - u_FogDist.x), 0.0, 1.0);\n' +
              // api 吧 混合 雾的颜色  物体颜色 雾化因子
            '  vec3 color = mix(u_FogColor, vec3(v_Color), fogFactor);\n' +
            '  gl_FragColor = vec4(color, v_Color.a);\n' +
            '}\n';
    
          function main() {
            // 获取dom对象
            var canvas = document.getElementById('webgl');
    
            // 获取gl 上下文对象
            var gl = getWebGLContext(canvas);
            if (!gl) {
              console.log('Failed to get the rendering context for WebGL');
              return;
            }
    
            // 初始化着色器  返回程序对象
            if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
              console.log('Failed to intialize shaders.');
              return;
            }
    
            // 着色器变量赋值
            var n = initVertexBuffers(gl);
            if (n < 1) {
              console.log('Failed to set the vertex information');
              return;
            }
    
            // 雾化颜色
            var fogColor = new Float32Array([0.137, 0.231, 0.423]); // 设置雾的颜色
            // 雾化的起点和终点
            var fogDist = new Float32Array([55, 80]);
            // 设置视点坐标
            var eye = new Float32Array([25, 65, 35, 1.0]);
    
            // 获取着色器的变量
            var u_MvpMatrix = gl.getUniformLocation(gl.program, 'u_MvpMatrix');
            var u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix');
            var u_Eye = gl.getUniformLocation(gl.program, 'u_Eye');
            var u_FogColor = gl.getUniformLocation(gl.program, 'u_FogColor');
            var u_FogDist = gl.getUniformLocation(gl.program, 'u_FogDist');
            if (!u_MvpMatrix || !u_ModelMatrix || !u_Eye || !u_FogColor || !u_FogDist) {
              console.log('Failed to get the storage location');
              return;
            }
            
            // 给 着色器变量赋值
            gl.uniform3fv(u_FogColor, fogColor); // Colors
            gl.uniform2fv(u_FogDist, fogDist);   // Starting point and end point
            gl.uniform4fv(u_Eye, eye);           // Eye point
    
            // 设置背景色
            gl.clearColor(fogColor[0], fogColor[1], fogColor[2], 1.0); // Color of Fog
            gl.enable(gl.DEPTH_TEST); // 开启隐藏面消除功能
    
            // 创建矩阵
            var modelMatrix = new Matrix4();
            modelMatrix.setScale(10, 10, 10); // 设置 收缩比例
            gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements); // 赋值
    
            // 创建矩阵
            var mvpMatrix = new Matrix4();
            mvpMatrix.setPerspective(30, canvas.width/canvas.height, 1, 1000); // // 定义透视 投影矩阵
            mvpMatrix.lookAt(eye[0], eye[1], eye[2], 0, 2, 0, 0, 1, 0);// 创建视图矩阵
            mvpMatrix.multiply(modelMatrix);
            gl.uniformMatrix4fv(u_MvpMatrix, false, mvpMatrix.elements);
            document.onkeydown = function(ev){ keydown(ev, gl, n, u_FogDist, fogDist); }; // 注册事件
    
            // 清空颜色缓冲器 和 深度缓冲区
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
            // 画图
            gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
    
            var modelViewMatrix = new Matrix4(); // ??? 干什么的 没看懂
            modelViewMatrix.setLookAt(eye[0], eye[1], eye[2], 0, 2, 0, 0, 1, 0);
            modelViewMatrix.multiply(modelMatrix);
            modelViewMatrix.multiplyVector4(new Vector4([1, 1, 1, 1]));
            mvpMatrix.multiplyVector4(new Vector4([1, 1, 1, 1]));
            modelViewMatrix.multiplyVector4(new Vector4([-1, 1, 1, 1]));
            mvpMatrix.multiplyVector4(new Vector4([-1, 1, 1, 1]));
          }
    
          function keydown(ev, gl, n, u_FogDist, fogDist) {
            switch (ev.keyCode) {
              case 38: // 方向键 上键 改变  fogDist的值
                fogDist[1]  += 1;
                break;
              case 40: // 方向键 下键 改变  fogDist的值
                if (fogDist[1] > fogDist[0]) fogDist[1] -= 1;
                break;
              default: return;
            }
            gl.uniform2fv(u_FogDist, fogDist);   // 赋值
            // 清空颜色缓冲器 和 深度缓冲区
            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
            // 画图
            gl.drawElements(gl.TRIANGLES, n, gl.UNSIGNED_BYTE, 0);
          }
    
          function initVertexBuffers(gl) {
            // Create a cube
            //    v6----- v5
            //   /|      /|
            //  v1------v0|
            //  | |     | |
            //  | |v7---|-|v4
            //  |/      |/
            //  v2------v3
    
            var vertices = new Float32Array([   // 顶点坐标
              1, 1, 1,  -1, 1, 1,  -1,-1, 1,   1,-1, 1,    // v0-v1-v2-v3 front
              1, 1, 1,   1,-1, 1,   1,-1,-1,   1, 1,-1,    // v0-v3-v4-v5 right
              1, 1, 1,   1, 1,-1,  -1, 1,-1,  -1, 1, 1,    // v0-v5-v6-v1 up
              -1, 1, 1,  -1, 1,-1,  -1,-1,-1,  -1,-1, 1,    // v1-v6-v7-v2 left
              -1,-1,-1,   1,-1,-1,   1,-1, 1,  -1,-1, 1,    // v7-v4-v3-v2 down
              1,-1,-1,  -1,-1,-1,  -1, 1,-1,   1, 1,-1     // v4-v7-v6-v5 back
            ]);
    
            var colors = new Float32Array([     // 颜色坐标
              0.4, 0.4, 1.0,  0.4, 0.4, 1.0,  0.4, 0.4, 1.0,  0.4, 0.4, 1.0,  // v0-v1-v2-v3 front
              0.4, 1.0, 0.4,  0.4, 1.0, 0.4,  0.4, 1.0, 0.4,  0.4, 1.0, 0.4,  // v0-v3-v4-v5 right
              1.0, 0.4, 0.4,  1.0, 0.4, 0.4,  1.0, 0.4, 0.4,  1.0, 0.4, 0.4,  // v0-v5-v6-v1 up
              1.0, 1.0, 0.4,  1.0, 1.0, 0.4,  1.0, 1.0, 0.4,  1.0, 1.0, 0.4,  // v1-v6-v7-v2 left
              1.0, 1.0, 1.0,  1.0, 1.0, 1.0,  1.0, 1.0, 1.0,  1.0, 1.0, 1.0,  // v7-v4-v3-v2 down
              0.4, 1.0, 1.0,  0.4, 1.0, 1.0,  0.4, 1.0, 1.0,  0.4, 1.0, 1.0   // v4-v7-v6-v5 back
            ]);
    
            var indices = new Uint8Array([       // 3d 物体 索引值坐标
              0, 1, 2,   0, 2, 3,    // front
              4, 5, 6,   4, 6, 7,    // right
              8, 9,10,   8,10,11,    // up
              12,13,14,  12,14,15,    // left
              16,17,18,  16,18,19,    // down
              20,21,22,  20,22,23     // back
            ]);
    
            // 创建 缓冲区对象
            var indexBuffer = gl.createBuffer();
            if (!indexBuffer) 
              return -1;
    
            // 着色器 变量赋值
            if (!initArrayBuffer(gl, vertices, 3, gl.FLOAT, 'a_Position')) return -1;
            if (!initArrayBuffer(gl, colors, 3, gl.FLOAT, 'a_Color')) return -1;
    
            // 将缓冲区对象 绑定到 gl.ELEMENT_ARRAY_BUFFER(gl.ELEMENT_ARRAY_BUFFER 管理具有索引结构的三维数据模型)
            gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
            gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
    
            return indices.length;
          }
    
          function initArrayBuffer (gl, data, num, type, attribute) {
            // 创建 缓冲区对象
            var buffer = gl.createBuffer();
            if (!buffer) {
              console.log('Failed to create the buffer object');
              return false;
            }
            // 将缓冲区对象分配给 ARRAY_BUFFER
            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
            gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW); // 赋值
            // 获取着色器 变量
            var a_attribute = gl.getAttribLocation(gl.program, attribute);
            if (a_attribute < 0) {
              console.log('Failed to get the storage location of ' + attribute);
              return false;
            }
            gl.vertexAttribPointer(a_attribute, num, type, false, 0, 0);
            // 开启访问权限
            gl.enableVertexAttribArray(a_attribute);
            // 缓冲区对象置空
            gl.bindBuffer(gl.ARRAY_BUFFER, null);
    
            return true;
          }
    
        </script>
      </body>
    </html>
    
    

    webgl代码地址


    相关文章

      网友评论

          本文标题:webgl 学习笔记

          本文链接:https://www.haomeiwen.com/subject/sbomzltx.html