Advertisement

Help with Quaternion rotation (6DOF)

Started by February 28, 2016 04:56 PM
46 comments, last by SBD 8 years, 5 months ago

So I am currently trying to create a space combat game and am currently working on the players movement (as well as the camera) but I have run into a problem with doing the rotation for the player.

The main goal is to have 6 degrees of freedom for the player but I am currently just working on yaw and pitch. I am using the mouse to control the rotation with mouse up and down changing pitch and mouse left and right controlling yaw. For this I have been trying to understand Quaternion and am currently using the axis angle method (with the glm library) but I have hit a problem.

I'm not sure if this is to do with a lack of understanding or some other factor,

Currently I can just change the pitch and yaw of the ship perfectly fine but say for example I was to have a pitch change of 90 degrees (so the ship was looking up) and was the to try and change the yaw of the ship, what would happen is the roll of the ship would change instead. the opposite would happen with the yaw being 90 degrees and then changing the pitch.

It feels like I'm not understanding something or maybe my code is incorrect. Any help with the problem or understanding more about Quaternion would be very appreciated.

code for creating the axis change


 ynewquat = glm::quat();
 xnewquat = glm::quat();


    if(currentmouse.x < 540)
     {
       int rotate = -(540 - currentmouse.x);
       glm::quat tempquad = glm::angleAxis((rotate * 0.002f) * deltaTs,glm::vec3(0,1,0));
       xnewquat = tempquad;
     }
     if(currentmouse.x > 740)
     {
       int rotate = (currentmouse.x - 740);
        glm::quat tempquad = glm::angleAxis((rotate * 0.002f) * deltaTs,glm::vec3(0,1,0));
        xnewquat = tempquad;
     }
     if(currentmouse.y > 400)
     {
        int rotate = (currentmouse.y - 400);
        glm::quat tempquad = glm::angleAxis((rotate * 0.005f) * deltaTs,glm::vec3(1,0,0));
        ynewquat = tempquad;
        std::cout<<rotate<<'\n';
     }
     if(currentmouse.y < 320)
     {
       int rotate = -(320 - currentmouse.y);
       glm::quat tempquad = glm::angleAxis((rotate * 0.005f) * deltaTs,glm::vec3(1,0,0));
       ynewquat = tempquad;
       std::cout<<rotate<<'\n';
     }

     newquat = xnewquat * ynewquat;
		
     player->Update(deltaTs,newquat);

Then in the player update function


void Gamemodelimported::Update(float deltaTs, glm::quat rotation)
{

  currentrotation = rotation * currentrotation;

  temp = currentrotation * direction;

   glm::vec3 tempvel = temp * speed * deltaTs;
  position += tempvel * deltaTs;

  glm::mat4 RotationMatrix = glm::toMat4(currentrotation);
   glm::mat4 translationmatrix = glm::translate(glm::mat4(1.0f), position);

   _modelMatrix = translationmatrix * RotationMatrix;

}
I am not sure what the difference is between roll and yaw when the ship is looking straight up.

There are two common situations when people try to program 3D rotations for the first time:
* They mess up the order in which rotations are applied.
* They think their code doesn't work, but it's really their understanding of 3D rotations that has issues.

I suspect you are in the latter category, but I am not sure.
Advertisement

I am not sure what the difference is between roll and yaw when the ship is looking straight up.

ill try to give a deeper explanation of what I mean

say for this example the camera is looking down at a pyramid

if I was to change the yaw of the shape (in other words construct a quad with an axis of (0,1,0) by an angle and times it to my objects quad) it will turn to look left and right (depending what side my mouse is on).

Then say I have applied a quad to the objects orientation (with an angle of 90 around axit (1,0,0)) so it is looking at the camera. so now if i was to apply a quad with an angle in the y axis (0,1,0) it will twirl rather then rotate left of right

Is this me misunderstanding how applying axis of rotation works or is there something else going wrong?

Yes, I think there is some misunderstanding. A sequence of rotations around the X axis and the Y axis can result in a rotation around the Z axis, and this is surprising to a lot of people.

If you want your code to control pitch and yaw, keep track of pitch and yaw separately and then build your rotation from them every frame.

If you want your code to control pitch and yaw, keep track of pitch and yaw separately and then build your rotation from them every frame.

so rather then continuously applying new quaternions to the objects quaternions, it would be best to store the rotation (in say a vec3) and then construct a new quad each time.

I have added this change (i believe) but now the object is twitching a lot, am I missing a component to make it sleeker

new code


 if(currentmouse.x < 540)
     {
       rotation.y += -(540 - currentmouse.x);
     }
     if(currentmouse.x > 740)
     {
       rotation.y += -(540 - currentmouse.x);
     }
     if(currentmouse.y > 400)
     {
        rotation.x += (currentmouse.y - 400);
     }
     if(currentmouse.y < 320)
     {
       rotation.x += -(320 - currentmouse.y);
     }
		
     player->Update(deltaTs,rotation);

void Gamemodelimported::Update(float deltaTs, glm::vec3 rotation)
{
	
  //glm::quat tempquad = glm::angleAxis((-300.0f * 0.005f) * deltaTs,glm::vec3(0,1,0));
  //glm::quat tempquad2 = glm::angleAxis((-500.0f * 0.001f) * deltaTs,glm::vec3(1,0,0));



  glm::quat xrotation = glm::angleAxis((rotation.x * 0.005f) * deltaTs,glm::vec3(1,0,0));
  glm::quat yrotation = glm::angleAxis((rotation.y * 0.002f) * deltaTs,glm::vec3(0,1,0));


  currentrotation = glm::quat();
  currentrotation = xrotation * yrotation;

  temp = currentrotation * direction;

   glm::vec3 tempvel = temp * speed * deltaTs;
  position += tempvel * deltaTs;

  glm::mat4 RotationMatrix = glm::toMat4(currentrotation);
   glm::mat4 translationmatrix = glm::translate(glm::mat4(1.0f), position);

   _modelMatrix = translationmatrix * RotationMatrix;

 
}

never mind i fixed the problem (mixture between when deltaT's was being used and the code to create the rotation vector)

Advertisement

I do still have a problem though, it seems that i have fix the fail where if u face the camera then rotate by y axis then it rolls but the other way does not work.

If i switch the order around so instead of

currentrotation = xrotation * yrotation;

i do

currentrotation = yrotation * xrotation;

it just leads to the opposite problem

Im confused on how i build a rotation off theses that does not lead to one of these problems?

Currently doing


glm::quat xrotation = glm::angleAxis((rotation.x),glm::vec3(1,0,0));
glm::quat yrotation = glm::angleAxis((rotation.y),glm::vec3(0,1,0));

currentrotation = xrotation * yrotation;
Your code seems correct now, and I don't quite understand what you mean by "but the other way doesn't work" or by "the opposite problem".

Rotating about global axes is rarely a good idea when it comes to spaceships. Are you sure you shouldn't be rotating about the ship's local axes instead?

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

arr i seem to have got this working by doing

currentrotation = currentrotation * xrotation * yrotation;

Rotating about global axes is rarely a good idea when it comes to spaceships. Are you sure you shouldn't be rotating about the ship's local axes instead?I

I thought the fact that i construct the rotation matrix first and apply it in the correct order means i had done a local rotation on the ships axes, is this incorrect?

This topic is closed to new replies.

Advertisement