这是我参与「第五届青训营 」笔记创作活动的第16天
WebGL简介
WebGL是一种用于在Web浏览器中渲染3D和2D图形的API(应用程序编程接口)。它基于OpenGL ES(嵌入式系统)2.0规范,可以在Web浏览器中使用JavaScript语言编写3D和2D图形应用程序。WebGL可以与HTML、CSS和JavaScript等Web技术集成,使得用户可以在浏览器中无需任何插件即可查看和交互式的3D和2D图形内容。
WebGL的功能非常强大,可以用于创建各种类型的应用程序,包括游戏、数据可视化、CAD应用程序、虚拟现实和增强现实应用程序等。WebGL能够利用GPU(图形处理器)来处理图形,从而提高性能和渲染速度。它还支持各种着色器和特效,使得用户可以创建高度自定义的图形。
WebGL的上手难度相对较高,需要具备一定的图形学和编程知识。开发者需要了解3D数学、着色器编程、WebGL的API等知识,并掌握JavaScript编程语言。但是,一些开发者认为,相比于其他的前端技术,WebGL的难度并不比较高,只要有一定的计算机图形学基础和JavaScript编程经验,就可以学习和使用WebGL技术。
相比于其他的前端技术,WebGL最大的难点在于其复杂性和性能要求。WebGL需要使用GPU进行图形处理,这要求开发者在设计和实现图形算法时必须考虑性能和效率。同时,WebGL中的着色器编程也需要开发者具备一定的数学和算法知识,因此对于初学者来说难度较大。
WebGL进行渲染或者绘图的过程介绍
WebGL的渲染或者绘图过程大致可以分为以下步骤:
- 准备画布:在Web页面中创建一个HTML canvas元素,并设置其大小和位置。这个画布将用于显示WebGL绘制或者渲染的图形内容。
- 初始化WebGL:通过JavaScript获取canvas元素并创建WebGL上下文。这个上下文将被用于执行WebGL API中的函数,从而完成图形的绘制和渲染。
- 准备顶点数据:定义几何图形中的顶点数据,并将这些数据存储在WebGL的缓冲区中。这些数据包括顶点位置、颜色、纹理坐标等等。
- 编写着色器程序:WebGL使用着色器程序来处理几何图形的渲染。着色器程序是一段GLSL(OpenGL着色语言)代码,分为顶点着色器和片元着色器。顶点着色器负责处理顶点的位置和颜色信息,片元着色器负责处理像素的颜色信息。
- 编译和链接着色器程序:将着色器代码编译成着色器对象,并将顶点着色器和片元着色器链接成WebGL程序对象。这个程序对象将在后续的绘制和渲染过程中使用。
- 设置WebGL状态:设置WebGL的各种状态,例如背景颜色、深度测试、面剔除等。这些状态可以影响图形的绘制和渲染结果。
- 绘制图形:使用WebGL API中的函数来绘制图形。这些函数包括绑定缓冲区、设置顶点属性、绘制图元等。绘制过程将使用前面准备好的顶点数据、着色器程序和WebGL状态来渲染图形。
- 显示图形:将绘制的图形显示在HTML canvas元素中。这样用户就可以在Web页面中看到绘制或者渲染的图形内容。
2D Mesh.js和webGL进行代码编写的区别
用2D Mesh.js和webGL绘制一个大小相同的红色三角形,代码编写的区别如下:
使用2D Mesh.js绘制红色三角形的代码:
javascript
// 创建canvas元素
const canvas = document.createElement('canvas');
canvas.width = 400;
canvas.height = 400;
document.body.appendChild(canvas);
// 创建2D上下文
const ctx = canvas.getContext('2d');
// 绘制红色三角形
ctx.fillStyle = 'red';
ctx.beginPath();
ctx.moveTo(100, 100);
ctx.lineTo(300, 100);
ctx.lineTo(200, 300);
ctx.fill();
使用WebGL绘制红色三角形的代码:
html
<!-- 创建canvas元素 -->
<canvas id="glcanvas" width="400" height="400"></canvas>
<script>
const canvas = document.querySelector("#glcanvas");
const gl = canvas.getContext("webgl");
// 顶点着色器代码
const vertexShaderSource = `
attribute vec3 aVertexPosition;
void main() {
gl_Position = vec4(aVertexPosition, 1.0);
}
`;
// 片元着色器代码
const fragmentShaderSource = `
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}
`;
// 编译和链接着色器程序
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
// 准备顶点数据
const triangleVertices = [
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.0, 0.5, 0.0
];
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(triangleVertices), gl.STATIC_DRAW);
// 设置顶点属性
const vertexPositionAttribute = gl.getAttribLocation(shaderProgram, 'aVertexPosition');
gl.enableVertexAttribArray(vertexPositionAttribute);
gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
// 设置WebGL状态
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
gl.viewport(0, 0, canvas.width, canvas.height);
// 绘制图形
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
Transforms
在计算机图形学中,Transforms(变换)是指将一个对象在二维或三维空间中进行平移、旋转和缩放等变换操作,以达到改变对象位置、方向、大小等目的的技术。
在二维图形学中,Transforms 包含平移(Translation)、旋转(Rotation)和缩放(Scale)三种变换。在三维图形学中,除了这三种变换之外,还有透视(Perspective)和投影(Projection)等变换。
以下是平移、旋转和缩放的数学公式:
- 平移变换: 将二维图形 (x, y) 沿着 x 轴平移 tx,沿着 y 轴平移 ty,得到变换后的点 (x', y')。
x' = x + tx y' = y + ty
- 旋转变换: 将二维图形 (x, y) 按照角度 θ 逆时针旋转,得到变换后的点 (x', y')。
x' = x * cos(θ) - y * sin(θ) y' = x * sin(θ) + y * cos(θ)
- 缩放变换: 将二维图形 (x, y) 沿着 x 轴缩放 sx 倍,沿着 y 轴缩放 sy 倍,得到变换后的点 (x', y')。
x' = x * sx y' = y * sy
在编程时,可以使用 JavaScript 和 webGL 来实现这些变换。通常情况下,webGL 使用变换矩阵来执行平移、旋转和缩放等变换操作。
下面是一些示例代码,展示如何使用 webGL 实现平移、旋转和缩放:
- 平移变换
javascript
function translate(x, y, z) {
// 创建平移矩阵
const matrix = new Float32Array([
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
x, y, z, 1
]);
// 将矩阵传递给着色器程序
const matrixLocation = gl.getUniformLocation(program, "u_matrix");
gl.uniformMatrix4fv(matrixLocation, false, matrix);
}
- 旋转变换
javascript
function rotate(angle, x, y, z) {
const rad = angle * Math.PI / 180;
// 创建旋转矩阵
const sin = Math.sin(rad);
const cos = Math.cos(rad);
const len = Math.sqrt(x * x + y * y + z * z);
x /= len;
y /= len;
z /= len;
const matrix = new Float32Array([
x*x*(1-cos)+cos, x*y*(1-cos)-z*sin, x*z*(1-cos)+y*sin, 0,
x*y*(1-cos)+z*sin, y*y*(1-cos)+cos, y*z*(1-cos)-x*sin, 0,
x*z*(1-cos)-y*sin, y*z*(1-cos)+x*sin, z*z*(1-cos)+cos, 0,
0, 0, 0, 1
]);
// 将矩阵传递给着色器程序
const matrixLocation = gl.getUniformLocation(program, "u_matrix");
gl.uniformMatrix4fv(matrixLocation, false, matrix);
}
- 缩放变换
javascript
function scale(sx, sy, sz) {
// 创建缩放矩阵
const matrix = new Float32Array([
sx, 0, 0, 0,
0, sy, 0, 0,
0, 0, sz, 0,
0, 0, 0, 1
]);
// 将矩阵传递给着色器程序
const matrixLocation = gl.getUniformLocation(program, "u_matrix");
gl.uniformMatrix4fv(matrixLocation, false, matrix);
}
以上代码中,我们创建了三个函数 translate、rotate 和 scale,它们分别用于进行平移、旋转和缩放变换。这些函数中,我们首先计算出对应的变换矩阵,然后将其传递给着色器程序中的 u_matrix 变量。
当我们需要对一个图形进行变换时,我们可以将上述函数组合使用,比如:
javascript
// 平移变换
translate(100, 100, 0);
// 旋转变换
rotate(45, 0, 0, 1);
// 缩放变换
scale(2, 2, 2);
在这个例子中,我们先将图形平移了 (100, 100, 0) 的距离,然后将其绕 z 轴旋转了 45 度,最后将其沿着三个轴方向放大了两倍。
当然,在实际开发中,我们可能需要更加复杂的变换组合,但基本思路是一样的:计算变换矩阵,将其传递给着色器程序,然后在绘制图形时使用这个矩阵。
3D标准模型的四个齐次矩阵
3D标准模型的四个齐次矩阵分别是模型矩阵(Model Matrix)、视图矩阵(View Matrix)、投影矩阵(Projection Matrix)和视口矩阵(Viewport Matrix),它们在 3D 图形的渲染过程中都有着重要的作用。
以下对部分矩阵进行实例演示:
-
模型矩阵(Model Matrix):用于将模型从对象坐标系(Model Space)转换到世界坐标系(World Space)。通过对模型矩阵进行平移、旋转、缩放等变换操作,我们可以调整模型的位置、朝向和大小。例如,下面的代码展示了如何使用模型矩阵将一个立方体向右平移:
javascript const modelMatrix = mat4.create(); mat4.translate(modelMatrix, modelMatrix, [2.0, 0.0, 0.0]); gl.uniformMatrix4fv(uModelMatrix, false, modelMatrix);在这段代码中,我们使用
mat4.translate函数将模型矩阵沿 x 轴方向平移了 2 个单位。最后,将更新后的模型矩阵传递给了着色器程序中的uModelMatrix变量。 -
视图矩阵(View Matrix):用于将世界坐标系(World Space)转换到相机坐标系(View Space)。通过对视图矩阵进行平移、旋转等变换操作,我们可以调整相机的位置、朝向和视野范围。例如,下面的代码展示了如何使用视图矩阵将相机向后移动:
javascript const viewMatrix = mat4.create(); mat4.translate(viewMatrix, viewMatrix, [0.0, 0.0, -10.0]); gl.uniformMatrix4fv(uViewMatrix, false, viewMatrix);在这段代码中,我们使用
mat4.translate函数将视图矩阵沿 z 轴方向平移了 10 个单位。最后,将更新后的视图矩阵传递给了着色器程序中的uViewMatrix变量。