WebGL 基础笔记

WebGL

  • WebGL 是什么:WebGL(Web Graphics Library)是一种3D绘图协议,这种绘图技术标准允许把 JavaScript和 OpenGL ES 2.0结合在一起,通过增加 OpenGL ES 2.0 的一个 JavaScript 绑定,WebGL 可以为 HTML5 Canvas 提供硬件 3D 加速渲染
  • GPU ≠ WebGL ≠ 3D
  • WebGL 很大程度上在和 GPU 打交道但不仅仅是 GPU 渲染
  • WebGL 不仅仅是绘制3D,把浏览器作为一个桥梁,是浏览器上的 OpenGL

现代计算机图形学系统

WebGL 基础笔记_第1张图片

  • 光栅(Raster):几乎所有的现代图形系统都是基于光栅来绘制图形的,光栅就是指构成图像的像素阵列
  • 像素(Pixel):一个像素对应图像上的一个点,它通常保存图像上的某个具体位置的颜色等信息
  • 帧缓存(Frame Buffer):在绘图过程中,像素信息被存放在帧缓存中,帧缓存是一块内存地址
  • CPU(Central Processing Unit):中央处理单元,负责逻辑计算
  • GPU(Graphics Processing Unit):图形处理单元,负责图形计算。GPU 由大量的小运算单元构成,每个运算单元只负责处理很简单的计算。每个运算单元彼此独立。因此所有计算可以并行处理
  • CPU VS GPU : CPU 适合处理复杂计算任务,不适合处理数量非常大的简单任务,则这种任务交给 GPU 来处理
  • WebGL 和 OpenGL 的关系:WebGL 是 OpenGL 在浏览器上的一种实现
    WebGL 基础笔记_第2张图片
  • 图形计算渲染过程:
    WebGL 基础笔记_第3张图片

    • 轮廓提取/ meshing
    • 光栅化
    • 帧缓存
    • 渲染

