【问题标题】:Converting a local rotation to a global one (matrices)将局部旋转转换为全局旋转(矩阵)
【发布时间】:2013-10-28 23:37:34
【问题描述】:

[C++] {DirectX 9}

TL;DR:如何使用矩阵将表示 X 轴上局部旋转的浮点数转换为全局偏航/俯仰/滚动?

所以我正在编写一个小游戏,其中玩家被表示为一个斧头网格。玩家的视图随着鼠标的移动水平旋转(围绕 Y 轴)。 [Here] 是一个截图,以获得更好的想法。

所以我试图在按住鼠标时让斧头来回摆动。目前,我在 Player 类中将玩家的全局位置和旋转存储为变量(m_x、m_y、m_z、m_rotationX、m_rotationY、m_rotationZ)。

当我绘制对象时,我将所有这些坐标转换到全局空间中以创建一个世界矩阵。所以,是的,这些是全球坐标。 m_rotationY 会根据鼠标移动而改变。

这意味着如果我增加 m_rotationX(即通过某个动画增量的 sin 值),则对象将全局旋转,这意味着如果我向左或向右看,斧头会在屏幕上摆动而不是远离它。

我的问题:我需要做什么样的矩阵变换才能将一些“局部”x 旋转值转换为“全局”x、y 和 z 旋转值。

if(m_attacking)
{
    m_attackAnimation += 0.1f;
    float rotationAmount = sin(m_attackAnimation) * 0.1;

    // How do I figure out m_rotationX, m_rotationY and m_rotationZ 
    // from rotationAmount here? :c
}

到目前为止,我的想法是创建一个 X 旋转矩阵,然后使用它转换某种矢量,但我所有的实验都非常不成功。

感谢您的宝贵时间:D

编辑:

更多图表!

这就是我做m_rotationX = rotationAmount;时发生的事情

http://imgur.com/a/yZqzx

编辑 2:

所以根据 Federico 的回答,我设置了以下代码:

// Get the local "right" vector
D3DXVECTOR3 right(1, 0, 0);
D3DXMATRIX rotationY;
D3DXMatrixRotationY(&rotationY, m_rotationY);
D3DXVec3TransformCoord(&right, &right, &rotationY);

// Calculate the theta value we want to rotate by
m_attackAnimation += 0.1f;
float rotationAmount = sin(m_attackAnimation) * 0.1;

//Cross product
D3DXVECTOR3 axis;
D3DXVECTOR3 up(0, 1, 0);
D3DXVec3Cross(&axis, &right, &up);

//Rotation matrix
D3DXMATRIX matrix;
D3DXMatrixRotationAxis(&matrix, &axis, rotationAmount);

这应该给我一个旋转矩阵,表示 X 轴上的局部旋转。但是我可能完全搞错了。

无论如何,我如何将它重新放入全局rotationX、rotationY 和rotationZ 浮动中

*编辑 3:*

这是我从矩阵中提取旋转角度的尝试。不幸的是,结果完全关闭。斧头从视野中消失,角色随机移动。

    float rotY = acosf(matrix._11);
float rotX = asinf(matrix._13 / sin(rotY));
float rotZ = acosf(matrix._21 / sin(rotX));

m_rotationX += rotX;
m_rotationY += rotY;
m_rotationZ += rotZ;

从数学上讲,这对我来说似乎是合理的。不知道从这里去哪里。

我想我会按照 Frederico 的建议尝试仅使用矩阵来实现它。

【问题讨论】:

  • 是的,这似乎是正确的,要获取全局旋转值,您应该从矩阵值中执行逆正弦和余弦,看看我的维基百科帖子,但如果您不需要这样做你总是使用 d3dx 矩阵和向量
  • 嗯,看那个维基百科链接,似乎我只能得到 yRotation 值。坐标矩阵[0][0] 就是 cos(yRotation),所以我可以很容易地得到它。所有其他的都是从多个其他角度复合的。是的,我最终需要这样做。目前欧拉锁不是问题,因为我只是沿 Y 轴旋转相机。
  • 没关系,想通了:Y = invCos(matrix[0][0]); X = invSin(矩阵[0][2] / sin(Y)); Z = invCos(矩阵[1][0] / sin(X));现在来实现它。

标签: c++ matrix game-engine directx-9 rotational-matrices


【解决方案1】:

如果我理解您要做什么,这将创建一个矩阵,该矩阵将围绕任意轴旋转,在您的情况下,轴是方向和向上向量之间的叉积,即指向您右侧的轴(或左,取决于坐标系和产品顺序)。叉积总是返回一个与其他两个垂直的向量。

//Cross product
D3DXVECTOR3 axis;
D3DXVec3Cross(&axis, &direction, &up);

//Rotation matrix
D3DXMATRIX matrix;
D3DXMatrixRotationAxis(&matrix, &axis, rotationAmount);

生成的矩阵应该是您的旋转矩阵。

如果您想恢复旋转角度,请查看“旋转矩阵 XYZ”部分中的 http://en.wikipedia.org/wiki/Euler_angles,但我建议您使用 directx 提供的内置矩阵和矢量运算来存储您的位置和旋转.

它将允许您使用矩阵轻松旋转、平移和缩放位置和方向,而无需在每个操作下处理数学问题,也不会导致 gimabl 锁定 (http://en.wikipedia.org/wiki/Gimbal_lock)。看看http://msdn.microsoft.com/en-us/library/windows/desktop/bb205164(v=vs.85).aspx进行directx数学运算或搜索其他教程,学习如何处理它们真的很容易。

如果您想了解有关特定数学或其他游戏相关主题的一些信息,我建议您阅读 Jason Gregory 的“游戏引擎架构”

【讨论】:

  • 嗯我明白你的意思了,但我不知道如何将这个旋转矩阵转换回代表rotationX、rotationY和rotationZ的两个或三个值
  • 进一步谷歌搜索后,我可以看到从旋转矩阵中获取 Yaw、Pitch 和 Roll 是一项非常费力的任务。尽管如此,这是一个好的开始。谢谢!
  • 再想一想,您的方程正在返回 RotationAmount 的矩阵旋转,所以就像一个 delta 对吧?如果是这样,有没有办法用完整的旋转矩阵修改单轴?此外,将这个 cmets 部分变成炸弹区。对不起
  • 您可以将新的旋转应用于矩阵,只需将新旋转乘以它即可。因此,您可以创建一个仅 x 旋转的矩阵并执行 oldmatrix * xrotationonly,获得旧的旋转加上新的旋转。
  • 是的,我想问题是我现在没有使用矩阵。你能看看我的编辑,看看它是否连贯?
猜你喜欢
  • 1970-01-01
  • 2010-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-30
  • 1970-01-01
  • 1970-01-01
  • 2021-01-17
相关资源
最近更新 更多