一、引言
在计算机图形学中,变换矩阵是实现图形平移、旋转、缩放等操作的数学基础。理解变换矩阵不仅有助于掌握图形学的基本原理,也是游戏开发、计算机辅助设计 (CAD)、虚拟现实等领域的必备技能。本文将深入浅出地介绍变换矩阵的基本概念和 JavaScript 实现。
二、基本变换类型
1. 平移变换
平移是将图形从一个位置移动到另一个位置的操作。在二维空间中,平移变换可以表示为:
// 二维平移变换函数
function translate(x, y, tx, ty) {
return [x + tx, y + ty];
}
2. 旋转变换
旋转是将图形绕某个点旋转一定角度的操作。在二维空间中,绕原点旋转 θ 角度的变换可以表示为:
// 二维旋转变换函数(绕原点)
function rotate(x, y, angle) {
const radians = angle * Math.PI / 180;
const cos = Math.cos(radians);
const sin = Math.sin(radians);
return [
x * cos - y * sin,
x * sin + y * cos
];
}
3. 缩放变换
缩放是改变图形大小的操作。在二维空间中,缩放变换可以表示为:
// 二维缩放变换函数
function scale(x, y, sx, sy) {
return [x * sx, y * sy];
}
三、变换矩阵表示
1. 齐次坐标
为了将平移变换也表示为矩阵乘法,引入齐次坐标。在二维空间中,点 (x, y) 的齐次坐标表示为 (x, y, 1)。
2. 二维变换矩阵
在齐次坐标下,二维变换矩阵是一个 3×3 的矩阵:
// 二维变换矩阵类
class Matrix2D {
constructor() {
// 初始化为单位矩阵
this.data = [ [1, 0, 0],
[0, 1, 0],
[0, 0, 1]
];
}
// 矩阵乘法
multiply(matrix) {
const result = new Matrix2D();
// 矩阵乘法实现...
return result;
}
// 设置平移变换
setTranslate(tx, ty) {
this.data = [ [1, 0, tx],
[0, 1, ty],
[0, 0, 1]
];
}
// 设置旋转变换
setRotate(angle) {
const radians = angle * Math.PI / 180;
const cos = Math.cos(radians);
const sin = Math.sin(radians);
this.data = [ [cos, -sin, 0],
[sin, cos, 0],
[0, 0, 1]
];
}
// 设置缩放变换
setScale(sx, sy) {
this.data = [ [sx, 0, 0],
[0, sy, 0],
[0, 0, 1]
];
}
// 应用变换到点
transformPoint(x, y) {
const point = [x, y, 1];
const result = [0, 0, 0];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
result[i] += this.data[i][j] * point[j];
}
}
return [result[0], result[1]];
}
}
四、变换组合
多个变换可以通过矩阵乘法组合成一个复合变换矩阵。注意,矩阵乘法不满足交换律,因此变换顺序很重要。
// 变换组合示例
function compositeTransform() {
const matrix = new Matrix2D();
// 先缩放
matrix.setScale(2, 2);
// 再旋转
const rotateMatrix = new Matrix2D();
rotateMatrix.setRotate(45);
matrix.multiply(rotateMatrix);
// 最后平移
const translateMatrix = new Matrix2D();
translateMatrix.setTranslate(100, 50);
matrix.multiply(translateMatrix);
// 应用复合变换到点(10, 10)
const result = matrix.transformPoint(10, 10);
return result;
}
五、三维变换矩阵简介
在三维空间中,变换矩阵扩展为 4×4 矩阵,用于处理三维点的平移、旋转和缩放。
// 三维变换矩阵类(简化版)
class Matrix3D {
constructor() {
// 初始化为单位矩阵
this.data = [
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
];
}
// 三维旋转变换(绕Z轴)
setRotateZ(angle) {
const radians = angle * Math.PI / 180;
const cos = Math.cos(radians);
const sin = Math.sin(radians);
this.data = [
[cos, -sin, 0, 0],
[sin, cos, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1]
];
}
// 其他三维变换方法...
}
六、实际应用示例
下面是一个使用 HTML5 Canvas 和变换矩阵实现图形变换的完整示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图形变换矩阵示例</title>
<style>
canvas {
border: 1px solid #ccc;
}
</style>
</head>
<body>
<canvas id="canvas" width="400" height="400"></canvas>
<script>
// 获取Canvas上下文
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
// 二维变换矩阵类
class Matrix2D {
constructor() {
this.data = [
[1, 0, 0],
[0, 1, 0],
[0, 0, 1]
];
}
multiply(matrix) {
const result = new Matrix2D();
const a = this.data;
const b = matrix.data;
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
result.data[i][j] = 0;
for (let k = 0; k < 3; k++) {
result.data[i][j] += a[i][k] * b[k][j];
}
}
}
return result;
}
setTranslate(tx, ty) {
this.data = [
[1, 0, tx],
[0, 1, ty],
[0, 0, 1]
];
}
setRotate(angle) {
const radians = angle * Math.PI / 180;
const cos = Math.cos(radians);
const sin = Math.sin(radians);
this.data = [
[cos, -sin, 0],
[sin, cos, 0],
[0, 0, 1]
];
}
setScale(sx, sy) {
this.data = [
[sx, 0, 0],
[0, sy, 0],
[0, 0, 1]
];
}
// 将矩阵应用到Canvas上下文
applyToContext(ctx) {
const m = this.data;
ctx.transform(m[0][0], m[1][0], m[0][1], m[1][1], m[0][2], m[1][2]);
}
}
// 绘制原始三角形
function drawOriginalTriangle() {
ctx.save();
ctx.strokeStyle = 'blue';
ctx.beginPath();
ctx.moveTo(0, -50);
ctx.lineTo(43.3, 25);
ctx.lineTo(-43.3, 25);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
// 绘制变换后的三角形
function drawTransformedTriangle() {
const matrix = new Matrix2D();
// 设置复合变换
const translate1 = new Matrix2D();
translate1.setTranslate(100, 100);
const rotate = new Matrix2D();
rotate.setRotate(45);
const scale = new Matrix2D();
scale.setScale(1.5, 1.5);
const translate2 = new Matrix2D();
translate2.setTranslate(50, 0);
// 注意矩阵乘法顺序(从右到左)
matrix.multiply(translate1);
matrix.multiply(rotate);
matrix.multiply(scale);
matrix.multiply(translate2);
ctx.save();
matrix.applyToContext(ctx);
ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
ctx.beginPath();
ctx.moveTo(0, -50);
ctx.lineTo(43.3, 25);
ctx.lineTo(-43.3, 25);
ctx.closePath();
ctx.fill();
ctx.restore();
}
// 绘制坐标系
function drawAxes() {
ctx.save();
ctx.strokeStyle = '#ccc';
ctx.beginPath();
ctx.moveTo(-canvas.width, 0);
ctx.lineTo(canvas.width, 0);
ctx.moveTo(0, -canvas.height);
ctx.lineTo(0, canvas.height);
ctx.stroke();
ctx.restore();
}
// 渲染函数
function render() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 将原点移到Canvas中心
ctx.save();
ctx.translate(canvas.width / 2, canvas.height / 2);
drawAxes();
drawOriginalTriangle();
drawTransformedTriangle();
ctx.restore();
}
// 初始化
render();
</script>
</body>
</html>
七、总结
变换矩阵是计算机图形学的核心概念之一,通过矩阵运算可以高效地实现图形的各种变换。掌握变换矩阵不仅有助于理解图形学 API 的工作原理,也为更高级的图形处理技术打下基础。