利用 WebGL 进行图形渲染

  • 利用 WebGL 绘图步骤:

    1. 创建 WebGL 上下文
    2. 创建 WebGL Program
    3. 将数据存入缓冲区
    4. 将缓冲区数据读取到 GPU
    5. GPU 执行 WebGL 程序,输出结果
      WebGL 基础笔记_第4张图片
  • 创建 WebGL 上下文

    • 在 HTML 中创建一个宽高 1000 的canvas画布:
    • 在 JavaScript 中获取 DOM 后调用getContext('webgl')获取对应的上下文

      const canvas = document.getElementById("canvas");
      const gl = canvas.getContext('webgl');
    • canvas.getContext() 函数接收的参数在不同浏览器中会不同。因为早期 WebGL 的 context,还不能通过正式的名称webgl来获取,必须使用experimental-webgl来获取 context 对象,现在很多浏览器也支持 webgl2 等其他参数,所以可以封装成一个具有特性检测的函数

      function create3DContext(canvas,options) {
        const names = ['webgl', 'experimental-webgl','webkit-3d', ' moz-webgl'];
        if (options && options.webgl2) names.unshift('webgl2');
        let context = null;
        for (let ii = 0; ii < names.length; ++ii) {
            try {
                context = canvas.getContext(names[ii], options);
            } catch (e) {
                // no-empty
            }
            if (context) {
                break;
            }
        }
        return context;
      }
  • 创建 WebGL Program

    • 顶点着色器 Vertex Shader : 用于处理顶点的位置

      attribute vec2 position;
      void main(){
        gl_PointSize = 1.0;
        gl_Position = vec4(position,1.0,1.0);
      }
    • 片元着色器 Fragment Shader : 并行处理顶点包围内的所有像素,处理次数更多。颜色取值 从 0.0 - 1.0 的浮点范围

      precision mediump float;
      void main(){
        gl_FragColor = vec4(1.0,0.0,0.0,1.0);
      }
    • Create Program

      // 顶点着色器代码
      const vertexShaderCode = `
      attribute vec2 position;
      void main(){
          gl_PointSize = 1.0;
          gl_Position = vec4(position,1.0,1.0);
      }
      `;
      // 片元着色器代码
      const fragmentShaderCode = `
      precision mediump float;
      void main(){
          gl_FragColor = vec4(1.0,0.0,0.0,1.0);
      }
      `;
      
      // 顶点着色器
      const vertexShader = gl.createShader(gl.VERTEX_SHADER);
      gl.shaderSource(vertexShader, vertexShaderCode);
      gl.compileShader(vertexShader);
      // 片元着色器
      const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
      gl.shaderSource(fragmentShader, fragmentShaderCode);
      gl.compileShader(fragmentShader);
      
      // 创建程序
      const program = gl.createProgram();
      gl.attachShader(program, vertexShader);
      gl.attachShader(program, fragmentShader);
      gl.linkProgram(program);
      gl.useProgram(program);
    • 创建并使用着色器的相关步骤:

      • 创建着色器对象gl.createShader()
      • 向着色器对象中填充着色器程序的源代码gl.shaderSource()
      • 编译着色器gl.compileShader()
      • 创建程序对象gl.createProgram()
      • 为程序对象分配着色器gl.attachShader()
      • 连接程序对象gl.linkProgram()
      • 使用程序对象gl.useProgram()
  • 将数据存入缓冲区(Frame Buffer)

    • 坐标系:canvas 和浏览器的坐标轴都是左上角为原点,x 轴向右为正方向,y 轴向下为正方向。在 WebGL 的坐标体系中,是一个以绘制画布的中心为原点,范围从 -1 到 1。在 3D 的情况下,z 轴正方向是向外的
      WebGL 基础笔记_第5张图片
  • 绘制一个三角形:

    • 用浮点类型数组表示顶点数据,创建 buffer 后将返回的 bufferid 绑定到上下文,最后绑定数据到缓冲区

      const points = new Float32Array([
        -1, -1,
        0, 1,
        1, -1,
      ]);
      
      const bufferId = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
      gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
  • 将缓冲区数据读取到 GPU

    • 做一个指针的绑定

      const vPosition = gl.getAttribLocation(program,'position');  //获取顶点着色器中的position变量的地址
      gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false,0, 0);   //给变量设置长度和类型
      gl.enableVertexAttribArray(vPosition);   //激活这个变量
  • GPU 执行 WebGL 程序,输出结果

    • 清除缓冲区数据,再以三角形图元方式绘制三角形,gl.drawArrays() 的三个参数,第一个是绘制的模式(三角形),第二个是绘制的 points 的起始下标,最后一个是绘制的顶点个数,因为每个点是一个二维的向量,length为 6,所以绘制三角形需要除以 2

      gl.clear(gl.COLOR_BUFFER_BIT);  //清除缓冲区
      gl.drawArrays(gl.TRIANGLES, 0 ,points.length / 2);  //绘制
    • 结果
      WebGL 基础笔记_第6张图片

其他方式绘制图形

  • 用 canvas 2D 绘制三角形

    • 在 HTML 中创建一个宽高 1000 的canvas画布:
    • 在 JavaScript 中获取 canvas 后通过 beginPath,moveTo,lineTo 等 API 绘制出图形

      const canvas = document.getElementById('canvas');
      const ctx = canvas.getContext('2d');
      
      ctx.beginPath();
      ctx.moveTo(250, 0);
      ctx.lineTo(500, 500);
      ctx.lineTo(0, 500);
      ctx.fillStyle = 'red';
      ctx.fill();

Read More

  1. The book of shaders
  2. Mesh.js
  3. glsl-doodle
  4. SpriteJS
  5. ThreeJS
  6. shadertoy

WebGL 和 canvas

  • WebGL 可以看成 OpenGL 的在浏览器上的一种实现,OpenGL 则是可以直接调用计算机 GPU 算力的一个 3d API。canvas 是在浏览器上的 2d 画布,通过 WebGL 转译光栅后在 canvas 上显示出来
  • 相比 canvas,WebGL性能更好。如果需要实现复杂效果,建议使用 WebGL
  • WebGL 可以压缩相同材质的图形,通过 GPU 一次渲染成千上万个图形,而 canvas 通过浏览器渲染,性能较差

你可能感兴趣的:(前端)