旋转矩阵乘法误差

时间:2013-07-06 13:14:11

标签: matrix directx direct3d matrix-multiplication directx-9

我正在使用Direct3D 9开发一个3 x 3 x 3 Rubik Cube,用户可以通过单击并拖动图层旋转一层Rubik Cube,旋转看起来像这样 enter image description here

旋转的底层实现是通过矩阵乘法计算的,每当用户拖动鼠标左键时,我将生成旋转角度和旋转轴,并用它们计算旋转矩阵,然后将旋转矩阵与单位相乘当前图层中立方体的世界矩阵,代码如下

世界之前的世界“立方体”旋转代表单位立方体类,而不是魔方,魔方是由27个单位立方体构建的,我通过旋转此层中的所有单位立方体来旋转图层。

void Cube::Rotate(D3DXVECTOR3& axis, float angle)
{
    // Calculate the rotation matrix
    D3DXMATRIX rotate_matrix;
    D3DXMatrixRotationAxis(&rotate_matrix, &axis, angle);

    // This may cause the matrix multiplication accumulate errors, how to fix it?
    world_matrix_ *= rotate_matrix;
}

但是这段代码是邪恶的,有时当我旋转图层时,它消失了,看下面的图片,它很难再现,但是ID确实发生了。 enter image description here

我知道这可能是由矩阵乘法累积误差引起的。所以我在图层消失之前转储了世界矩阵,如下所示,我们可以看到矩阵中的一些数字是NaN(不是数字)。

world matrix
_11:0.999996 _12:0.000000 _13:0.000000 _14:0.000000
_21:0.000000 _22:-0.508825 _23:-0.860867 _24:0.000000
_31:0.000000 _32:0.860867 _33:-0.508825 _34:0.000000
_41:0.000000 _42:0.000000 _43:0.000000 _44:1.000000


world matrix
_11:0.999996 _12:0.000000 _13:-0.000000 _14:0.000000
_21:0.000000 _22:-0.508824 _23:-0.860866 _24:0.000000
_31:-0.000000 _32:0.860868 _33:-0.508825 _34:0.000000
_41:0.000000 _42:0.000000 _43:0.000000 _44:1.000000


world matrix
_11:0.999996 _12:-0.000000 _13:-0.000000 _14:0.000000
_21:0.000000 _22:-0.508824 _23:-0.860866 _24:0.000000
_31:0.000000 _32:0.860867 _33:-0.508825 _34:0.000000
_41:0.000000 _42:0.000000 _43:0.000000 _44:1.000000


world matrix
_11:0.999996 _12:-0.000000 _13:-0.000000 _14:0.000000
_21:0.000000 _22:-0.508824 _23:-0.860866 _24:0.000000
_31:0.000000 _32:0.860867 _33:-0.508825 _34:0.000000
_41:0.000000 _42:0.000000 _43:0.000000 _44:1.000000


world matrix
_11:0.999996 _12:0.000000 _13:-0.000000 _14:0.000000
_21:0.000000 _22:-0.508824 _23:-0.860866 _24:0.000000
_31:-0.000000 _32:0.860868 _33:-0.508825 _34:0.000000
_41:0.000000 _42:0.000000 _43:0.000000 _44:1.000000


world matrix
_11:1.#QNAN0 _12:1.#QNAN0 _13:1.#QNAN0 _14:0.000000
_21:1.#QNAN0 _22:1.#QNAN0 _23:1.#QNAN0 _24:0.000000
_31:1.#QNAN0 _32:1.#QNAN0 _33:1.#QNAN0 _34:0.000000
_41:1.#QNAN0 _42:1.#QNAN0 _43:1.#QNAN0 _44:1.000000


world matrix
_11:1.#QNAN0 _12:1.#QNAN0 _13:1.#QNAN0 _14:0.000000
_21:1.#QNAN0 _22:1.#QNAN0 _23:1.#QNAN0 _24:0.000000
_31:1.#QNAN0 _32:1.#QNAN0 _33:1.#QNAN0 _34:0.000000
_41:1.#QNAN0 _42:1.#QNAN0 _43:1.#QNAN0 _44:1.000000

问题是,我知道错误是什么,但我不知道如何修复它。

  • 我需要更改旋转方法吗?
  • 我可以做一些修正吗? 层之前的矩阵消失了吗?

您可以下载binaries进行试用,如果有必要,我可以提供项目代码,这是很多代码,所以我没有把它放在这里。

1 个答案:

答案 0 :(得分:1)

如果您获得无效的世界矩阵,那么您必须知道其中确切矩阵无效才能修复它。 添加对NaN的简单检查,以查看损坏的确切情况(添加assert或调试器中断条件)。 NaNs本身并不相同,所以你可以通过将它与自身进行比较来检查float是否为NaN

bool isNaN = (f != f); // true if f is NaN.

我的赌注是,有时会传递错误的旋转轴(可能是(0, 0, 0)),因此构建了无效的旋转矩阵。但这只是猜测。

此外, D3DXMath 有点过时, XMMath #include <directxmath.h>)更有帮助,因为它在这种情况下显示断言错误消息:

// directxmathmatrix.inl
inline XMMATRIX XM_CALLCONV XMMatrixRotationAxis(FXMVECTOR Axis, float Angle)
{
    assert(!XMVector3Equal(Axis, XMVectorZero()));
    assert(!XMVector3IsInfinite(Axis));

    XMVECTOR Normal = XMVector3Normalize(Axis);
    return XMMatrixRotationNormal(Normal, Angle);
 }

希望它有所帮助!快乐的编码!

BTW,漂亮的立方体=)