zdd
zdd

Reputation: 8747

Rotation matrix multiplication error

I am developing a 3 x 3 x 3 Rubik Cube with Direct3D 9, User can rotate one layer of the Rubik Cube by click and drag the layer, the rotation looks like this enter image description here

the underlaying implementation of the rotation was calculate by matrix multiplication, each time when user drag left mouse, i will generate the rotation angle and the rotation axis, and calculate the rotation matrix with them, then multiply the rotation matrix with the unit cube's world matrix in current layer, code as below

The world "Cube" below before world Rotate stands for the unit cube class, not the Rubik Cube, a Rubik Cube was build up by 27 unit cubes, I am rotate a layer by rotate all the unit cubes in this layer.

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;
}

but this code is evil, sometimes when I rotate the layer, it got disappeared, see picture below, it's very hard to reproduce, but id does happen. enter image description here

I know this may caused by the matrix multiplication accumulate error. so I dump the world matrix before the layers got disappeared, as below, we can see some numbers in the matrix becames NaN(not a number).

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

The problem is, I know what's the error, but I don't know how to fix it.

You can download the binaries to have a try, if necessory, I can provide the project code, it's lot's of code, so I didn't put it here.

Upvotes: 1

Views: 1011

Answers (1)

Drop
Drop

Reputation: 13003

If you get invalid world matrix, then you must know where exactly matrix becomes invalid to fix it. Add a simple checking for NaN to see exact circumstances of corruption (add asserts or debugger break condition). NaNs are not equal for themselves, so you can check if float is NaN by comparing it with itself:

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

My bet, is that there are wrong rotation axis sometimes passed (maybe (0, 0, 0)), so invalid rotation matrix builds. But this is just a guess.

Also, D3DXMath is a bit outdated and XMMath (#include <directxmath.h>) is more helpful, as it shows assertion error messages in such situations:

// 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);
 }

Hope it helps! Happy coding!

BTW, nice cube =)

Upvotes: 1

Related Questions