时隔2年再次回顾webgl的基础学习,基础忘记的差不多了,还是得做个记录总结一下。
本文整合了《WebGL编程指南》第二、三章的部分内容,旨在系统性地介绍WebGL的基本概念、绘制流程以及着色器编程。
我们首先需要对WebGL有一个基础的认识,WebGL的核心是一个光栅化引擎,它基于OpenGL ES,通过JavaScript在HTML5的 <canvas> 元素中绘制3D图形。其编程模式与传统的CPU编程截然不同,主要依赖于着色器(Shader) 。
好了,废话不多说,让我们直接进入正题。
Step1:绘制一个点
效果如下图所示。
那么为达到上述效果,我们需要经过以下几个步骤:
1. 获取Canvas元素和WebGL上下文
2. 初始化着色器程序
3. 获取并设置顶点属性
4. 设置背景色并清空画布
5. 执行绘制命令
1. 获取Canvas元素和WebGL上下文
var canvas = document.getElementById('webgl');
var gl = canvas.getContext('webgl')
2. 初始化着色器程序
// 顶点着色器
var VSHADER_SOURCE = `
// 位置
attribute vec4 a_Position;
// 大小
attribute float a_Size;
void main() {
gl_Position = a_Position;
gl_PointSize = a_Size;
}
`
// 片源着色器
var FSHADER_SOURCE = `
// 精度限定词:定义精度为中等精度
precision mediump float;
// 颜色
uniform vec4 u_FragColor;
void main() {
gl_FragColor = u_FragColor;
}
`
// 初始化着色器
initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)
- 上面的代码片段中,你会看到两种不同的变量:
- attribute,它用来表示与顶点相关的数据,因此只有顶点着色器可以使用它;
- uniform,它可以表示所有顶点都相同的数据
- attribute,它用来表示与顶点相关的数据,因此只有顶点着色器可以使用它;
3. 获取并设置顶点属性
- 为了修改它们的值,就必须要先获取变量的存储位置。
你需要分别使用 gl.getAttribLocation 和 gl.getUniformLocation 来获取不同类型变量的地址。
然后将值写入获取的位置中。
// 3.1 位置:分配给a_Position变量
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
// 3.2 大小:分配给a_Size变量
var a_Size = gl.getAttribLocation(gl.program, 'a_Size');
// 3.3 颜色:分配给u_FragColor变量
var u_FragColor = gl.getUniformLocation(gl.program, 'u_FragColor');
// 3.4 设置上述参数
gl.vertexAttrib3f(a_Position, 0.0, 0.0, 0.0);
gl.vertexAttrib1f(a_Size, 15.0);
gl.uniform4f(u_FragColor, 1.0, 0.0, 1.0, 1.0);
4. 设置背景色并清空画布 (可以跳过)
- 这里主要用于设置背景颜色,跳过的话背景就是白色的。
gl.clear(gl.COLOR_BUFFER_BIT) 就是在告诉webGL清空颜色缓冲区(除此外还有深度缓冲区和模板缓冲区)
// 4. 设置背景色:用clearColor清空颜色缓冲区
gl.clearColor(0.1, 0.2, 0.3, 0.7);
gl.clear(gl.COLOR_BUFFER_BIT);
5. 执行绘制命令
- gl.drawArrays,可以被用来绘制各种图形,这里主要是点因此使用 gl.POINTS这个常量。
// 5. 绘制图形
gl.drawArrays(gl.POINTS, 0, 1);
你可以通过下面的在线代码进行不同的尝试。
Step2:绘制多个点 -> 绘制多边形
- 为了绘制多个点,webGL提供一种机制,叫缓冲区对象(buffer object),它可以一次性向着色器传入多个顶点数据。
- 在 Step1 绘制单个点的基础上,我们新建一个方法用来创建多个点。
function initVertexBuffers(gl) {
// 这里设置了4个点
const pointLength = 2; // 这里用来表示一个点需要几个数据来表示
const vertices = new Float32Array([
-0.5, 0.5,
-0.5, -0.5,
0.5, -0.5,
0.5, 0.5,
]);
// 一共创建了n个点
var n = vertices.length / pointLength;
// 1. 创建缓冲区对象
var vertexBuffer = gl.createBuffer();
// 2. 绑定缓冲区对象到目标
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// 3. 向缓冲区对象写入数据
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
// 4.1 获取a_Position变量的存储地址
var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
// 4.2 关联a_Position变量与缓冲区对象
gl.vertexAttribPointer(a_Position, pointLength, gl.FLOAT, false, 0, 0);
// 5. 开启a_Position变量
gl.enableVertexAttribArray(a_Position);
return n;
}
- 具体的流程可以看下图
- 获取点位置后需要将drawArrays中的3个参数,改为n,就可以出现我们设置的点啦。
- 你也可以修改第1个参数,来修改渲染图形的型状。
// 5. 绘制图形
gl.drawArrays(gl.POINTS, 0, n);
Over
好了,经过上述的步骤,你已经能够使用webGL来绘制基本的图形了。
下一章将主要介绍变换、缩放来让你的图形动起来。