Jump to content

  • Log In with Google      Sign In   
  • Create Account

Awesome job so far everyone! Please give us your feedback on how our article efforts are going. We still need more finished articles for our May contest theme: Remake the Classics

#ActualgbMike

Posted 24 September 2012 - 01:47 PM

I'm having some difficulty replicating a bit of code, after switching from Euler, to Quaternions. The rotation value (a vec3) in my transform class, has each value (x, y, z) constrained between -180 and 180. So, if I was to rotate an object with 0 degrees rotation, 190 degrees, the new rotation would be -170.

My camera's transform needs to be rubber banded to the player. Heres how it was setup with Euler angles (This was called each frame):

   vec3 posDif = coreTransform->getTranslation() - lastCoreTransform->getTranslation();
   vec3 rotDif = coreTransform->getRotation() - lastCoreTransform->getRotation();
  
   //Adjust values
   if( rotDif.x > 180.0f )
	rotDif.x -= 360;
   if( rotDif.y > 180.0f )
	rotDif.y -= 360;
   if( rotDif.z > 180.0f )
	rotDif.z -= 360;
   if( rotDif.x < -180.0f )
	rotDif.x += 360;
   if( rotDif.y < -180.0f )
	rotDif.y += 360;
   if( rotDif.z < -180.0f )
	rotDif.z += 360;
  
   //reduce the position and rotation by a %
   posDif *= 0.25f;
   rotDif *= 0.5f;
   vec3 newRot = -(lastCoreTransform->getRotation() + rotDif);
   vec3 newPos = lastCoreTransform->getTranslation() + posDif;

Here, it is pretty easy to constrain the rotation difference. That way if last rotation was 170, and new rotation is -170, the difference will be the correct 20, rather than -340. So my question is, how do I replicate this with Quaternions? Here is the current interpolation code:

//Interpolate between this transform, and the passed in 'target'
Transform* Transform::interpolate( Transform *target, float rotMultiplier, float posMultiplier )
{
quat thisQuat = cdata->quaternion;
quat targetQuat = target->getQuat();
quat newRotQuat = glm::mix( thisQuat, targetQuat, rotMultiplier );

//check for infinities in return values
if ( newRotQuat.w <= FLT_MAX && newRotQuat.w >= -FLT_MAX)
{
  //Number is real, within boudaries.
}
else
{
		//then our quat has returned overflow numbers, either to large or too small
  // -1.#IND or  1.#IND
  newRotQuat = target->getQuat();
	}  

vec3 newRot = glm::eulerAngles( newRotQuat );

vec3 newPos = cdata->translation + ( (target->getTranslation() - cdata->translation ) * posMultiplier );

//create the new Transform, and pass in values
Transform *nTrans = new Transform();
//nTrans->setMatrix( newPos, newRot, vec3(1.0f, 1.0f, 1.0f) );
nTrans->setMatrix( vec3(0.0f,0.0f,0.0f), newRot, vec3(1.0f, 1.0f, 1.0f) );
return nTrans;
}

It causes the camera to start spinning wildly after a certain rotation is reached. How can I properly constrain the value like I used to, while the code for quaternion interpolation is handled through GLM? (glm::mix)


EDIT:
Alternatively, if anyone has a suggestion, for another way to add easing animation to the camera, I'd be interested in trying it.

#1gbMike

Posted 21 September 2012 - 03:07 PM

I'm having some difficulty replicating a bit of code, after switching from Euler, to Quaternions. The rotation value (a vec3) in my transform class, has each value (x, y, z) constrained between -180 and 180. So, if I was to rotate an object with 0 degrees rotation, 190 degrees, the new rotation would be -170.

My camera's transform needs to be rubber banded to the player. Heres how it was setup with Euler angles (This was called each frame):

   vec3 posDif = coreTransform->getTranslation() - lastCoreTransform->getTranslation();
   vec3 rotDif = coreTransform->getRotation() - lastCoreTransform->getRotation();
  
   //Adjust values
   if( rotDif.x > 180.0f )
	rotDif.x -= 360;
   if( rotDif.y > 180.0f )
	rotDif.y -= 360;
   if( rotDif.z > 180.0f )
	rotDif.z -= 360;
   if( rotDif.x < -180.0f )
	rotDif.x += 360;
   if( rotDif.y < -180.0f )
	rotDif.y += 360;
   if( rotDif.z < -180.0f )
	rotDif.z += 360;
  
   //reduce the position and rotation by a %
   posDif *= 0.25f;
   rotDif *= 0.5f;
   vec3 newRot = -(lastCoreTransform->getRotation() + rotDif);
   vec3 newPos = lastCoreTransform->getTranslation() + posDif;

Here, it is pretty easy to constrain the rotation difference. That way if last rotation was 170, and new rotation is -170, the difference will be the correct 20, rather than -340. So my question is, how do I replicate this with Quaternions? Here is the current interpolation code:

//Interpolate between this transform, and the passed in 'target'
Transform* Transform::interpolate( Transform *target, float rotMultiplier, float posMultiplier )
{
quat thisQuat = cdata->quaternion;
quat targetQuat = target->getQuat();
quat newRotQuat = glm::mix( thisQuat, targetQuat, rotMultiplier );

//check for infinities in return values
if ( newRotQuat.w <= FLT_MAX && newRotQuat.w >= -FLT_MAX)
{
  //Number is real, within boudaries.
}
else
{
		//then our quat has returned overflow numbers, either to large or too small
  // -1.#IND or  1.#IND
  newRotQuat = target->getQuat();
	}  

vec3 newRot = glm::eulerAngles( newRotQuat );

vec3 newPos = cdata->translation + ( (target->getTranslation() - cdata->translation ) * posMultiplier );

//create the new Transform, and pass in values
Transform *nTrans = new Transform();
//nTrans->setMatrix( newPos, newRot, vec3(1.0f, 1.0f, 1.0f) );
nTrans->setMatrix( vec3(0.0f,0.0f,0.0f), newRot, vec3(1.0f, 1.0f, 1.0f) );
return nTrans;
}

It causes the camera to start spinning wildly after a certain rotation is reached. How can I properly constrain the value like I used to, while the code for quaternion interpolation is handled through GLM? (glm::mix)

PARTNERS