webgl 学习笔记

2021-11-24  本文已影响0人  _旁观者_

webgl 介绍

区别

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


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

着色器

// 最简单的代码片段参考
// 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 环境光(物体周围均匀分布的光线)
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

可视空间矩阵

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

// 参数依次为 近裁剪面左边界、近裁剪面右边界、近裁剪面上边界、近裁剪面下边界、近裁剪面位置、远裁剪面位置
projMatrix.setOrtho(-1.0, 1.0, -1.0, 1.0, g_near, g_far); // 设置盒装可视空间
// 参数依次是  可视空间的夹角(观察者顶面和底面的夹角),近裁剪面的宽高比,近裁剪面位置,远裁剪面的位置
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来实现

  // 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

基本开发流程



代码案例


主要注意的是 可以通过 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>

<!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>

<!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>

<!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>

<!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>

<!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代码地址


上一篇下一篇

猜你喜欢

热点阅读