WebGL入门1:从绘制一个点到多边形

217 阅读3分钟

  时隔2年再次回顾webgl的基础学习,基础忘记的差不多了,还是得做个记录总结一下。

  本文整合了《WebGL编程指南》第二、三章的部分内容,旨在系统性地介绍WebGL的基本概念、绘制流程以及着色器编程。

  我们首先需要对WebGL有一个基础的认识,WebGL的核心是一个光栅化引擎,它基于OpenGL ES,通过JavaScript在HTML5的 <canvas> 元素中绘制3D图形。其编程模式与传统的CPU编程截然不同,主要依赖于着色器(Shader)

  好了,废话不多说,让我们直接进入正题。

Step1:绘制一个点

  效果如下图所示。

image.png

   那么为达到上述效果,我们需要经过以下几个步骤:
  1. 获取Canvas元素和WebGL上下文
  2. 初始化着色器程序
  3. 获取并设置顶点属性
  4. 设置背景色并清空画布
  5. 执行绘制命令

1. 获取Canvas元素和WebGL上下文
    var canvas = document.getElementById('webgl');
    var gl = canvas.getContext('webgl')
2. 初始化着色器程序
    // 顶点着色器
    var VSHADER_SOURCE = `
      // 位置
      attribute vec4 a_Position;
      // 大小
      attribute float a_Size;
      void main() {
        gl_Position = a_Position;
        gl_PointSize = a_Size;
      }
    `

    // 片源着色器
    var FSHADER_SOURCE = `
      // 精度限定词:定义精度为中等精度
      precision mediump float;
      // 颜色
      uniform vec4 u_FragColor;
      void main() {
        gl_FragColor = u_FragColor;
      }
    `
    
    // 初始化着色器
    initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)
  • 上面的代码片段中,你会看到两种不同的变量:
    • attribute,它用来表示与顶点相关的数据,因此只有顶点着色器可以使用它;
    • uniform,它可以表示所有顶点都相同的数据
3. 获取并设置顶点属性
  • 为了修改它们的值,就必须要先获取变量的存储位置。
    你需要分别使用 gl.getAttribLocationgl.getUniformLocation 来获取不同类型变量的地址。
    然后将值写入获取的位置中。
    // 3.1 位置:分配给a_Position变量
    var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
    // 3.2 大小:分配给a_Size变量
    var a_Size = gl.getAttribLocation(gl.program, 'a_Size');
    // 3.3 颜色:分配给u_FragColor变量
    var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');

    // 3.4 设置上述参数
    gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
    gl.vertexAttrib1f(a_Size, 15.0);
    gl.uniform4f(u_FragColor, 1.0, 0.0, 1.0, 1.0);
4. 设置背景色并清空画布 (可以跳过)
  • 这里主要用于设置背景颜色,跳过的话背景就是白色的。
    gl.clear(gl.COLOR_BUFFER_BIT) 就是在告诉webGL清空颜色缓冲区(除此外还有深度缓冲区和模板缓冲区)
    // 4. 设置背景色:用clearColor清空颜色缓冲区
    gl.clearColor(0.1, 0.2, 0.3, 0.7);
    gl.clear(gl.COLOR_BUFFER_BIT);
5. 执行绘制命令
  • gl.drawArrays,可以被用来绘制各种图形,这里主要是点因此使用 gl.POINTS这个常量。
    // 5. 绘制图形
    gl.drawArrays(gl.POINTS, 0, 1);

你可以通过下面的在线代码进行不同的尝试。

Step2:绘制多个点 -> 绘制多边形

  • 为了绘制多个点,webGL提供一种机制,叫缓冲区对象(buffer object),它可以一次性向着色器传入多个顶点数据。
  • 在 Step1 绘制单个点的基础上,我们新建一个方法用来创建多个点。
function initVertexBuffers(gl) {
    // 这里设置了4个点
    const pointLength = 2;  // 这里用来表示一个点需要几个数据来表示
    const vertices = new Float32Array([
        -0.5, 0.5,
        -0.5, -0.5, 
        0.5, -0.5, 
        0.5, 0.5, 
    ]);
    // 一共创建了n个点
    var n = vertices.length / pointLength;

    // 1. 创建缓冲区对象
    var vertexBuffer = gl.createBuffer();
    
    // 2. 绑定缓冲区对象到目标
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    
    // 3. 向缓冲区对象写入数据
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
    
    // 4.1 获取a_Position变量的存储地址
    var a_Position = gl.getAttribLocation(gl.program, 'a_Position');

    // 4.2 关联a_Position变量与缓冲区对象
    gl.vertexAttribPointer(a_Position, pointLength, gl.FLOAT, false, 0, 0);
    
    // 5. 开启a_Position变量
    gl.enableVertexAttribArray(a_Position);

    return n;
}
  • 具体的流程可以看下图

image.png

  • 获取点位置后需要将drawArrays中的3个参数,改为n,就可以出现我们设置的点啦。
  • 你也可以修改第1个参数,来修改渲染图形的型状。
    // 5. 绘制图形
    gl.drawArrays(gl.POINTS, 0, n);

image.png

Over

好了,经过上述的步骤,你已经能够使用webGL来绘制基本的图形了。
下一章将主要介绍变换、缩放来让你的图形动起来。