Glm矩阵与向量乘法
示例¶
auto mat = glm::translate(glm::mat4(1.0f), glm::vec3(-0.5, 0.5, 1));
//按列式存储
auto v = glm::vec4(1.0, 1.0, 1.0, 1.0);
//列式存储。没有重写一个vec3,重用matrix
auto tmp = mat * v;
//为了和glsl统一
输出
matrix: mat4x4((1.000000, 0.000000, 0.000000, 0.000000), (0.000000, 1.000000, 0.000000, 0.000000), (0.000000, 0.000000, 1.000000, 0.000000), (-0.500000, 0.500000, 1.000000, 1.000000))
vector: vec4(1.000000, 1.000000, 1.000000, 1.000000)
result: vec4(0.500000, 1.500000, 2.000000, 1.000000)
整理成行列式,方便查看
- 根据资料显示,glm的向量是列向量
- 而且,
向量 = 矩阵 * 向量
- 因此,可以将示例整理成如下形式
| 1.0 0.0 0.0 0.0 | | 1 | | 0.5 |
| 0.0 1.0 0.0 0.0 | x | 1 | = | 1.5 |
| 0.0 0.0 1.0 0.0 | | 1 | | 2.0 |
| -0.5 0.5 1.0 1.0 | | 1 | | 1.0 |
分析¶
手动计算¶
我们根据矩阵的计算方式,手动计算一下:
计算公式
| m11 m12 m13 m14 | | x |
| m21 m22 m23 m24 | x | y |
| m31 m32 m33 m34 | | z |
| m41 m42 m43 m44 | | w |
=
(
x*m11 + y*m12 + z*m13 + w*m14,
x*m21 + y*m22 + z*m23 + w*m24,
x*m31 + y*m32 + z*m33 + w*m34,
x*m41 + y*m42 + z*m43 + w*m44
)
计算结果
发现结果和程序运行的对不到!那只有一种可能了,glm的 (4x4) * (4x1)
并不是数学中矩阵的计算方法!
查看glm源码¶
template<typename T, qualifier Q>
GLM_FUNC_QUALIFIER typename mat<4, 4, T, Q>::col_type operator*
(
mat<4, 4, T, Q> const& m,
typename mat<4, 4, T, Q>::row_type const& v
)
{
typename mat<4, 4, T, Q>::col_type const Mov0(v[0]);
//x
typename mat<4, 4, T, Q>::col_type const Mov1(v[1]);
//y
typename mat<4, 4, T, Q>::col_type const Mul0 = m[0] * Mov0;
//第一行 * x
typename mat<4, 4, T, Q>::col_type const Mul1 = m[1] * Mov1;
//第二行 * y
typename mat<4, 4, T, Q>::col_type const Add0 = Mul0 + Mul1;
//第一行 * x + 第二行 * y
typename mat<4, 4, T, Q>::col_type const Mov2(v[2]);
//z
typename mat<4, 4, T, Q>::col_type const Mov3(v[3]);
//w
typename mat<4, 4, T, Q>::col_type const Mul2 = m[2] * Mov2;
//第三行 * z
typename mat<4, 4, T, Q>::col_type const Mul3 = m[3] * Mov3;
//第四行 * w
typename mat<4, 4, T, Q>::col_type const Add1 = Mul2 + Mul3;
//第三行 * z + 第四行 * w
typename mat<4, 4, T, Q>::col_type const Add2 = Add0 + Add1;
//第一行 * x + 第二行 * y + 第三行 * z + 第四行 * w
return Add2;
}
梳理源码,惊讶的发现,在glm中:(4x4) * (4x1)
的结果居然是(1x4) * (4x4)
的结果。
| m11 m12 m13 m14 | | x |
| m21 m22 m23 m24 | x | y |
| m31 m32 m33 m34 | | z |
| m41 m42 m43 m44 | | w |
=x(m11, m12, m13, m14) + y(m21, m22, m23, m24) + z(m31, m32, m33, m34) + w(m41, m42, m43, m44)
=
(
x*m11 + y*m21 + z*m31 + w*m41,
x*m12 + y*m22 + z*m32 + w*m42,
x*m13 + y*m23 + z*m33 + w*m43,
x*m14 + y*m24 + z*m34 + w*m44
)
=
(x, y, z, w) x | m11 m12 m13 m14 |
| m21 m22 m23 m24 |
| m31 m32 m33 m34 |
| m41 m42 m43 m44 |
按照示例代入,计算结果确实是对的。
结论¶
因此,不要被glm骗了。
- 在数学的角度、行列式的角度,glm的向量其实是行向量,应该写成
向量 = 向量 * 矩阵
(因为矩阵是列式存储的) - 但它被人为定义成列向量,并人为重新定义了
operator *
,最后写成向量 = 矩阵 * 向量
的形式 - 这可能是为了和GLSL做统一,因为在GLSL中,也是
向量 = 矩阵 * 向量
的形式
总结¶
glm是OpenGL的数学库,因此OpenGL的情况与glm一致
- glm的矩阵是按列优先存储(列主序)
- glm的向量被视为列向量
向量 = 矩阵 * 向量
,需注意的是,此处的乘法并不是行列式的乘法,而是被程序员自定义了