🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Problems rotating objects using eulers - quaternions

Started by
18 comments, last by alvaro 6 years, 3 months ago

I'm having problems rotating GameObjects in my engine. I'm trying to rotate in 2 ways.
I'm using MathGeoLib to calculate maths in the engine.

First way: Rotates correctly around axis but if I want to rotate back, if I don't do it following the inverse order then rotation doesn't work properly. 

e.g: 

Rotate X axis 50 degrees, Rotate Y axis 30 degrees -> Rotate Y axis -50 degrees, Rotate X axis -30 degrees. Works.

Rotate X axis 50 degrees, Rotate Y axis 30 degrees -> Rotate X axis -50 degrees, Rotate Y axis -30 degrees. Doesn't.

multiply_rot.gif.644b223fe7939fd1d9cfe8390265534a.gif

Code:


void ComponentTransform::SetRotation(float3 euler_rotation)
{
  float3 diff = euler_rotation - editor_rotation;
  editor_rotation = euler_rotation;

  math::Quat mod = math::Quat::FromEulerXYZ(diff.x * DEGTORAD, diff.y * DEGTORAD, diff.z * DEGTORAD);

  quat_rotation = quat_rotation * mod;
  UpdateMatrix(); 
}

Second way: Starts rotating good around axis but after rotating some times, then it stops to rotate correctly around axis, but if I rotate it back regardless of the rotation order it works, not like the first way.

 

not_multiple_rot.gif.d85c26ed6e9691cf95dad93c1a6892a5.gif

Code: 


void ComponentTransform::SetRotation(float3 euler_rotation)
{
    editor_rotation = euler_rotation;

    quat_rotation = math::Quat::FromEulerXYZ(euler_rotation.x * DEGTORAD, euler_rotation.y * DEGTORAD, euler_rotation.z * DEGTORAD);

    UpdateMatrix(); 
}


Rest of code:   


 #define DEGTORAD 0.0174532925199432957f

   void ComponentTransform::UpdateMatrix()
   {
     if (!this->GetGameObject()->IsParent())
     {
       //Get parent transform component
       ComponentTransform* parent_transform = (ComponentTransform*)this->GetGameObject()->GetParent()->GetComponent(Component::CompTransform);

       //Create matrix from position, rotation(quaternion) and scale
       transform_matrix = math::float4x4::FromTRS(position, quat_rotation, scale);

       //Multiply the object transform by parent transform
       transform_matrix = parent_transform->transform_matrix * transform_matrix;

       //If object have childs, call this function in childs objects
       for (std::list<GameObject*>::iterator it = this->GetGameObject()->childs.begin(); it != this->GetGameObject()->childs.end(); it++)
       {
         ComponentTransform* child_transform = (ComponentTransform*)(*it)->GetComponent(Component::CompTransform);
         child_transform->UpdateMatrix();
       }
     }
     else
     {
       //Create matrix from position, rotation(quaternion) and scale
       transform_matrix = math::float4x4::FromTRS(position, quat_rotation, scale);

       //If object have childs, call this function in childs objects
       for (std::list<GameObject*>::iterator it = this->GetGameObject()->childs.begin(); it != this->GetGameObject()->childs.end(); it++)
       {
         ComponentTransform* child_transform = (ComponentTransform*)(*it)->GetComponent(Component::CompTransform);
         child_transform->UpdateMatrix();
       }
     }
   }

  MathGeoLib:
  Quat MUST_USE_RESULT Quat::FromEulerXYZ(float x, float y, float z) { return (Quat::RotateX(x) * Quat::RotateY(y) * Quat::RotateZ(z)).Normalized(); }

  Quat MUST_USE_RESULT Quat::RotateX(float angle)
  {
    return Quat(float3(1,0,0), angle);
  }

  Quat MUST_USE_RESULT Quat::RotateY(float angle)
  {
    return Quat(float3(0,1,0), angle);
  }

  Quat MUST_USE_RESULT Quat::RotateZ(float angle)
  {
    return Quat(float3(0,0,1), angle);
  }

  Quat(const float3 &rotationAxis, float rotationAngleRadians) { SetFromAxisAngle(rotationAxis, rotationAngleRadians); }

  void Quat::SetFromAxisAngle(const float3 &axis, float angle)
  {
    assume1(axis.IsNormalized(), axis);
    assume1(MATH_NS::IsFinite(angle), angle);
    float sinz, cosz;
    SinCos(angle*0.5f, sinz, cosz);
    x = axis.x * sinz;
    y = axis.y * sinz;
    z = axis.z * sinz;
    w = cosz;
  }

Any help?

Thanks.

Advertisement

I don't see a problem anywhere. Rotations are not commutative. If you rotate around the X axis first and then around the Y axis, in order to undo the rotations you need to undo the Y-axis rotation first and then the X-axis rotation. If you put on your socks and then your shoes, the correct way to undo the operation is to take off your shoes first and then your socks.

This is a matter of how 3D rotations work. There doesn't seem to be anything wrong with your code.

 

55 minutes ago, alvaro said:

I don't see a problem anywhere. Rotations are not commutative. If you rotate around the X axis first and then around the Y axis, in order to undo the rotations you need to undo the Y-axis rotation first and then the X-axis rotation. If you put on your socks and then your shoes, the correct way to undo the operation is to take off your shoes first and then your socks.

This is a matter of how 3D rotations work. There doesn't seem to be anything wrong with your code.

 

then which of the 2 ways is correct (or better)? Because you can see that results are not equal

Well, you are doing two different things. If you compose rotations around the axes in an arbitrary order, you'll observe the non-commutativity. If you keep track of two numbers like yaw and roll, you can construct rotations from them, but you'll encounter gimbal lock.

What are you trying to accomplish?

I just want to rotate the GameObjects correctly in the engine like Unity or any other game engine.

4 hours ago, Orella said:

Second way: Starts rotating good around axis but after rotating some times, then it stops to rotate correctly

Looks like it stops rotating correctly when the values are > 360 or < -360. You could reset to zero and use this.

23 minutes ago, Scouting Ninja said:

Looks like it stops rotating correctly when the values are > 360 or < -360. You could reset to zero and use this.

This also happens between 360 and -360

1 hour ago, Orella said:

I just want to rotate the GameObjects correctly in the engine like Unity or any other game engine.

You need to define what you mean by "correctly". Both methods you have shown (incrementally applying many small rotations, versus apply a single cumulative rotation) may be "correct" depending on what you are trying to accomplish.

It might be easier to explain exactly what you are trying to accomplish.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

52 minutes ago, Orella said:

This also happens between 360 and -360

Looked like it could be a easy fix. Have you tried rotating a other object around this one, then using a "Look At" function;

I opened Unity too see how theirs works, it's the same as your first one when you use the boxes. When you rotate by using the rotation widget it targets a orbiting point.

So your first one is already correct.

5 hours ago, swiftcoder said:

You need to define what you mean by "correctly". Both methods you have shown (incrementally applying many small rotations, versus apply a single cumulative rotation) may be "correct" depending on what you are trying to accomplish.

It might be easier to explain exactly what you are trying to accomplish.

Well. As I said. I want to totate the GameObects, and rotate them around the corresponding axis as you can see in the first way but allowing to rotate them back regardless the rotation order.

This topic is closed to new replies.

Advertisement