解析C++ Mat44类矩阵乘法实现及相关技术疑问
矩阵运算实现解析
以下代码取自Austin Morlan的ECS示例:
class Mat44 { public: Mat44() { //@formatter:off m[0][0] = 1.0f; m[0][1] = 0.0f; m[0][2] = 0.0f; m[0][3] = 0.0f; m[1][0] = 0.0f; m[1][1] = 1.0f; m[1][2] = 0.0f; m[1][3] = 0.0f; m[2][0] = 0.0f; m[2][1] = 0.0f; m[2][2] = 1.0f; m[2][3] = 0.0f; m[3][0] = 0.0f; m[3][1] = 0.0f; m[3][2] = 0.0f; m[3][3] = 1.0f; //@formatter:on } Mat44 operator*(Mat44 const& rhs) { Mat44 result; for (int row = 0; row < 4; ++row) { for (int col = 0; col < 4; ++col) { float sum = 0.0f; for (int i = 0; i < 4; ++i) { sum += m[row][i] * rhs.m[i][col]; } result.m[row][col] = sum; } } return result; } Vec4 operator*(Vec4 const& rhs) { return Vec4( (rhs.x * m[0][0]) + (rhs.y * m[0][1]) + (rhs.z * m[0][2]) + (rhs.w * m[0][3]), (rhs.x * m[1][0]) + (rhs.y * m[1][1]) + (rhs.z * m[1][2]) + (rhs.w * m[1][3]), (rhs.x * m[2][0]) + (rhs.y * m[2][1]) + (rhs.z * m[2][2]) + (rhs.w * m[2][3]), (rhs.x * m[3][0]) + (rhs.y * m[3][1]) + (rhs.z * m[3][2]) + (rhs.w * m[3][3])); } float m[4][4]; };
技术问题解答
1. 矩阵乘法重载函数的三层循环逻辑
矩阵乘法的核心规则是:结果矩阵中第row行第col列的元素,等于左边矩阵的第row行,和右边矩阵的第col列,对应位置的元素相乘后全部加起来。
- 最外层
row循环:遍历结果矩阵的每一行,从第0行到第3行。 - 中间层
col循环:遍历当前行的每一列,从第0列到第3列。 - 最内层
i循环:负责把左边矩阵第row行的第i个元素,和右边矩阵第col列的第i个元素相乘,累加到sum里。等i遍历完0到3,sum就是结果矩阵[row][col]的最终值,赋值给结果矩阵即可。
2. 矩阵与向量乘法是否属于GLM的底层抽象?
是的。GLM作为游戏开发常用的线性代数库,对外提供简洁的接口(比如直接用mat4 * vec4),但底层确实封装了这类基础运算逻辑。不同的是GLM会做更多优化,比如利用SIMD指令加速运算,同时处理了更多边界情况和类型兼容问题,而示例里的代码是最基础的手动实现版本。
3. 运算符重载函数为何需要传入参数?
以a * b为例,这是双目运算符,需要两个操作数。在成员函数形式的运算符重载中,左操作数a是当前对象(通过this指针隐式访问),而右操作数b必须通过参数传入,也就是代码里的rhs(right-hand side,右操作数)。如果没有这个参数,函数不知道要和哪个对象做乘法,逻辑无法完成。
4. 矩阵与向量乘法的实现逻辑
这里的Vec4可以看作是一个4行1列的列向量,矩阵乘向量的规则是:结果向量的每个分量,等于矩阵的对应行,和向量的每个元素相乘后求和。
- 结果向量的x分量:用矩阵的第0行(
m[0][0]到m[0][3])分别乘向量的x、y、z、w,再把四个乘积加起来。 - 结果向量的y分量:用矩阵的第1行(
m[1][0]到m[1][3])做同样的操作。 - z、w分量以此类推,对应矩阵的第2、3行。代码里的四个表达式正好对应这四个分量的计算。
内容的提问来源于stack exchange,提问作者verdy
相关产品推荐
相关产品推荐

