【问题标题】:Directx - Matrix translation in local axisDirectx - 局部轴上的矩阵平移
【发布时间】:2016-02-14 15:39:54
【问题描述】:

我在使用矩阵方面有困难

我可以像这样移动对象、旋转和在单词坐标中移动:

matScale* matRotate * matTranslate

但我不知道如何在他的局部轴上移动一个对象 即:旋转后,移动(0,0,10) i 对象的局部Z

编辑: 对不起,我迷路了:(

我试过这个:

D3DXMatrixRotationX(&matRotateX, modell->getPitch());
    D3DXMatrixRotationY(&matRotateY, modell->getYaw());
    D3DXMatrixRotationZ(&matRotateZ, modell->getRoll());

    matRotate = matRotateX * matRotateY * matRotateZ; 




    D3DXMatrixScaling(&matScale, modell->getScale().x, modell->getScale().y, modell->getScale().z);



        Matrix WVP;
        WVP = matScale* matTranslate * matRotate * matView * matProjection;

        Matrix translation;
        D3DXMatrixTranslation(&translation, 10, 10, 0); // just for test


        cBuffer.Final = translation * WVP;

...但是旋转是围绕 WORLD 轴,而不是本地:(


编辑 2:

好的,我开始明白了……我们现在可以:

-在本地轴上翻译我的对象:

translation * matRotate * matScale * matTranslate * matView * matProjection

“或”我们可以:

-在局部轴上旋转这个对象:

matRotate * 平移 * matScale * matTranslate * matView * matProjection

但是,我想同时进行这两个转换^^,我想在<local> 中进行翻译,并且我想在<local> 中使用相同的操作进行旋转

这怎么可能? :-)


编辑 3

好的,我想我们可以简化一下...

我想在物体的 Z 轴上移动,我可以这样做:

if (input.keyPressed(VK_UP))
{
    ship->translate(0, 0, -0.01, ASF3D::LOCAL);

}

然后,我更新我的对象在他们的类中的位置:(函数:翻译)

position.x += z * sin(yaw);
position.y += z * sin(pitch);
position.z += z * -cos(yaw);

在此之后,我制作了 matPosition(而不是管理位置矩阵和矩阵平移)

然后,我做我的:cBuffer.Final = matScale* matRotate * matTranslate* matView * matProjection;

我无法测试 atm,但我确信它可以正常工作并且更容易
我只是不确定三角函数的计算:P

【问题讨论】:

  • 请添加一些代码。
  • 显示您到目前为止尝试过的内容以及无法正常工作的内容
  • 您在某处缺少cos(pitch),我认为在 x 和 z 中(为了保持向量的长度),但除此之外,这应该是一个可行的解决方案。

标签: c++ math matrix directx


【解决方案1】:

注意:
这个答案并不特定于 DirectX,它是关于一般矩阵乘法的。但是由于您没有提供任何代码或有关您如何尝试解决问题的更多信息,因此这是我能想到的最好的。它应该让您走上正确的轨道,如何完成矩阵转换。


首先是一些矩阵的一般关系:

M*N != N*M  //non-commutative
M*(N*O) = (M*N)*O  //associative
inverse(M*N) = inverse(N)*inverse(N)

S 为缩放矩阵,R 旋转和T 平移。此外,x 是本地未转换坐标中的坐标,而w 是世界坐标中的坐标。

如果你从右边乘以坐标作为列向量,你会得到类似的结果:

w = S*R*T * x  <-> w = S*(R*(T*x))

它首先在 x 的局部坐标中平移,然后在平移坐标中旋转,然后在平移和旋转坐标中缩放。局部坐标系中的变换L 可以通过将右侧的“L”乘以当前变换矩阵来轻松实现:

w = S*R*T * L * x  <-> w = S*(R*(T*(L*x)))

如果你固定将它向左相乘,你需要先用一些矩阵 M 和它的逆矩阵 I=inverse(M) 对其进行转换,如下所示:

w = M*L*I * S*R*T * x

很容易看出,M=(S*R*T) 变成:

w = (S*R*T) * L * inverse(S*R*T) * (S*R*T) * x
w = S*R*T * L * x

同上。


如果将坐标x 从左侧乘以行向量,则上述公式变为:

w = x * S*R*T <-> w = ((x*S)*R)*T

它首先在 x 的局部坐标中缩放,然后在缩放坐标中旋转,然后在缩放和旋转坐标中平移。
(...)

w = x * L * S*R*T  <-> w = (((x*L)*S)*R)*T

(...)

w = x * S*R*T * I*L*M
w = x * (S*R*T) * inverse(S*R*T) * L * (S*R*T)
w = x * L * S*R*T
在您提供一些代码后

编辑

您的cBuffer.Final 计算为:

cBuffer.Final = translation * WVP;

cBuffer.Final = translation * matScale* matTranslate * matRotate * matView * matProjection;

由于 DirectX 使用行向量,这将获取您的坐标 x,然后首先应用 translation,将对象移出中心。然后它应用matScale 围绕坐标系中心缩放对象(并因此进一步移动它)。然后它再次应用matTranslate 移动它。然后它应用matRotate,围绕你的坐标系中心旋转它(这将使对象以宽弧移动,因为你的对象不再居中)。然后它应用matView,最后应用matProjection 来获取对象的屏幕坐标。

如果您想围绕其局部坐标系旋转对象,请尝试以下操作:

cBuffer.Final = matRotate * translation * matScale * matTranslate * matView * matProjection;

这将首先旋转对象(当它仍在您的坐标系中心时),然后应用(按顺序)translationmatScalematTranslatematViewmatProjection

如果您(如编辑前的问题部分所述)想要沿矢量 (0,0,10) 在局部坐标中移动对象,请尝试以下操作:

D3DXMatrixTranslation(&translation, 0, 0, 10);
cBuffer.Final = translation * matRotate * matScale * matTranslate * matView * matProjection;

需要注意的重要部分是:矩阵乘法的顺序决定了应用转换的顺序。 IE。 A*B != B*A

编辑2:
以评论中的宇宙飞船为例:

假设你的宇宙飞船有一个位置和一个旋转,由两个矩阵matPositionmatRotate 给出。那么最终的变换矩阵由下式给出:

cBuffer.Final = matScale * matRotate * matPosition * matView * matProjection

(再次查看 this image 为什么我们先旋转然后平移。)

然后,如果您想通过在 z 方向移动位置 5 步来更新您的 matPosition,您可以这样写:

D3DXMatrixTranslation(&translation, 0, 0, 5);
matPosition *= translation;

但您想在本地 z 方向上移动它。所以你要做的就是进行这种转换:

cBuffer.Final = matScale * translation * matRotate * matPosition * matView * matProjection

哪个(再看一下图片)将首先平移,然后旋转(在局部轴上进行平移),然后将对象移动到其位置。然而,我们无论如何都需要将此平移“移动”到位置矩阵中,或者在下一步中它将使用我们不想要的新旋转矩阵。但是我们可以将这一行改写为(没有比例、视图和项目):

cBuffer.Final = translation * matRotate * matPosition

                /  This is the unity-matrix \ 
cBuffer.Final = matRotate * inverse(matRotate) * translation * matRotate * matPosition 
                            \ - - store this in a new position-matrix - - - - - - - /
cBuffer.Final = matRotate * matNewPosition

这导致我们:

D3DXMatrixTranslation(&translation, 0, 0, 5);
matPosition = inverse(matRotate) * translation * matRotate * matPosition;
cBuffer.Final = matScale * matRotate * matPosition * matView * matProjection;

【讨论】:

  • 我已经更新了我的答案,需要注意的重要部分是矩阵的顺序很重要。由于您可以完全访问矩阵乘法,因此我使用inverse(S*R*T) 的原始答案部分与您无关。
  • @Asphodeuls:看例如在this image(不确定版权,所以我只在此处链接)。你想要哪一个?我想这是第二个,因为它的行为就像你先旋转然后在本地坐标系中平移一样。我不知道第三种可能性.....
  • 以宇宙飞船为例,它以每帧 5 个单位的速度移动在他的本地 Z (Vector3(0,0,5) ) 中保留翻译
  • 我也为此添加了一个示例。然而矩阵乘法很复杂,我知道你需要把头绕在它周围一段时间。但是您仍然应该尝试了解它们的工作原理以及它们的作用。如果尝试失败,请拿起笔和纸,写下您需要的方程式或画出会发生什么。
  • 这正是我所做的,所以我只是编辑我的帖子来向你展示我的建议:-)(我只是怀疑三角学)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-17
  • 2018-12-02
相关资源
最近更新 更多