WebGL从零开始(六)—— 复习数学知识
# 1.向量
既有大小(Length/Magnitude)又有方向(Direction)的量。在 WebGL 中常用来表示空间中的点、方向、颜色、法线等。
# 1.1向量的运算
- 点乘 (Dot Product):
dot(a, b)。结果是标量。几何意义:∣a∣∣b∣cos(θ)。常用于计算夹角、判断朝向(同向为正,垂直为0,反向为负),是 漫反射光照 的核心。 - 叉乘 (Cross Product):
cross(a, b)。结果是向量,且垂直于 a 和 b 构成的平面。遵循右手定则。常用于计算法线、判断点在直线的哪一侧。 -归一化 (Normalize):normalize(v),保持方向不变,将长度变为 1(单位向量)。光照计算必备。
示例:
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = fragCoord / iResolution.xy;
// 1. 点乘:计算两个向量的相似度(常用于光照)
vec3 lightDir = normalize(vec3(1.0, 1.0, 0.0));
vec3 normal = vec3(0.0, 1.0, 0.0); // 朝上的法线
float diff = max(dot(lightDir, normal), 0.0); // 结果在 0~1 之间
// 2. 叉乘:计算垂直于两个向量的新向量(常用于求法线)
vec3 tangent = vec3(1.0, 0.0, 0.0);
vec3 bitangent = cross(normal, tangent); // 得到垂直于两者的向量
}
2
3
4
5
6
7
8
9
10
11
12
# 2.矩阵
3D 变换的载体。WebGL 使用 4x4 矩阵(齐次坐标),第四维 w 用于处理平移和透视除法。
GLSL ES中,支持 2、3、4维的矩阵:mat2, mat3, mat4。
# 1.矩阵的运算
- 矩阵加法:
- 矩阵减法:
- 矩阵乘法:
C = A * B。不满足交换律 - 矩阵除法:
- 列主序 (Column-Major):OpenGL/WebGL 在内存中按列存储矩阵。
- MVP 变换链:
gl_Position = Projection * View * Model * vec4(position, 1.0);(从右向左读:先模型,再视图,最后投影)。
下面是一个顶点着色器
attribute vec4 a_Position;
uniform mat4 u_ModelMatrix; // 本地 -> 世界
uniform mat4 u_ViewMatrix; // 世界 -> 相机
uniform mat4 u_ProjectionMatrix; // 相机 -> 裁剪空间
void main() {
// 注意:矩阵乘法是从右向左读的!
gl_Position = u_ProjectionMatrix * u_ViewMatrix * u_ModelMatrix * a_Position;
}
2
3
4
5
6
7
8
9
# 3.逆矩阵
矩阵的逆(inverse of a matrix)是数学中满足特定条件的方阵,其与原矩阵相乘得到单位矩阵,类似于数的倒数关系,记作A⁻¹。
可逆矩阵一定是方阵,且其逆矩阵是唯一的。
对于一个n阶方阵A,如果存在一个n阶方阵B,使得AB=BA=I(I为单位矩阵),则称A是可逆的,并把B称为A的逆矩阵,记作A⁻¹。
# 矩阵的逆的解法:
# 1.伴随矩阵法
适用于 二阶或三阶矩阵 对于一个 n×n 的可逆矩阵 A ,其逆矩阵公式为:A⁻¹=$\frac{1}{∣A∣}$⋅A∗
其中 A∗ 就是 A 矩阵的 伴随矩阵。 ∣A∣ 是矩阵 A 的行列式(必须 ≠0 ,否则无逆矩阵)
A* 是代数余子式矩阵的转置。

