计算机图形学是一门迷人的领域,它将数学原理与计算机编程紧密结合,创造出令人惊叹的视觉效果。无论是制作精美的游戏、逼真的动画,还是进行科学数据可视化,扎实的数学基础都是理解和实现复杂图形算法的关键。本文将深入探讨计算机图形学中不可或缺的数学知识,并通过 JavaScript 代码示例展示其实际应用。
一、向量基础
1.1 向量的定义与表示
向量是计算机图形学中的基本概念,它既有大小又有方向。在二维空间中,向量可以表示为[x, y],三维空间中则为[x, y, z]。例如,在 JavaScript 中,我们可以用数组来表示向量:
// 二维向量
let vector2D = [2, 3];
// 三维向量
let vector3D = [1, -2, 4];
1.2 向量的运算
1.2.1 向量加法
向量加法遵循平行四边形法则或三角形法则。在 JavaScript 中,实现向量加法的函数如下:
function addVectors(vectorA, vectorB) {
return [vectorA[0] + vectorB[0], vectorA[1] + vectorB[1]];
}
// 示例
let vectorA = [1, 2];
let vectorB = [3, 4];
let result = addVectors(vectorA, vectorB);
console.log(result); // 输出: [4, 6]
1.2.2 向量减法
向量减法是加法的逆运算。其 JavaScript 实现如下:
function subtractVectors(vectorA, vectorB) {
return [vectorA[0] - vectorB[0], vectorA[1] - vectorB[1]];
}
// 示例
let vectorC = [5, 7];
let vectorD = [2, 3];
let difference = subtractVectors(vectorC, vectorD);
console.log(difference); // 输出: [3, 4]
1.2.3 向量点积
向量点积(也称为内积)用于衡量两个向量的相似程度,其结果是一个标量。点积的计算公式为:A·B = |A|×|B|×cos(θ),其中θ是两个向量之间的夹角。在 JavaScript 中:
function dotProduct(vectorA, vectorB) {
return vectorA[0] * vectorB[0] + vectorA[1] * vectorB[1];
}
// 示例
let vectorE = [2, 3];
let vectorF = [4, -1];
let dotResult = dotProduct(vectorE, vectorF);
console.log(dotResult); // 输出: 5
点积在图形学中有广泛应用,如计算光照模型中的光照强度,判断两个向量的方向关系等。
1.2.4 向量叉积
向量叉积仅适用于三维向量,其结果是一个与两个输入向量都垂直的向量。叉积的大小等于两个向量构成的平行四边形的面积。在 JavaScript 中:
function crossProduct(vectorA, vectorB) {
return [
vectorA[1] * vectorB[2] - vectorA[2] * vectorB[1],
vectorA[2] * vectorB[0] - vectorA[0] * vectorB[2],
vectorA[0] * vectorB[1] - vectorA[1] * vectorB[0]
];
}
// 示例
let vectorG = [1, 2, 3];
let vectorH = [4, 5, 6];
let crossResult = crossProduct(vectorG, vectorH);
console.log(crossResult); // 输出: [-3, 6, -3]
叉积常用于计算平面的法向量,判断物体的旋转方向等。
二、矩阵基础
2.1 矩阵的定义与表示
矩阵是一个二维数组,在计算机图形学中用于表示线性变换。例如,一个 2x2 的矩阵可以表示为:( \begin{bmatrix} a & b \ c & d \end{bmatrix} )
在 JavaScript 中,我们可以用二维数组来表示矩阵:
// 2x2矩阵
let matrix2x2 = [
[1, 2],
[3, 4]
];
2.2 矩阵运算
2.2.1 矩阵加法
两个矩阵相加,对应位置的元素相加即可。前提是两个矩阵的大小相同。JavaScript 实现如下:
function addMatrices(matrixA, matrixB) {
let result = [];
for (let i = 0; i < matrixA.length; i++) {
let row = [];
for (let j = 0; j < matrixA[0].length; j++) {
row.push(matrixA[i][j] + matrixB[i][j]);
}
result.push(row);
}
return result;
}
// 示例
let matrix1 = [
[1, 2],
[3, 4]
];
let matrix2 = [
[5, 6],
[7, 8]
];
let sumMatrix = addMatrices(matrix1, matrix2);
console.log(sumMatrix);
// 输出:
// [
// [6, 8],
// [10, 12]
// ]
2.2.2 矩阵乘法
矩阵乘法较为复杂,只有当第一个矩阵的列数等于第二个矩阵的行数时,两个矩阵才能相乘。结果矩阵的元素C[i][j]等于第一个矩阵的第i行与第二个矩阵的第j列对应元素乘积之和。JavaScript 实现如下:
function multiplyMatrices(matrixA, matrixB) {
let result = [];
for (let i = 0; i < matrixA.length; i++) {
let row = [];
for (let j = 0; j < matrixB[0].length; j++) {
let sum = 0;
for (let k = 0; k < matrixA[0].length; k++) {
sum += matrixA[i][k] * matrixB[k][j];
}
row.push(sum);
}
result.push(row);
}
return result;
}
// 示例
let matrix3 = [
[1, 2],
[3, 4]
];
let matrix4 = [
[5, 6],
[7, 8]
];
let productMatrix = multiplyMatrices(matrix3, matrix4);
console.log(productMatrix);
// 输出:
// [
// [19, 22],
// [43, 50]
// ]
在图形学中,矩阵乘法常用于复合变换,如先旋转再平移等。通过将多个变换矩阵相乘,可以得到一个综合的变换矩阵,然后应用于图形对象上。
三、三角函数
3.1 基本三角函数
在计算机图形学中,三角函数用于处理角度、旋转和几何形状等问题。JavaScript 内置了Math对象,提供了常用的三角函数方法,如Math.sin()、Math.cos()、Math.tan()等。这些函数接受的参数是弧度制,而非角度制。如果需要使用角度,需要先将其转换为弧度,转换公式为:弧度 = 角度 × (π / 180)。
例如,计算 30 度角的正弦值:
let degrees = 30;
let radians = degrees * (Math.PI / 180);
let sineValue = Math.sin(radians);
console.log(sineValue); // 输出约0.5
3.2 三角函数在图形学中的应用
在实现图形的旋转效果时,三角函数发挥着关键作用。假设我们要将一个点(x, y)绕原点旋转θ角度,旋转后的点(x', y')可以通过以下公式计算:( x' = x à cos(θ) - y à sin(θ) )
( y' = x à sin(θ) + y à cos(θ) )
在 JavaScript 中,可以实现一个旋转点的函数:
function rotatePoint(x, y, angleInRadians) {
let cosTheta = Math.cos(angleInRadians);
let sinTheta = Math.sin(angleInRadians);
let newX = x * cosTheta - y * sinTheta;
let newY = x * sinTheta + y * cosTheta;
return [newX, newY];
}
// 示例
let point = [2, 3];
let angle = 45 * (Math.PI / 180); // 45度转换为弧度
let rotatedPoint = rotatePoint(point[0], point[1], angle);
console.log(rotatedPoint);
// 输出: 旋转后的点坐标
此外,在计算光照模型中的入射角、反射角,以及处理曲线、曲面等几何形状时,三角函数也都有着广泛的应用。
四、线性代数在图形变换中的应用
4.1 二维图形变换
4.1.1 平移变换
平移变换是将图形在平面上移动一定的距离。对于一个点(x, y),沿x轴方向平移tx,沿y轴方向平移ty,平移后的点(x', y')为:( x' = x + tx )
( y' = y + ty )
在 JavaScript 中,可以通过以下函数实现点的平移:
function translatePoint(x, y, tx, ty) {
return [x + tx, y + ty];
}
// 示例
let originalPoint = [1, 1];
let translatedPoint = translatePoint(originalPoint[0], originalPoint[1], 3, 2);
console.log(translatedPoint); // 输出: [4, 3]
4.1.2 缩放变换
缩放变换用于改变图形的大小。对于一个点(x, y),沿x轴方向缩放sx倍,沿y轴方向缩放sy倍,缩放后的点(x', y')为:( x' = x à sx )
( y' = y à sy )
JavaScript 实现如下:
function scalePoint(x, y, sx, sy) {
return [x * sx, y * sy];
}
// 示例
let pointToScale = [2, 3];
let scaledPoint = scalePoint(pointToScale[0], pointToScale[1], 2, 0.5);
console.log(scaledPoint); // 输出: [4, 1.5]
4.1.3 旋转变换
前面已经介绍过通过三角函数实现点绕原点的旋转变换。在矩阵变换中,二维旋转变换可以用一个 2x2 的旋转矩阵表示:( \begin{bmatrix} cos(θ) & -sin(θ) \ sin(θ) & cos(θ) \end{bmatrix} )
将点(x, y)表示为列向量[x, y]^T,通过矩阵乘法[旋转矩阵] × [点向量]即可得到旋转后的点向量。在 JavaScript 中,可以结合前面的矩阵乘法函数实现基于矩阵的旋转变换:
function rotatePointMatrix(x, y, angleInRadians) {
let rotationMatrix = [
[Math.cos(angleInRadians), -Math.sin(angleInRadians)],
[Math.sin(angleInRadians), Math.cos(angleInRadians)]
];
let pointVector = [[x], [y]];
let resultMatrix = multiplyMatrices(rotationMatrix, pointVector);
return [resultMatrix[0][0], resultMatrix[1][0]];
}
// 示例
let pointForRotation = [3, 4];
let rotationAngle = 30 * (Math.PI / 180);
let rotatedPointMatrix = rotatePointMatrix(pointForRotation[0], pointForRotation[1], rotationAngle);
console.log(rotatedPointMatrix);
// 输出: 基于矩阵旋转后的点坐标
4.2 三维图形变换
三维图形变换在二维变换的基础上增加了z轴方向的操作,并且涉及到更多复杂的变换矩阵。
4.2.1 三维平移变换
对于一个三维点(x, y, z),沿x轴平移tx,沿y轴平移ty,沿z轴平移tz,平移后的点(x', y', z')为:( x' = x + tx )
( y' = y + ty )
( z' = z + tz )
在 JavaScript 中实现三维点平移的函数如下:
function translatePoint3D(x, y, z, tx, ty, tz) {
return [x + tx, y + ty, z + tz];
}
// 示例
let point3D = [1, 2, 3];
let translatedPoint3D = translatePoint3D(point3D[0], point3D[1], point3D[2], 1, -1, 2);
console.log(translatedPoint3D); // 输出: [2, 1, 5]
4.2.2 三维缩放变换
三维缩放变换同样是对x、y、z三个方向分别进行缩放。对于点(x, y, z),沿x轴缩放sx,沿y轴缩放sy,沿z轴缩放sz,缩放后的点(x', y', z')为:( x' = x à sx )
( y' = y à sy )
( z' = z à sz )
JavaScript 实现:
function scalePoint3D(x, y, z, sx, sy, sz) {
return [x * sx, y * sy, z * sz];
}
// 示例
let pointToScale3D = [2, 3, 4];
let scaledPoint3D = scalePoint3D(pointToScale3D[0], pointToScale3D[1], pointToScale3D[2], 2, 0.5, 3);
console.log(scaledPoint3D); // 输出: [4, 1.5, 12]
4.2.3 三维旋转变换
三维旋转变换相对复杂,需要指定旋转轴和旋转角度。常见的旋转轴有x轴、y轴和z轴。以绕x轴旋转为例,旋转矩阵为:( \begin{bmatrix} 1 & 0 & 0 \ 0 & cos(θ) & -sin(θ) \ 0 & sin(θ) & cos(θ) \end{bmatrix} )
绕y轴旋转的矩阵为:( \begin{bmatrix} cos(θ) & 0 & sin(θ) \ 0 & 1 & 0 \ -sin(θ) & 0 & cos(θ) \end{bmatrix} )
绕z轴旋转的矩阵为:( \begin{bmatrix} cos(θ) & -sin(θ) & 0 \ sin(θ) & cos(θ) & 0 \ 0 & 0 & 1 \end{bmatrix} )
通过将点表示为三维列向量,与相应的旋转矩阵相乘,即可实现三维点绕特定轴的旋转。在 JavaScript 中,可以基于前面的矩阵乘法函数实现三维旋转变换。例如,实现绕x轴旋转的函数:
function rotateX(x, y, z, angleInRadians) {
let rotationMatrix = [
[1, 0, 0],
[0, Math.cos(angleInRadians), -Math.sin(angleInRadians)],
[0, Math.sin(angleInRadians), Math.cos(angleInRadians)]
];
let pointVector = [[x], [y], [z]];
let resultMatrix = multiplyMatrices(rotationMatrix, pointVector);
return [resultMatrix[0][0], resultMatrix[1][0], resultMatrix[2][0]];
}
// 示例
let point3DForRotation = [1, 2, 3];
let rotationAngleX = 45 * (Math.PI / 180);
let rotatedPoint3DX = rotateX(point3DForRotation[0], point3DForRotation[1], point3DForRotation[2], rotationAngleX);
console.log(rotatedPoint3DX);
// 输出: 绕x轴旋转后的三维点坐标
类似地,可以实现绕y轴和z轴旋转的函数。在实际应用中,常常需要将