所以我有一个由glm::mat4 m_yellow_mat
表示的立方体
[我围绕30 degree
进行了z-axis
旋转
m_yellow_mat = glm::rotate(m_yellow_mat, glm::radians(30), glm::vec3(0, 0, 1));
现在参考下图
我想找到蓝色矢量和红色矢量之间的叉积
我知道蓝色矢量,但不确定如何找到红色矢量?红色矢量代表立方体局部y轴的方向吗?
cross( ?????? , blue_vector);
世界空间中的局部y轴存储在矩阵的第二行中:
vec3 yaxis_world = normalize(m_yellow_mat[1][0], m_yellow_mat[1][1], m_yellow_mat[1][2]);
说明:
根据定义,对象空间中的y轴(我们称为yaxis)为[0,1,0]。为了将向量从对象空间转换为世界空间,我们将向量与模型矩阵相乘。由于我们对某个方向感兴趣,因此齐次坐标必须为0:
axisy_world = modelMatrix * yaxis
axisy_world = modelMatrix * [0,1,0,0]
[当看矩阵乘法时,我们注意到它会恰好返回矩阵的第二行。
注意,必须对结果进行归一化,以从矩阵中消除比例因子。如果保证只包含平移/旋转,则可以跳过归一化。
来自BDL的答案已经明确指出,您可以从第二列转换矩阵中获得这样的up vector来表示对象在场景中的局部坐标。
我想走得更远,因为从另一个角度来看为什么我们可以从变换矩阵本身中提取这样的向量,这可能对其他读者有好处。
首先,我们可以从变换矩阵(矩阵运算的结果矩阵,即平移,旋转,缩放)中提取以下方向矢量
这在某种程度上与view matrix的构造有关。这将有助于回答为什么这些信息位于其中。
对于立即使用,如果我们有4x4矩阵,我们可以忽略最后一列是位置分量,如果您知道这样的矩阵已缩放,或者只是想确保然后再进行标准化,然后再使用从矩阵中提取的列向量。
通过构造视图矩阵,我们知道它只是我们通常对世界上某个对象所做的反向。因为在OpenGL中没有像照相机这样的东西,也可能没有任何渲染API,所以这只是一个虚拟的东西。
为了获得摄影机的效果,并能够模拟玩家的运动或观察特定方向,我们做的恰恰相反(此处使用世界空间中OpenGL使用的右手规则,默认情况下使用GLM)
0,0,10
:我们要做的是通过0,0,-10
转换场景中的所有对象。通过将上面的两个数相乘,我们将得到
view_matrix = inverse(M_rotation) * M_translation
您可以read more对此进行撰写,因为它由Song Ho写得很好。
从他的文章中摘录,我们会得到
其中有Notice Left,up和forward矢量。总而言之,视图矩阵就像操纵或模拟世界来满足相机交互一样,从某种意义上说,它仍在与世界空间交互。
我们看到了视图矩阵的构造,也应用了类似的概念。我们可以将其与场景中具有3个差异的对象一起使用
我们不需要将逆矩阵应用于旋转矩阵,因为我们不是在相机上操作,而是在对象本身上操作
0,0,0,1
的4x4矩阵。简而言之,m_yellow_mat
,您可以使用表示对象局部轴的left,up和forward矢量打包。您可以直接将其提取出来,如下所示
glm::vec3 left = glm::vec3(m_yellow_mat[0]);
glm::vec3 up = glm::vec3(m_yellow_mat[1]);
glm::vec3 forward = glm::vec3(m_yellow_mat[2]);
了解视图矩阵]的构造方式的进一步好处。单个方向矢量可以表示对象的方向,而无需我们保持每个轴3个矩阵旋转,但是它会丢失一个单独的信息(该信息大部分围绕z轴滚动)仅当此时的up vector;但对于像gizmo,平面或本身这样的简单对象而言,大多数情况下它并不重要,只要您知道它的初始起始方向必须朝向+ z轴(在y-方向),就可以将其定向为正确的方向轴。
这样做的代码是我从Song Ho的实现中学到的,它是构造视图矩阵的简单形式,并做了一些修改以适合我的示例。
glm::mat4 computeLookAtForObject(const glm::vec3& pos, const glm::vec3& target) { glm::vec3 forward = glm::normalize(target - pos); glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f); // handle if forward is nearly the same as up vector // then we choose another direction for forward if (std::abs(forward.x) < kEpsilon && std::abs(forward.z) < kEpsilon) { if (forward.y > 0.0f) { up.x = 0.0f; up.y = 0.0f; up.z = -1.0f; } else { up.x = 0.0f; up.y = 0.0f; up.z = 1.0f; } } glm::vec3 left = glm::normalize(glm::cross(up, forward)); up = glm::cross(forward, left); glm::mat4 m = glm::mat4(1.0f); m[0] = glm::vec4(left, 0.0f); m[1] = glm::vec4(up, 0.0f); m[2] = glm::vec4(forward, 0.0f); //m[3] = glm::vec4(pos, 1.0f); // <--- (optional) we can completely ignore this, or build up full-feature matrix from this function as well by uncommenting this line return m; }
在我的示例中也使用了这种功能。
我创建了两个示例对此进行验证。
computeLookAtForObject()
。检查haxpor/lgl - 2两个示例,都可以直接在此类目录中单击make
。在Ubuntu 18.04和Linux上进行了测试。