个人参加字节跳动的青训营时写的笔记。这部分是月影老师讲的 WebGL 基础。
WebGL 代码有两部分:
CPU 和 GPU:
图像的处理适合交给 GPU,因为图像会有很多的像素点需要处理。
这部分只能说似懂非懂(任重而道远啊),先贴一下课上的示例代码,方便之后看。
创建 WebGL 上下文
const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl");
创建 WebGL 程序(GLSL,顶点着色器、片元着色器)
顶点着色器(Vertex Shader):
片元着色器(Fragment Shader):顶点之间的轮廓中的所有像素都会经过片元着色器处理。(并行处理)
将数据存入缓冲区
将缓冲区数据读取到 GPU
GPU 执行 WebGL 程序,输出结果
完整代码:
// 1. 创建WebGL上下文
const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl");
// 2. 创建WebGL程序
// 2.1 顶点着色器
const vertex = `
attribute vec2 position;
void main() {
gl_PointSize = 1.0;
gl_Position = vec4(position, 1.0, 1.0);
}
`;
// 2.2 片元着色器
const fragment = `
precision mediump float;
void main()
{
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // 类似rgba
}
`;
// 2.3 加载、编译、使用着色器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertex);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragment);
gl.compileShader(fragmentShader);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
const points = new Float32Array([-1, -1, 0, 1, 1, -1]);
// 3. 将数据存入缓存区
const bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
// 4. 将缓冲区数据读取到GPU
const vPosition = gl.getAttribLocation(program, "position");
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vPosition);
// 5. GPU执行WebGL程序
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, points.length / 2); // points中有六个点,实际上只有三个点,所以需要除以2
效果:
canvas 2D 版本:
const canvas = document.querySelector("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();
效果和上图所示一样。(比原生 WebGL 简单好多)
多边形需要进行三角划分
// 1. 创建WebGL上下文
const canvas = document.querySelector("canvas");
const gl = canvas.getContext("webgl");
// 2. 创建WebGL程序
// 2.1 顶点着色器
const vertex = `
attribute vec2 position;
void main() {
gl_PointSize = 1.0;
gl_Position = vec4(position, 1.0, 1.0);
}
`;
// 2.2 片元着色器
const fragment = `
precision mediump float;
void main()
{
gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0);
}
`;
// 2.3 加载、编译、使用着色器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertex);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragment);
gl.compileShader(fragmentShader);
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
gl.useProgram(program);
// 顶点集
const vertices = [
[-1, -1],
[-1, 0],
[0, 0],
[0, -1],
];
const points = vertices.flat(); // 点集
const triangles = earcut(points); // 三角形集(三角划分后的三角性)
const position = new Float32Array(points);
const cells = new Uint16Array(triangles);
// 3. 将数据存入缓存区,这时候需要分点和三角形来分别存
const pointBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, pointBuffer);
gl.bufferData(gl.ARRAY_BUFFER, position, gl.STATIC_DRAW);
const cellsBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, cellsBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, cells, gl.STATIC_DRAW);
// 4. 将缓冲区数据读取到GPU
const vPosition = gl.getAttribLocation(program, "position");
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vPosition);
// 5. GPU执行WebGL程序
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES, cells.length, gl.UNSIGNED_SHORT, 0); // 这部分还不是很明白
效果:
挖了个大坑