这是我参与「第四届青训营 」笔记创作活动的的第13天
初识WebGL
Why WebGL / Why GPU ?
- WebGL是什么:GPU != WebGL != 3D,它是一种3D绘图协议,属于OpenGL的子集,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染。
- GPU是什么:GPU有由大量的小运算单元组成,每个运算单元只负责处理很简单的计算,每个运算单元彼此独立,因此所有计算可以并行处理。
WebGL使用
- 创建WebGL上下文
- 创建WebGL Program
- 将数据存入缓冲区
- 将缓冲区数据读取到GPU中
- GPU执行WebGL程序,输出结果
如何利用WebGL绘制一个点
要使用WebGL进行绘图就必须使用着色器,在代码中,着色器是一字符串的形式‘嵌入’在JavaScript文件中的,在程序运行前它就已经设置好了。
顶点着色器:用来描述顶点的特性(如位置、颜色等)的程序。顶点是指二维或三维中的一个点。
片元着色器:进行逐片元处理过程的程序。片元是一个webgl中的术语,你可以理解为像素(图片的单元)。
3D矩阵
3D标准模型的四个齐次矩阵(mat4):
- 投影矩阵
- 模型矩阵
- 视图矩阵
- 法向量矩阵
WebGL绘制三角形
// 顶点着色器代码
const vertex_source = `
attribute vec3 aPos;
void main() {
gl_Position = vec4(aPos, 1);
}
`;
// 片段着色器代码
const fragment_source = `
precision mediump float;
uniform vec3 uColor;
void main() {
gl_FragColor = vec4(uColor, 1.0);
}
`;
// 三角形的顶点数据
const vertexs: number[] = [
0, 0.5, 0,
-0.5, 0, 0,
0.5, 0, 0
];
const draw = (gl: WebGLRenderingContext) => {
// 1.准备工作
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); // 告诉webgl窗口大小
gl.clearColor(0, 0, 0, 0); // 设定clearColor的颜色缓冲
gl.clear(gl.COLOR_BUFFER_BIT); // 用clearColor的颜色,清屏
// 2.创建着色器程序
// 创建顶点着色器
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertex_source); // 绑定着色器代码
gl.compileShader(vertexShader); // 编译着色器
var success = gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS);
if (!success) {
throw "colud not compile vertex shader:" + gl.getShaderInfoLog(vertexShader);
}
// 创建片段着色器
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragment_source); // 绑定着色器代码
gl.compileShader(fragmentShader); // 编译着色器
success = gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS);
if (!success) {
throw "colud not compile vertex shader:" + gl.getShaderInfoLog(fragmentShader);
}
// 链接着色器程序
var program = gl.createProgram();
gl.attachShader(program, vertexShader); // 添加着色器
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!success) {
throw "colud not link shader: " + gl.getProgramInfoLog(program);
}
// 已经链接成程序,可以删除着色器
gl.deleteShader(vertexShader);
gl.deleteShader(fragmentShader);
gl.useProgram(program);
// 3. 传递数据
// 传递attribute数据
const aPosAttLocation = gl.getAttribLocation(program, "aPos");
const aPosAttBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, aPosAttBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertexs), gl.STATIC_DRAW);
gl.vertexAttribPointer(aPosAttLocation, 3, gl.FLOAT, false, 0, 0); // 告诉gl如何解析数据
gl.enableVertexAttribArray(aPosAttLocation);
// 传递全局变量数据
const uColorLocation = gl.getUniformLocation(program, "uColor");
gl.uniform3f(uColorLocation, 0.36, 0.42, 0.60);
// 4. 绘制
gl.drawArrays(gl.TRIANGLES, 0, 3);
总结
一些简单的图形我们可以直接通过canvas2d直接绘制,但是当遇到一些复杂且像素多的图的时候,canvas2d的效率就偏低且难以实现。这时我们就可以通过WebGL来实现,同时,如果我们要实现复杂的粒子效果,那么WebGL就是不二首选。