一帧画面是怎么来的
GPU 把绘制拆成一条固定的流水线(pipeline),数据从左流到右:
- 顶点数据:你上传到显存的数字,比如三个点的坐标。
- 顶点着色器(vertex shader):每个顶点运行一次,输出它在 裁剪空间 中的位置
gl_Position,x、y 范围是 -1 到 1。 - 图元装配:按
gl.TRIANGLES、gl.LINE_LOOP等模式把顶点连成三角形或线段。 - 光栅化:找出三角形覆盖了哪些像素,为每个像素生成一个片元(fragment)。
- 片元着色器(fragment shader):每个片元运行一次,输出颜色。
- 帧缓冲:颜色写进画布。
其中第 2 步和第 5 步是可编程的,用 GLSL 编写。
着色器:编译与链接
着色器像 C 程序一样需要先编译、再链接成一个 program。编译失败不会抛异常,必须主动查询状态并读取日志:
glsl
#version 300 es
in vec2 aPosition;
void main() {
gl_Position = vec4(aPosition, 0.0, 1.0);
}gl.getShaderParameter(shader, gl.COMPILE_STATUS) 为 false 时,用 gl.getShaderInfoLog 拿到错误信息并打印出来。链接同理,用 LINK_STATUS 和 getProgramInfoLog。
Buffer 与 VAO
- Buffer 是显存里的一块字节数组,
gl.bufferData把Float32Array上传进去。 - VAO(顶点数组对象)记录“怎样读取这块内存”:
gl.vertexAttribPointer(位置, 分量数, 类型, 是否归一化, 步长, 偏移)。之后每次绘制只需绑定 VAO。
绘制
每帧先 gl.viewport 把裁剪空间映射到像素,gl.clear 清屏,然后 useProgram、bindVertexArray,最后 gl.drawArrays(gl.TRIANGLES, 0, 3):3 个顶点,组成 1 个三角形。
点一下面板里的“compile a broken shader”,在控制台读一读真实的编译错误日志:以后调试着色器,这就是你的第一手线索。
核心 API
canvas.getContext('webgl2')gl.createShadergl.compileShadergl.getShaderInfoLoggl.linkProgramgl.createBuffergl.bufferDatagl.createVertexArraygl.vertexAttribPointergl.drawArrays动手试试
- 1把三个顶点之一改到 (0.9, 0.9),看三角形如何变形。
- 2把 primitive 切到 POINTS,再在顶点着色器里改 gl_PointSize。
- 3在顶点着色器里写错一个变量名,读一读控制台中的报错行号。
还没有输出。console.log 的内容会显示在这里。
运行中