使用glm在本地和全局方向上旋转和平移物体

6

我正在尝试实现函数,可以在本地或全局方向上旋转/平移对象,就像在三维建模软件中一样,使用glm库。类似这样:

void Rotate(float x, float y, float z, bool localOrientation);

但我不知道如何让它工作。本地旋转应该只是像这样:(?)
m_Orientation *= glm::rotate(x, glm::vec3(1,0,0);
m_Orientation *= glm::rotate(y, glm::vec3(0,1,0);
m_Orientation *= glm::rotate(z, glm::vec3(0,0,1);

// (m_Orientation is glm::mat4)

但是如何将其与本地方向结合起来呢?实际上,我需要在世界方向中旋转旋转矩阵,对吗? 我希望你知道我所说的本地和全局方向旋转/平移的含义,就像在三维建模程序中一样。在大多数程序中,您可以切换本地和全局。

那么我该如何计算前方/右侧/向上矢量呢? 通常应该是这样的,对吗?

forward = m_Orientation * glm::vec4(0,0,-1,0);

我用下面的方法尝试了全局旋转:

m_GlobalOrientation = glm::rotate(m_GlobalRotation.x, glm::vec(1,0,0);
m_GlobalOrientation *= glm::rotate(m_GlobalRotation.y, glm::vec(0,1,0);
m_GlobalOrientation *= glm::rotate(m_GlobalRotation.z, glm::vec(0,0,1);

但是只有x轴旋转是在全局方向上的,y和z轴旋转是在本地方向上的,因为它已经围绕x轴旋转了。所以我需要同时旋转所有3个角度(?)

将本地翻译应该只是将翻译值添加到当前翻译中,并且本地翻译应该是glm::inverse(m_Orientation) * translationVector,对吗?

1个回答

27
在回答你的问题之前,让我先解释一些矩阵的核心概念。
假设我们有以下矩阵:
其中,T是一个平移矩阵,R是一个旋转矩阵。
当我们使用这个矩阵来转换一个顶点(甚至是网格)时,会得到一个唯一的结果。然而,我们可以通过两种解释来得到这个结果: 解释1:从右到左进行评估 如果我们从右到左评估矩阵,所有的变换都是在全局坐标系中完成的。因此,如果我们将一个位于原点的三角形进行变换,会得到以下结果: 解释2:从左到右进行评估 在另一种情况下,所有的变换都是在局部坐标系中完成的:
当然,我们得到的结果是相同的。
所以回到你的问题。如果你将物体的位置和方向存储为一个矩阵T,你可以通过将一个旋转矩阵乘到当前矩阵的右侧,在其局部坐标系中旋转该物体。在全局坐标系中,通过将旋转矩阵乘到当前矩阵的左侧来实现。对于平移也是一样的。
void Rotate(float x, float y, float z, bool localOrientation) 
{
    auto rotationMatrix = glm::rotate(x, glm::vec3(1,0,0));
    rotationMatrix  *= glm::rotate(y, glm::vec3(0,1,0));
    rotationMatrix  *= glm::rotate(z, glm::vec3(0,0,1));
    if(localOrientation)
        this->T = this->T * rotationMatrix;
    else
        this->T = rotationMatrix * this->T;
}

正确/前进/向上的向量是矩阵 T 的列向量。您可以直接读取它们,或者通过将矩阵与 (1, 0, 0, 0) (右方向)、(0, 1, 0, 0) (向上方向)、(0, 0, 1, 0) (前/后向) 或 (0, 0, 0, 1) (位置) 相乘来获取它们。
如果您想了解更多信息,请查看我的有关DirectX中矩阵的博客文章。但这是针对使用转置矩阵的DirectX的,因此矩阵顺序是相反的。在阅读文章时要注意这一点。

1
哇,这是一个非常好的解释!现在我知道人们所说的左乘和右乘是什么意思了。谢谢,我会尝试一下的! - C0dR
1
它成功了!非常感谢,我已经为此烦恼了几周。你帮助我更好地理解了矩阵乘法,特别是因为代码示例(我更喜欢从代码中学习)! - C0dR

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接