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

Rotation problem

IceLuna opened this issue · comments

I have a problem when rotating an object. X & Z rotate in the same direction. Am I doing smth wrong?

image
image

Transform contains three glm::vec3 each for Translation, Rotation and Scale. Rotation is stored in Euler angles in radians.

glm::mat4 transformMatrix = Math::ToTransformMatrix(transform);

ImGuizmo::Manipulate(glm::value_ptr(cameraViewMatrix), glm::value_ptr(cameraProjection), 
                                     (ImGuizmo::OPERATION)m_GuizmoType, ImGuizmo::WORLD, glm::value_ptr(transformMatrix), nullptr, nullptr);

if (ImGuizmo::IsUsing())
{
    glm::vec3 notUsed1; glm::vec4 notUsed2;
    glm::quat oldRotation(transform.Rotation);
    glm::quat newRotation;

    glm::decompose(transformMatrix, transform.Scale3D, newRotation, transform.Translation, notUsed1, notUsed2);
    
    if (m_GuizmoType == ImGuizmo::OPERATION::ROTATE)
    {
        newRotation = glm::conjugate(newRotation);
        glm::vec3 euler = glm::eulerAngles(oldRotation * newRotation);
        transform.Rotation -= euler;
    }
}

Math::ToTransformMatrix:

glm::mat4 ToTransformMatrix(const Transform& transform)
{
    glm::mat4 rotation = GetRotationMatrix(transform.Rotation);
    return glm::translate(glm::mat4(1.0f), transform.Translation)
	    * rotation
	    * glm::scale(glm::mat4(1.0f), transform.Scale3D);
}

glm::mat4 GetRotationMatrix(const glm::vec3& rotation)
{
    return glm::toMat4(glm::quat(rotation));
}

I use Math::ToTransformMatrix whenever I need model matrix.

I'm not very familiar with glm but instead of doing
transform.Rotation -= euler;
Can you just set the angles coming from transformMatrix ?

You mean

glm::vec3 euler = glm::eulerAngles(newRotation);
transform.Rotation = euler;

?

It doesn't work. 3D Object's rotation is changing inadequately.

glm::vec3 notUsed1; glm::vec4 notUsed2;
//glm::quat oldRotation(transform.Rotation);
glm::quat newRotation;

glm::decompose(transformMatrix, transform.Scale3D, newRotation, transform.Translation, notUsed1, notUsed2);

if (m_GuizmoType == ImGuizmo::OPERATION::ROTATE)
{
	newRotation = glm::conjugate(newRotation);
	glm::vec3 euler = glm::eulerAngles(newRotation);

	transform.Rotation = euler;
}

Did you try to call this method :

IMGUI_API void DecomposeMatrixToComponents(const float* matrix, float* translation, float* rotation, float* scale);

I guess the issue has to do with axis order. Check glm euler order, or try to shuffle vec3 values to figure it out.

No, I didn't. Should rotation be a quat?

It can be Euler but order of rotation can be a problem. XYZ vs ZYX vs ...

It works but I don't want my rotation values to be limited in (-180; 180) range.
And won't it be a problem to use Euler's angles since the have some flaws?

Euler angles will be limited to that range. You can extract euler angles from the delta matrix and cumulate the values. I'm sure the cumulated angles will produce a good matrix. There are an infinite combination of euler angles that will produce the same matrix. It's a good practice to not use Euler internaly in the engine (use quaternion instead). Euler should only exist as inputs for fine grain value editing.

I'm doing this not to be limited in (-180; 180) range but X & Z rotate in the same direction as mentioned in the problem description.

Transform temp = transform;
if (m_GuizmoType == ImGuizmo::OPERATION::ROTATE)
  temp.Rotation = glm::vec3(0.f);
glm::mat4 transformMatrix = Math::ToTransformMatrix(temp);

ImGuizmo::Manipulate(glm::value_ptr(cameraViewMatrix), glm::value_ptr(cameraProjection), 
                                     (ImGuizmo::OPERATION)m_GuizmoType, ImGuizmo::WORLD, glm::value_ptr(transformMatrix), nullptr, nullptr);

if (ImGuizmo::IsUsing())
{
      glm::vec3 deltaRotation;
      ImGuizmo::DecomposeMatrixToComponents(&transformMatrix[0][0], &transform.Translation.x, &deltaRotation.x, &transform.Scale3D.x);
      
      if (m_GuizmoType == ImGuizmo::OPERATION::ROTATE)
      {
	      deltaRotation = glm::radians(deltaRotation);
	      transform.Rotation += deltaRotation;
      }
}