Jump to content
  • Advertisement
Sign in to follow this  
Alundra

Quaternion local-axis

This topic is 1943 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi all,

Using the view matrix, computed like that :

const CMatrix4 ViewMatrix = m_WorldMatrix.Inverse();

You can get the local-axis :

// Forward vector.
m_ForwardVector.x = ViewMatrix( 2, 0 );
m_ForwardVector.y = ViewMatrix( 2, 1 );
m_ForwardVector.z = ViewMatrix( 2, 2 );
m_ForwardVector.Normalize();

// Right vector.
m_RightVector.x = ViewMatrix( 0, 0 );
m_RightVector.y = ViewMatrix( 0, 1 );
m_RightVector.z = ViewMatrix( 0, 2 );
m_RightVector.Normalize();

// Up vector.
m_UpVector.x = ViewMatrix( 1, 0 );
m_UpVector.y = ViewMatrix( 1, 1 );
m_UpVector.z = ViewMatrix( 1, 2 );
m_UpVector.Normalize();

Using quaternion you can get the local-axis like that :

CVector3 CQuaternion::GetForwardVector() const
{
const float x2 = 2.0f * x;
const float y2 = 2.0f * y;
const float z2 = 2.0f * z;
const float x2w = x2 * w;
const float y2w = y2 * w;
const float x2x = x2 * x;
const float z2x = z2 * x;
const float y2y = y2 * y;
const float z2y = z2 * y;
return CVector3( z2x + y2w, z2y - x2w, 1.0f - ( x2x + y2y ) );
}

CVector3 CQuaternion::GetRightVector() const
{
const float y2 = 2.0f * y;
const float z2 = 2.0f * z;
const float y2w = y2 * w;
const float z2w = z2 * w;
const float y2x = y2 * x;
const float z2x = z2 * x;
const float y2y = y2 * y;
const float z2z = z2 * z;
return CVector3( 1.0f - ( y2y + z2z ), y2x + z2w, z2x - y2w );
}

CVector3 CQuaternion::GetUpVector() const
{
const float x2 = 2.0f * x;
const float y2 = 2.0f * y;
const float z2 = 2.0f * z;
const float x2w = x2 * w;
const float z2w = z2 * w;
const float x2x = x2 * x;
const float y2x = y2 * x;
const float z2y = z2 * y;
const float z2z = z2 * z;
return CVector3( y2x - z2w, 1.0f - ( x2x + z2z ), z2y + x2w );
}

When I compare the value from the quaternion and from the view matrix, I don't get the same values.

Compute euler from a matrix or a quaternion is not possible, is it the same for local-axis from a quaternion ?

 

Thanks

Edited by Alundra

Share this post


Link to post
Share on other sites
Advertisement

In both cases I would obtain the three vectors like this:

 

  CVector3 right_vector   = apply_rotation_to_vector(CVector3(1, 0, 0));
  CVector3 up_vector      = apply_rotation_to_vector(CVector3(0, 1, 0));
  CVector3 forward_vector = apply_rotation_to_vector(CVector3(0, 0, 1));

 

 

When I compare the value from the quaternion and from the view matrix, I don't get the same values.

Can you post the quaternion, the matrix and the values that don't match? How did you obtain them? Try to make the example as simple as possible.

 

 

Compute euler from a matrix or a quaternion is not possible, is it the same for local-axis from a quaternion ?

That part I didn't understand at all.

Edited by Álvaro

Share this post


Link to post
Share on other sites

Ok, it was a problem of space I think since i'm using left-handed coordinate system.

The corrected function is :

CVector3 CQuaternion::GetForwardVector() const
{
const float x2 = 2.0f * x;
const float y2 = 2.0f * y;
const float z2 = 2.0f * z;
const float x2w = x2 * w;
const float y2w = y2 * w;
const float x2x = x2 * x;
const float z2x = z2 * x;
const float y2y = y2 * y;
const float z2y = z2 * y;
return CVector3( z2x - y2w, z2y + x2w, 1.0f - ( x2x + y2y ) );
}

CVector3 CQuaternion::GetRightVector() const
{
const float y2 = 2.0f * y;
const float z2 = 2.0f * z;
const float y2w = y2 * w;
const float z2w = z2 * w;
const float y2x = y2 * x;
const float z2x = z2 * x;
const float y2y = y2 * y;
const float z2z = z2 * z;
return CVector3( 1.0f - ( y2y + z2z ), y2x - z2w, z2x + y2w );
}

