webgl工作原理

2023/8/22 webgl3D

我们已经知道了webgl基本概念,那么WebGL在GPU上究竟做了什么呢?

WebGL在GPU上的工作基本上分为两部分,第一部分是将顶点(或数据流)转换到裁剪空间坐标, 第二部分是基于第一部分的结果绘制像素点。

  • 坐标映射:vertex shadergl_Position
  • 像素绘制: fragment shadergl_FragColor

比如下述代码:

var primitiveType = gl.TRIANGLES;
var offset = 0;
var count = 9;
gl.drawArrays(primitiveType, offset, count);
1
2
3
4

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

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

比如绘制三角形:

See the Pen WebGL - Triangle with position for color by Keekuun (@keekuun) on CodePen.

  • 定义顶点:顶点着色器(Vertex Shader)每完成三次顶点处理,WebGL就会用这三个顶点(gl_Position)画一个三角形
  • 绘制像素:计算出这三个顶点对应的像素后,就会光栅化这个三角形,“光栅化”其实就是“用像素画出来” 的花哨叫法。
  • 填充颜色:对于每一个像素,它会调用你的片段着色器询问你使用什么颜色。 你通过给片段着色器的一个特殊变量gl_FragColor设置一个颜色值,实现自定义像素颜色。

想要从顶点着色器传值到片段着色器,我们可以定义“可变量(varyings)”。

<canvas id="canvas"></canvas>

<!-- vertex shader -->
<script  id="vertex-shader-2d" type="x-shader/x-vertex">
attribute vec2 a_position;
attribute vec4 a_color;

uniform mat3 u_matrix;

varying vec4 v_color; // 定义变量接收

void main() {
  // Multiply the position by the matrix.
  gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1);

  // Copy the color from the attribute to the varying.
  v_color = a_color; // 变量赋值
}
</script>
<!-- fragment shader -->
<script  id="fragment-shader-2d" type="x-shader/x-fragment">
precision mediump float;

varying vec4 v_color; // 定义同名变量

void main() {
  gl_FragColor = v_color; // 变量赋值
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

然后:

function main() {
  // Get A WebGL context
  /** @type {HTMLCanvasElement} */
  var canvas = document.querySelector("#canvas");
  var gl = canvas.getContext("webgl");
  if (!gl) {
    return;
  }

  // setup GLSL program
  var program = webglUtils.createProgramFromScripts(gl, ["vertex-shader-2d", "fragment-shader-2d"]);

  // 询问顶点数据应该放在哪里
  // look up where the vertex data needs to go.
  var positionLocation = gl.getAttribLocation(program, "a_position");
  var colorLocation = gl.getAttribLocation(program, "a_color");

  // lookup uniforms
  var matrixLocation = gl.getUniformLocation(program, "u_matrix");
  
  // ...
}

main();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

关于buffer和attribute的代码是干什么的?

缓冲操作是在GPU上获取顶点和其他顶点数据的一种方式。 gl.createBuffer创建一个缓冲;gl.bindBuffer是设置缓冲为当前使用缓冲; gl.bufferData将数据拷贝到缓冲,这个操作一般在初始化完成。

Demo:

See the Pen WebGL - Fundamentals by Keekuun (@keekuun) on CodePen.