A*ij 的计算 Aij=(−1)i+j⋅Mij
其中 M**ij 是划去第 i 行和第 j 列后剩下的行列式。
# 2.矩阵的行列式
一个n×n的方阵A的行列式记为det(A)或者|A|,一个2×2矩阵的行列式可表示如下:
行列式的计算法:从左到右对角线乘积之和+从右到左对角线乘积之和的负数:
如三阶矩阵(a,b,c,d,e,f,g,h,i) 的行列式:
# 初等行变换法
也称高斯-若尔当消元法。这是处理 3×3 或更大矩阵时最常用的方法,也适合计算机编程实现。
原理:构造一个增广矩阵 (A∣I) ,其中 I 是单位矩阵。 通过初等行变换,将左边的 A 变为单位矩阵 I 。此时,右边的 I 就会自动变为 A−1 。 即: (A∣I) 行变换 (I∣A−1)
如:矩阵B $$ \begin{pmatrix} 1 & 2 & 3 \ 2 & 5 & 3 \ 1 & 0 & 8 \end{pmatrix} $$
步骤 1:构造增广矩阵 (B∣I)
$$ \left( \begin{array}{ccc|ccc} 1 & 2 & 3 & 1 & 0 & 0 \ 2 & 5 & 3 & 0 & 1 & 0 \ 1 & 0 & 8 & 0 & 0 & 1 \end{array} \right) $$
步骤 2:进行行变换,目标是将左边变为单位矩阵
消去第一列下方的数:
- R2−2R1 (第2行减去第1行的2倍)
- R3−R1 (第3行减去第1行)
$$\left( \begin{array}{ccc|ccc} 1 & 2 & 3 & 1 & 0 & 0 \ 0 & 1 & -3 & -2 & 1 & 0 \ 0 & -2 & 5 & -1 & 0 & 1 \end{array} \right)$$
- 消去第二列下方的数:
- R3+2R2 (第3行加上第2行的2倍)
$$\left(\begin{array}{ccc|ccc} 1 & 2 & 3 & 1 & 0 & 0 \ 0 & 1 & -3 & -2 & 1 & 0 \ 0 & 0 & -1 & -5 & 2 & 1 \end{array}\right)$$
将主对角线元素变为 1:
- R3×(−1) (第3行乘以 -1)
$$\left(\begin{array}{ccc|ccc} 1 & 2 & 3 & 1 & 0 & 0 \ 0 & 1 & -3 & -2 & 1 & 0 \ 0 & 0 & 1 & 5 & -2 & -1 \end{array}\right)$$
现在左边已经是上三角矩阵,接下来从下往上消元
消去第三列上方的数:
R2+3R3 (第2行加上第3行的3倍)
右边计算: (−2)+15=13 , 1+(−6)=−5 , 0+(−3)=−3
R1−3R3 (第1行减去第3行的3倍)
右边计算:1−15=−14 , 0−(−6)=6 , 0−(−3)=3
$$\left(\begin{array}{ccc|ccc} 1 & 2 & 0 & -14 & 6 & 3 \ 0 & 1 & 0 & 13 & -5 & -3 \ 0 & 0 & 1 & 5 & -2 & -1 \end{array}\right)$$
消去第二列上方的数:
- R1−2R2 (第1行减去第2行的2倍)
右边计算: −14−26=−40 , 6−(−10)=16 , 3−(−6)=9
$$\left(\begin{array}{ccc|ccc} 1 & 0 & 0 & -40 & 16 & 9 \ 0 & 1 & 0 & 13 & -5 & -3 \ 0 & 0 & 1 & 5 & -2 & -1 \end{array}\right)$$
得出结果
左边已变为单位矩阵,右边即为逆矩阵:
$$\left(\begin{array}{ccc} -40 & 16 & 9 \ 13 & -5 & -3 \ 5 & -2 & -1 \end{array}\right)$$
# 3.极坐标
O点的射线Ox做极轴,一般以逆时针为正方向。在 Shader 中画圆、扇形、波浪,或实现物体的圆周运动。
公式转换: x=r⋅cos(θ) , y=r⋅sin(θ) 。
示例:会呼吸的圆
uniform float u_Time;
attribute vec2 a_TexCoord; // 假设传入 0.0~1.0 的纹理坐标
void main() {
vec2 uv = a_TexCoord;
vec2 center = vec2(0.5);
// 计算当前点到中心的距离
float dist = distance(uv, center);
// 使用 sin 函数让半径随时间变化(呼吸效果)
float radius = 0.2 + 0.05 * sin(u_Time * 3.0);
// step(a,b): b < a 返回 1.0, 否则返回 0.0
float circle = step(dist, radius);
gl_FragColor = vec4(vec3(circle), 1.0);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 4.坐标系转换
理解 3D 渲染管线必须掌握的五大空间:
- 本地空间 (Local Space):模型自身的坐标系。
- 世界空间 (World Space):所有模型共存的绝对坐标系(通过 Model Matrix(模型矩阵) 变换)。
- 观察/相机空间 (View Space):以相机为原点的坐标系(通过 View Matrix(视图矩阵) 变换)。
- 裁剪空间 (Clip Space):经过投影矩阵变换后的空间,超出 [−1,1] 范围的会被裁剪(通过 Projection Matrix(投影矩阵) 变换)。
- 屏幕空间 (Screen Space):最终映射到 2D 像素的坐标。
# 5.欧拉
用三个角度(Pitch 俯仰, Yaw 偏航, Roll 翻滚)来描述 3D 旋转。
了解 致命缺陷:万向节死锁 (Gimbal Lock)。当两个旋转轴重合时,会丢失一个维度的旋转自由度。在底层引擎和复杂动画中,尽量避免直接使用欧拉角进行插值或连续旋转。
# 6.四元数
用 4 个分量 (x,y,z,w) 表示 3D 旋转的数学工具。
- 优势:完美解决万向节死锁;支持平滑的球面线性插值(Slerp),非常适合相机平滑跟随和骨骼动画。
- 劣势:不直观,人类难以直接手写四元数,通常在 JS 端用库(如 gl-matrix)计算好后传给 Shader。
# 7.齐次坐标
齐次坐标是用 n+1 维向量表示 n 维空间中点的坐标系统,如二维的笛卡尔坐标(x,y),它的齐次坐标为(x,y,w),w默认是1,那么会有
(x,y) = (x,y,1) = (x,y,2) ...
(x,y,1)、(x,y,2)都是(x,y) w只要是大于0的数,那么都(x,y,w)都代表(x,y)。w等于0,代表的就是无穷远。