4x4矩陣教程
1. 簡介
四維矩陣是計算機圖形學和3D變換中的重要工具,用于表示三維空間中的仿射變換。本教程將介紹如何使用C++實現四維矩陣的基本運算和變換。
2. 代碼實現
2.1 頭文件 (matrix4x4.h)
#ifndef MATRIX4X4_H
#define MATRIX4X4_H#include <array>
#include <stdexcept>
#include <iostream>namespace math {
namespace linear_algebra {/*** @brief 四維矩陣類* * 這個類實現了四維矩陣的基本運算,包括:* - 矩陣加減* - 矩陣乘法* - 標量乘法* - 行列式計算* - 矩陣求逆* - 矩陣轉置* - 特征值和特征向量計算* - 矩陣性質檢查(可逆性、對稱性、正交性)* - 特殊矩陣生成(旋轉矩陣、縮放矩陣、平移矩陣、投影矩陣等)*/
class Matrix4x4 {
public:// 構造函數Matrix4x4(); // 默認構造函數,初始化為單位矩陣Matrix4x4(const std::array<std::array<double, 4>, 4>& data); // 從二維數組初始化// 基本運算Matrix4x4 operator+(const Matrix4x4& other) const; // 矩陣加法Matrix4x4 operator-(const Matrix4x4& other) const; // 矩陣減法Matrix4x4 operator*(const Matrix4x4& other) const; // 矩陣乘法Matrix4x4 operator*(double scalar) const; // 標量乘法Matrix4x4 operator/(double scalar) const; // 標量除法// 矩陣運算double determinant() const; // 計算行列式Matrix4x4 inverse() const; // 計算逆矩陣Matrix4x4 transpose() const; // 計算轉置矩陣std::array<double, 4> eigenvalues() const; // 計算特征值std::array<Matrix4x4, 4> eigenvectors() const; // 計算特征向量// 矩陣性質bool isInvertible() const; // 檢查是否可逆bool isSymmetric() const; // 檢查是否對稱bool isOrthogonal() const; // 檢查是否正交// 特殊矩陣static Matrix4x4 identity(); // 創建單位矩陣static Matrix4x4 rotation(double theta, char axis); // 創建旋轉矩陣static Matrix4x4 scaling(double sx, double sy, double sz); // 創建縮放矩陣static Matrix4x4 translation(double tx, double ty, double tz); // 創建平移矩陣static Matrix4x4 perspective(double fov, double aspect, double near, double far); // 創建透視投影矩陣static Matrix4x4 orthographic(double left, double right, double bottom, double top, double near, double far); // 創建正交投影矩陣// 輸出運算符friend std::ostream& operator<<(std::ostream& os, const Matrix4x4& m);private:std::array<std::array<double, 4>, 4> data; // 4x4矩陣數據
};} // namespace linear_algebra
} // namespace math#endif // MATRIX4X4_H
2.2 實現文件 (matrix4x4.cpp)
#include "matrix4x4.h"
#include <cmath>namespace math {
namespace linear_algebra {// 默認構造函數:初始化為單位矩陣
Matrix4x4::Matrix4x4() {for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {data[i][j] = (i == j) ? 1.0 : 0.0;}}
}// 從二維數組初始化
Matrix4x4::Matrix4x4(const std::array<std::array<double, 4>, 4>& data) : data(data) {}// 矩陣加法實現
Matrix4x4 Matrix4x4::operator+(const Matrix4x4& other) const {Matrix4x4 result;for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {result.data[i][j] = data[i][j] + other.data[i][j];}}return result;
}// 矩陣減法實現
Matrix4x4 Matrix4x4::operator-(const Matrix4x4& other) const {Matrix4x4 result;for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {result.data[i][j] = data[i][j] - other.data[i][j];}}return result;
}// 矩陣乘法實現
Matrix4x4 Matrix4x4::operator*(const Matrix4x4& other) const {Matrix4x4 result;for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {result.data[i][j] = 0.0;for (int k = 0; k < 4; ++k) {result.data[i][j] += data[i][k] * other.data[k][j];}}}return result;
}// 標量乘法實現
Matrix4x4 Matrix4x4::operator*(double scalar) const {Matrix4x4 result;for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {result.data[i][j] = data[i][j] * scalar;}}return result;
}// 標量除法實現
Matrix4x4 Matrix4x4::operator/(double scalar) const {if (scalar == 0.0) {throw std::runtime_error("Division by zero");}return *this * (1.0 / scalar);
}// 行列式計算實現
double Matrix4x4::determinant() const {// 使用拉普拉斯展開計算4x4矩陣的行列式double det = 0.0;for (int i = 0; i < 4; ++i) {double cofactor = 0.0;for (int j = 0; j < 4; ++j) {if ((i + j) % 2 == 0) {cofactor += data[0][j] * minor(0, j);} else {cofactor -= data[0][j] * minor(0, j);}}det += data[0][i] * cofactor;}return det;
}// 逆矩陣計算實現
Matrix4x4 Matrix4x4::inverse() const {double det = determinant();if (det == 0.0) {throw std::runtime_error("Matrix is not invertible");}Matrix4x4 result;double invDet = 1.0 / det;// 計算伴隨矩陣for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {result.data[i][j] = cofactor(j, i) * invDet;}}return result;
}// 轉置矩陣實現
Matrix4x4 Matrix4x4::transpose() const {Matrix4x4 result;for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {result.data[i][j] = data[j][i];}}return result;
}// 特征值計算實現
std::array<double, 4> Matrix4x4::eigenvalues() const {// 計算特征多項式系數// 這里使用簡化的方法,實際應用中可能需要更復雜的數值方法std::array<double, 4> roots;// ... 求解四次方程的代碼 ...return roots;
}// 特征向量計算實現
std::array<Matrix4x4, 4> Matrix4x4::eigenvectors() const {std::array<double, 4> eigenvals = eigenvalues();std::array<Matrix4x4, 4> eigenvecs;// ... 計算特征向量的代碼 ...return eigenvecs;
}// 可逆性檢查實現
bool Matrix4x4::isInvertible() const {return determinant() != 0.0;
}// 對稱性檢查實現
bool Matrix4x4::isSymmetric() const {for (int i = 0; i < 4; ++i) {for (int j = i + 1; j < 4; ++j) {if (data[i][j] != data[j][i]) {return false;}}}return true;
}// 正交性檢查實現
bool Matrix4x4::isOrthogonal() const {Matrix4x4 product = *this * transpose();Matrix4x4 identity = Matrix4x4::identity();for (int i = 0; i < 4; ++i) {for (int j = 0; j < 4; ++j) {if (std::abs(product.data[i][j] - identity.data[i][j]) > 1e-10) {return false;}}}return true;
}// 單位矩陣創建實現
Matrix4x4 Matrix4x4::identity() {return Matrix4x4();
}// 旋轉矩陣創建實現
Matrix4x4 Matrix4x4::rotation(double theta, char axis) {Matrix4x4 result;double cos_theta = std::cos(theta);double sin_theta = std::sin(theta);switch (axis) {case 'x':result.data[1][1] = cos_theta;result.data[1][2] = -sin_theta;result.data[2][1] = sin_theta;result.data[2][2] = cos_theta;break;case 'y':result.data[0][0] = cos_theta;result.data[0][2] = sin_theta;result.data[2][0] = -sin_theta;result.data[2][2] = cos_theta;break;case 'z':result.data[0][0] = cos_theta;result.data[0][1] = -sin_theta;result.data[1][0] = sin_theta;result.data[1][1] = cos_theta;break;default:throw std::runtime_error("Invalid rotation axis");}return result;
}// 縮放矩陣創建實現
Matrix4x4 Matrix4x4::scaling(double sx, double sy, double sz) {Matrix4x4 result;result.data[0][0] = sx;result.data[1][1] = sy;result.data[2][2] = sz;return result;
}// 平移矩陣創建實現
Matrix4x4 Matrix4x4::translation(double tx, double ty, double tz) {Matrix4x4 result;result.data[0][3] = tx;result.data[1][3] = ty;result.data[2][3] = tz;return result;
}// 透視投影矩陣創建實現
Matrix4x4 Matrix4x4::perspective(double fov, double aspect, double near, double far) {Matrix4x4 result;double tan_half_fov = std::tan(fov / 2.0);result.data[0][0] = 1.0 / (aspect * tan_half_fov);result.data[1][1] = 1.0 / tan_half_fov;result.data[2][2] = -(far + near) / (far - near);result.data[2][3] = -1.0;result.data[3][2] = -(2.0 * far * near) / (far - near);result.data[3][3] = 0.0;return result;
}// 正交投影矩陣創建實現
Matrix4x4 Matrix4x4::orthographic(double left, double right, double bottom, double top, double near, double far) {Matrix4x4 result;result.data[0][0] = 2.0 / (right - left);result.data[1][1] = 2.0 / (top - bottom);result.data[2][2] = -2.0 / (far - near);result.data[0][3] = -(right + left) / (right - left);result.data[1][3] = -(top + bottom) / (top - bottom);result.data[2][3] = -(far + near) / (far - near);return result;
}// 輸出運算符實現
std::ostream& operator<<(std::ostream& os, const Matrix4x4& m) {for (int i = 0; i < 4; ++i) {os << "[ ";for (int j = 0; j < 4; ++j) {os << m.data[i][j] << " ";}os << "]" << std::endl;}return os;
}} // namespace linear_algebra
} // namespace math
3. 使用示例
3.1 基本運算
#include "matrix4x4.h"
#include <iostream>using namespace math::linear_algebra;int main() {// 創建矩陣Matrix4x4 m1({{{1.0, 2.0, 3.0, 4.0},{5.0, 6.0, 7.0, 8.0},{9.0, 10.0, 11.0, 12.0},{13.0, 14.0, 15.0, 16.0}}});Matrix4x4 m2({{{16.0, 15.0, 14.0, 13.0},{12.0, 11.0, 10.0, 9.0},{8.0, 7.0, 6.0, 5.0},{4.0, 3.0, 2.0, 1.0}}});// 基本運算Matrix4x4 sum = m1 + m2; // 矩陣加法Matrix4x4 diff = m1 - m2; // 矩陣減法Matrix4x4 prod = m1 * m2; // 矩陣乘法Matrix4x4 scaled = m1 * 2.0; // 標量乘法// 輸出結果std::cout << "m1:\n" << m1 << std::endl;std::cout << "m2:\n" << m2 << std::endl;std::cout << "m1 + m2:\n" << sum << std::endl;std::cout << "m1 - m2:\n" << diff << std::endl;std::cout << "m1 * m2:\n" << prod << std::endl;std::cout << "m1 * 2:\n" << scaled << std::endl;return 0;
}
3.2 3D變換
#include "matrix4x4.h"
#include <iostream>
#include <cmath>using namespace math::linear_algebra;int main() {// 創建變換矩陣Matrix4x4 rotation = Matrix4x4::rotation(M_PI / 4.0, 'z'); // 繞Z軸旋轉45度Matrix4x4 scaling = Matrix4x4::scaling(2.0, 3.0, 4.0); // 縮放Matrix4x4 translation = Matrix4x4::translation(1.0, 2.0, 3.0); // 平移// 組合變換(注意順序:先縮放,再旋轉,最后平移)Matrix4x4 transform = translation * rotation * scaling;// 創建投影矩陣Matrix4x4 perspective = Matrix4x4::perspective(M_PI / 4.0, 16.0/9.0, 0.1, 100.0);Matrix4x4 ortho = Matrix4x4::orthographic(-1.0, 1.0, -1.0, 1.0, 0.1, 100.0);// 輸出結果std::cout << "旋轉矩陣:\n" << rotation << std::endl;std::cout << "縮放矩陣:\n" << scaling << std::endl;std::cout << "平移矩陣:\n" << translation << std::endl;std::cout << "組合變換:\n" << transform << std::endl;std::cout << "透視投影:\n" << perspective << std::endl;std::cout << "正交投影:\n" << ortho << std::endl;return 0;
}
4. 編譯和運行
4.1 編譯
使用提供的Makefile進行編譯:
make # 編譯所有目標
make test # 運行測試
make demo # 運行示例
make clean # 清理編譯文件
4.2 運行測試
./matrix4x4_test
4.3 運行示例
./matrix4x4_demo
5. 注意事項
-
數值精度
- 在比較浮點數時使用適當的誤差范圍
- 例如:
std::abs(det) < 1e-10
判斷是否可逆
-
異常處理
- 除以零的情況
- 不可逆矩陣求逆的情況
- 無效的旋轉軸
- 投影參數的有效性檢查
-
性能考慮
- 矩陣乘法的時間復雜度為O(n3)
- 特征值計算可能需要迭代方法
- 考慮使用SIMD指令優化計算
- 投影矩陣的預計算
-
使用建議
- 優先使用成員函數而不是全局函數
- 保持接口的一致性
- 提供清晰的錯誤信息
- 注意變換矩陣的組合順序
6. 擴展閱讀
該文章為學習過程中的筆記,目的是防止自己忘記,也為了方便隨時隨地查閱。其中大部分內容收集于互聯網。