# 工作原理

GLSL

  • attribute uniform varying
  • vec2 mat4

WebGL 在 GPU 上的工作基本上分为两部分

  • 第一部分是将顶点转换到裁剪空间坐标
  • 第二部分是基于第一部分的结果绘制像素点

当你调用

export function draw(gl) {
  const primitiveType = gl.TRIANGLES;
  const offset = 0;
  const count = 9;
  gl.drawArrays(primitiveType, offset, count);  
}

这里的9表示“处理9个顶点”,所以将会有9个顶点被转换。

左侧是你提供的数据。顶点着色器(Vertex Shader)是你写进GLSL 中的一个方法,每个顶点调用一次,在这个方法中做一些数学运算后设置了一个特殊的gl_Position变量, 这个变量就是该顶点转换到裁剪空间中的坐标值,GPU接收该值并将其保存起来。

# 三角形

// 定义一个三角形填充到缓冲里
function setGeometry(gl) {
  const WIDTH = gl.canvas.width
  const HEIGHT  = gl.canvas.height
  gl.bufferData(
    gl.ARRAY_BUFFER,
    new Float32Array([
      WIDTH * 0.5,
      HEIGHT * (1 - 0.75),
      WIDTH * 0.06,
      HEIGHT * (1 - 0.17),  
      WIDTH * 0.88,
      HEIGHT * (1 - 0.09)
    ]),
    gl.STATIC_DRAW
  );
}

然后在我们的顶点着色器中定义一个 varying(可变量)用来给片断着色器传值。

// 一个属性变量,将会从缓冲中获取数据
attribute vec2 a_position;
uniform mat3 u_matrix;
varying vec4 v_color;

void main() {
  // 将位置和矩阵相乘
  gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);

  // 从裁减空间转换到颜色空间
  // 裁减空间范围 -1.0 到 +1.0
  // 颜色空间范围 0.0 到 1.0  
  v_color = gl_Position * 0.5 + 0.5;
}

在片断着色器中定义同名 varying 变量。

precision mediump float; // 这决定了 GPU 在计算浮点数时使用的精度。
// highp 高精度
// mediump 中精度
// lowp 低精度
varying vec4 v_color; // 同名变量

void main() {
  gl_FragColor = v_color;
}

# 渲染结果

# 着色原理

WebGL先获得顶点着色器中计算的三个颜色值,在光栅化三角形时将会根据这三个值进行插值。 每一个像素在调用片断着色器时,可变量的值是与之对应的插值。

我们的给顶点着色器施加了一个包含平移,旋转和缩放的的矩阵,并将结果转换到裁剪空间。

gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);

同时将这些值转换到颜色空间中赋给我们定义的可变量v_color。

v_color = gl_Position * 0.5 + 0.5;

利用这三个值进行插值后传进每个像素运行的片断着色器中。

varying vec4 v_color; // 同名变量

void main() {
  gl_FragColor = v_color;
}

# 缓冲操作

缓冲操作是在GPU上获取顶点和其他顶点数据的一种方式。

  • gl.createBuffer创建一个缓冲
  • gl.bindBuffer是设置缓冲为当前使用缓冲
  • gl.bufferData将数据拷贝到缓冲,这个操作一般在初始化完成
// 创建对应缓冲
const positionBuffer = gl.createBuffer();
// 绑定位置信息缓冲
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
// 通过绑定点向缓冲中存放数据
gl.bufferData(
  gl.ARRAY_BUFFER,
  new Float32Array([0, 0, 0, 0.5, 0.7, 0]),
  gl.STATIC_DRAW
);

一旦数据存到缓冲中,还需要告诉WebGL怎么从缓冲中提取数据传给顶点着色器的属性。

// 开启属性
gl.enableVertexAttribArray(positionLocation);
// 告诉属性怎么从 ARRAY_BUFFER 中读取数据
const size = 2;  // 每次迭代运行提取两个单位数据
const type = gl.FLOAT;  // 每个单位的数据类型是32位浮点型
const normalize = false;  // 不需要归一化数据
const stride = 0;  // 每次迭代运行运动多少内存到下一个数据开始点
// 0 = 移动单位数量 * 每个单位占用内存(sizeof(type))
const offset = 0;  // 从缓冲起始位置开始读取
// 告诉如何使用传入的数据
gl.vertexAttribPointer(
  positionLocation,
  size,
  type,
  normalize,
  stride,
  offset
);