CVector3 CQuaternion::GetUpVector() const
{
const float x2 = 2.0f * x;
const float y2 = 2.0f * y;
const float z2 = 2.0f * z;
const float x2w = x2 * w;
const float z2w = z2 * w;
const float x2x = x2 * x;
const float y2x = y2 * x;
const float z2y = z2 * y;
const float z2z = z2 * z;
return CVector3( y2x + z2w, 1.0f - ( x2x + z2z ), z2y - x2w );
}

Log result (R = from inverse matrix, Q = from quaternion) :

(21:57:02) RF : -0.278453, -0.092483, -0.092483

(21:57:02) RR : 0.960248, -0.006399, -0.006399

(21:57:02) RU : -0.019692, 0.995694, 0.995694

(21:57:02) QF : -0.278433, -0.093478, -0.093478

(21:57:02) QR : 0.960248, -0.006399, -0.006399

(21:57:02) QU : -0.019971, 0.995601, 0.995601

You can see precision difference, I don't know who is the more accurate.

About :

That part I didn't understand at all.

It's possible but the most of time you get weird results.It's why it's better to store the euler angle manually.

Edited by Alundra

Share this post


Link to post
Share on other sites

The most accurate one is the one that does the least amount of floating point operations :)

Just count the number of +-*/

 

You can see precision difference, I don't know who is the more accurate.

Share this post


Link to post
Share on other sites

In both cases I would obtain the three vectors like this:

 

  CVector3 right_vector   = apply_rotation_to_vector(CVector3(1, 0, 0));
  CVector3 up_vector      = apply_rotation_to_vector(CVector3(0, 1, 0));
  CVector3 forward_vector = apply_rotation_to_vector(CVector3(0, 0, 1));

 

that's exactly what he's doing, but he's factored the zero's and ones out (it seems like he's deriving the quat to matrix equations from first principles)

 

 

Compute euler from a matrix or a quaternion is not possible, is it the same for local-axis from a quaternion ?

That part I didn't understand at all.

 

converting from eulers to a matrix or quat is a lossy process. You can never go back (although you can get +-180 degree approximations using the bog standard ken shoemake code, and you can apply an euler filter over a range of changing rotations to give a reasonable flip free set of FCurves).

Share this post


Link to post
Share on other sites

Yea, you have the quaternion from eulers too :

void CQuaternion::FromEulerAngles( const float X, const float Y, const float Z )
{
const float HP = 0.5f * X;
const float HY = 0.5f * Y;
const float HR = 0.5f * Z;
const float SinHP = CMath::Sin( HP );
const float SinHY = CMath::Sin( HY );
const float SinHR = CMath::Sin( HR );
const float CosHP = CMath::Cos( HP );
const float CosHY = CMath::Cos( HY );
const float CosHR = CMath::Cos( HR );
x = SinHY * CosHP * SinHR + CosHY * SinHP * CosHR;
y = SinHY * CosHP * CosHR - CosHY * SinHP * SinHR;
z = CosHY * CosHP * SinHR - SinHY * SinHP * CosHR;
w = CosHY * CosHP * CosHR + SinHY * SinHP * SinHR;
}

About Ken Shoemake, he has done a great job on quaternion.Paper can be found on google.

Edited by Alundra

Share this post


Link to post
Share on other sites

Yeah, I think you might have misunderstood my point. I was saying that quat (or matrix) to euler is a conversion that has limited success, because euler-to-quat is a lossy conversion.


i.e. Given a rotation order of ZXY, and Euler angles of 987, 377, and -448 degrees, convert to a quat, and then back again, you will have lost information along the way. The resulting eulers will be limited to the +180 to -180 range, and the resulting Euler F-Curves will need filtering to remove the flips. 

Share this post


Link to post
Share on other sites

This is one of the problem I had in my editor since I showed the X/Y/Z value.

When I moved the object I changed the text using Quat-To-Euler but most of time the result was weird.

The best option, I think, is to store the X/Y/Z value in a property by object for the editor.

The bad point too was I used this value to set the new rotation, better to use the quaternion operator *.

Edited by Alundra

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!