CedricGuillemet / ImGuizmo

Immediate mode 3D gizmo for scene editing and other controls based on Dear Imgui

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Handedness of the coordinate system

neo-mashiro opened this issue · comments

Hi, I realized that you are assuming a left-handed coordinate system in ImGuizmo::Manipulate(), which accepts the input matrices and then take the 1st, 2nd and 3rd column directly as the right, up and forward vector. I'm using OpenGL which adopts a right-handed coordinate system, so the 1st column of the model matrix is the left vector rather than right. The correct right should initially be glm::vec3(-1, 0, 0) to match up with forward (0,0,1) and up (0,1,0). As a result, while rotating the object, the gizmo direction vectors are not rendered correctly (sometimes in the opposite direction and will be negated suddenly over 180 degrees).

I have tried to convert the entity's model matrix to left-handed convention, but still cannot get expected result, and the vectors are sometimes negated at different viewing angles, maybe I have to convert the camera's view and projection matrix as well, but that's not easy. Anyway, is it possible to improve the matrix_t struct by including a handedness parameter?

Apart from the handedness issue, actually there are many left-handed forward/right/up conventions as well, for example some people use the x-axis as up instead of y. As there's much ambiguity going on here in the matrix representation, I personally think it would be better to have a overloaded ImGuizmo::Manipulate() function that takes in direction vectors directly rather than pointers to matrix, thus leaving all the responsibility of handling convention to the user, but then we would also need separate pointers for translation and scaling though...

To clarify, this is what I mean by saying "the vectors are suddenly inverted". You can see from the two screenshots below that, once rotation goes beyond a certain threshold, the blue forward vector is suddenly negated (sometimes two vectors are negated)

1r2r1
2222

I also found that the provided sample exe ImGuizmoSample.exe has the exact same problem, as shown below. I simply tried to rotate around the blue axis, but when I go from 32 to 33 degrees, the green up vector is negated.

1111
222232

I guess maybe this is intended behavior? I'm saying so because I noticed that sometimes there are black crosswalk lines on the gizmo. I cannot find any documentation explaining it, what are these black crosswalk lines trying to convey?

black crossed lines mean negative axis value. Red axis is X+, crossed Red is X-

Also, axis are reversed at display to make them more visible (and clicked) to the user.
Yes, handness is a weak point in imguizmo. Any improvement is welcome. Same, being able to test handness (with a radio button) in the sample is hugely welcome.

Also, axis are reversed at display to make them more visible (and clicked) to the user. Yes, handness is a weak point in imguizmo. Any improvement is welcome. Same, being able to test handness (with a radio button) in the sample is hugely welcome.

OK that makes sense, I think it's a good feature to revert the axis then, which does help me see better. I'm also aware that handedness is a hard topic as there can be many combinations, after all, the interpretation of direction vectors is entirely up to the user. It may be well enough to just clarify our convention in the docs so that people are aware of it.

commented

For anyone else having coordinate system issues.
ImGuizmo uses a right-handed coordinate system with Right +X, Up +Y, Forward -Z.

I used this paper to implement the conversion to CryEngine (RH, Right +X, Up +Z, Forward +Y).

  1. Write the standard Euclidean basis for your coordinate system.
    image
  2. Write the basis for ImGuizmo
    image
  3. Transformation of a matrix $M$ from your system to ImGuizmo: $I = I_b * M * I_b^{-1}$
  4. Transformation of a matrix $M$ from ImGuizmo to your system: $Y = I_b^{-1} * M * I_b$

And don't forget about row-major and column-major matrix storage. If they differ, you need to transpose your matrices. If something doesn't work, try swapping $I_b^{-1}$ and $I_b$

Example code:

/**
 * Right +X
 * Up +Y
 * Forward -Z
 */
static const Matrix44 g_ImGuizmoBasis = Matrix44(
     1.0f,  0.0f,  0.0f,  0.0f,
     0.0f,  0.0f,  1.0f,  0.0f,
     0.0f, -1.0f,  0.0f,  0.0f,
     0.0f,  0.0f,  0.0f,  1.0f
);

static const Matrix44 g_ImGuizmoBasisInv = g_ImGuizmoBasis.GetInverted();

Matrix44 CryToImGuizmo(const Matrix44& src)
{
    Matrix44 dest = g_ImGuizmoBasis * src * g_ImGuizmoBasisInv;
    dest.Transpose();
    return dest;
}

Matrix44 ImGuizmoToCry(const Matrix44& src)
{
    Matrix44 dest = src;
    dest.Transpose();
    dest = g_ImGuizmoBasisInv * dest * g_ImGuizmoBasis;
    return dest;
}