Jump to content
  • Advertisement
Sign in to follow this  
-Datriot-

Preventing a camera's roll from drifting

This topic is 3406 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

I had actually thought I got my 6DOF camera working properly, but only recently I've noticed that whenever I rotate the yaw and pitch 'too much', the roll seems to drift apart and the three basis vectors are not orthogonal any more. So my guess is that I have to orthogonalise the matrix (which is generated using a FromYawPitchRoll() method) because I'm storing the rotations incrementally, however I'm unsure how to actually do this. I've looked around and the only thing I could find is the Gram-Schmidt algorithm. My math background being very weak, I couldn't really understand how the whole thing worked. Also, just to be sure, checking the dot products of all three vectors should return 0 if they are mutually perpendicular right? Since that's how I'm checking if the three vectors are orthogonal. Any help would be greatly appreciated. :)

Share this post


Link to post
Share on other sites
Advertisement
If you renormalize the matrix periodically this shouldn't happen, or be noticeable. But you could just reorthogonalize the matrix with cross products. This will be biased towards a particular axis of your choosing.

Ideally though wouldn't make incremental corrections on the output value, the matrix. You'd increment the source values, such as the angles like you mentioned, or a quaterion, and use that to regenerate the matrix.

Share this post


Link to post
Share on other sites
Quote:
Ideally though wouldn't make incremental corrections on the output value, the matrix. You'd increment the source values, such as the angles like you mentioned, or a quaternion , and use that to regenerate the matrix.


Thanks for replying.

The matrix used to get the camera's three basis vectors is actually converted from a quaternion which represents the total rotation. Every frame, a matrix is created using yaw pitch and roll values, converted to a quaternion which is multiplied by the total rotation. Sorry, I forgot to explain that.

For clarity, it goes like this:

Take the change of rotation in yaw, pitch and roll values
Build a matrix representing the change
Convert that matrix to a quaternion
Multiply the converted quaternion with the totalRotation quaternion

Whenever the RotateYawPitchRoll() is called and then:

Convert totalRotation to matrix
Orthoganalise the matrix here????
Retrieve the camera's three basis vectors from that matrix
Normalise those vectors

Whenever Update() is called, which is every frame.

[Edited by - -Datriot- on April 22, 2009 8:12:27 AM]

Share this post


Link to post
Share on other sites
Why do you create a matrix only to convert it to a quaternion? Why not just create the quaternion directly?

After calling CreateFromYawPitchRoll() a matrix should be returned which is completely orthogonal, there should be no reorthogonalization required after that. Though i dont know how you're using both quaternions and YawPitchRoll.. there's far too much conversion going on here.

it shouldbe:

Quat dQ = GetIncrementalRotation();
finalQ *= dQ;

finalMatrix = Matrix(finalQ);

Share this post


Link to post
Share on other sites
I'm not sure about other methods, but the way I orthonormalize matrices is this:


void OrthoNormalize(Matrix3& m)
{
m[0] /= m[0].Length();
m[1] /= m[1].Length();
m[2] = m[0].CrossProduct(m[1]);
m[2] /= m[2].Length();
m[0] = m[1].CrossProduct(m[2]);
}


Assuming your 0 and 1 columns are more or less correct, you can automatically get the correct 2 column using the cross product. The final step ensures that 0 column is orthogonal to 1 column.

edit:
Added m[2] normalize, might be required.

Share this post


Link to post
Share on other sites
Quote:
For clarity, it goes like this:

Take the change of rotation in yaw, pitch and roll values
Build a matrix representing the change
Convert that matrix to a quaternion
Multiply the converted quaternion with the totalRotation quaternion

Whenever the RotateYawPitchRoll() is called and then:

Convert totalRotation to matrix
Orthoganalise the matrix here????
Retrieve the camera's three basis vectors from that matrix
Normalise those vectors

Whenever Update() is called, which is every frame.
Just to echo what bzroom said, it sounds like you're doing some unnecessary conversions and normalizations here. Here's a stripped-down version with the redundancies removed:
- Build a quaternion from the yaw, pitch, and roll delta values
- Multiply the delta quaternion with the totalRotation quaternion
- Normalize the totalRotation quaternion
- Convert the totalRotation quaternion to matrix form if/as needed
Let me know if that requires any clarification.

Share this post


Link to post
Share on other sites
The roll of the camera still persists. I reduced the number of conversions by creating the deltaQuaternion directly from the yaw, pitch and roll angles instead of converting it from a matrix like you said, using the following member function.

void FromYawPitchRoll(float yaw, float pitch, float roll)
{
yaw = DegreesToRadians(yaw);
pitch = DegreesToRadians(pitch);
roll = DegreesToRadians(roll);

Quaternion<T> y, p, r;
y = Quaternion<T>(0, sin(-yaw / 2), 0, cos(-yaw / 2));
p = Quaternion<T>(sin(-pitch / 2), 0, 0, cos(-pitch / 2));
r = Quaternion<T>(0, 0, sin(-roll / 2), cos(-roll / 2));

// Could the order of multiplication matter here???
*this = (y * p * r);
Normalise();
}



After that, I used Thrump's method of orthoganalising the three basis vectors, just in case, like so:

// Gets the vectors from the matrix created from totalRotation
right = vector3f(mat(0, 0), mat(1, 0), mat(2, 0));
up = vector3f(mat(0, 1), mat(1, 1), mat(2, 1));
// Orthoganalises them
right.Normalise();
up.Normalise();
forward = -vector3f::Cross(right, up);
forward.Normalise();
right = vector3f::Cross(up, forward);




Rotating the pitch of the camera keeps the dot products as (0, 0, 0), but any change the yaw or roll knocks it all off balance and the three vectorsaren't orthogonal anymore.

Could it be that the operations I'm doing is biased to a certain axis? Since changing the pitch doesn't 'break' the orthoganal vectors.

[Edited by - -Datriot- on April 22, 2009 9:33:05 AM]

Share this post


Link to post
Share on other sites
Quote:
The roll of the camera still persists.
Can you clarify what you mean by 'the roll of the camera persists'? Earlier you mentioned that the orientation is drifting out of orthogonality, but 'the roll still persists' seems like it probably means something different.
Quote:
        void FromYawPitchRoll(float yaw, float pitch, float roll)
{
yaw = DegreesToRadians(yaw);
pitch = DegreesToRadians(pitch);
roll = DegreesToRadians(roll);

Quaternion<T> y, p, r;
y = Quaternion<T>(0, sin(-yaw / 2), 0, cos(-yaw / 2));
p = Quaternion<T>(sin(-pitch / 2), 0, 0, cos(-pitch / 2));
r = Quaternion<T>(0, 0, sin(-roll / 2), cos(-roll / 2));

// Could the order of multiplication matter here???
*this = (y * p * r);
Normalise();
}
Couple of tips here. It would be a good idea to create a 'from axis-angle' function for creating your rotation functions. Doing it manually like this is laborious and highly error-prone. (This applies in general, as well, for any oft-repeated bit of code.)

Assuming the deltas are small, the order of multiplication does not matter (much) here. In any case, it's probably not the cause of the problem. Finally, there's no need to call Normalize() at the end of the function (the quaternion will already be sufficiently close to unit length).
Quote:
After that, I used Thrump's method of orthoganalising the three basis vectors, just in case, like so:
This is completely unnecessary and out of place in the given context. The only 're-orthogonalization' you should need to do in the given context is to call Normalize() on your orientation quaternion at the end of each update. That's it - that will be sufficient to prevent any noticeable numerical error from accumulating.
Quote:
Rotating the pitch of the camera keeps the dot products as (0, 0, 0), but any change the yaw or roll knocks it all off balance and the three vectorsaren't orthogonal anymore.
Are you actually seeing incorrect behavior in your simulation, or is you observation based only on the dot product values that you're seeing? If the latter, can you post an example of a set of values that looks incorrect to you (i.e. something other than zeros)?

Are the values small? Are they displayed in scientific notation? It may be that you're simply misinterpreting numerical error as non-orthogonality.

Share this post


Link to post
Share on other sites
Quote:
Can you clarify what you mean by 'the roll of the camera persists'? Earlier you mentioned that the orientation is drifting out of orthogonality, but 'the roll still persists' seems like it probably means something different.


Sorry about that, I should have said 'the problem with the roll still persists'.

Quote:
Are you actually seeing incorrect behavior in your simulation, or is you observation based only on the dot product values that you're seeing?


It is very noticable on the simulation itself, that's how I first become aware of the problem. I just printed the dot products to make sure that the problem was with the camera. The dot products printed off usually range from -10 to 10.

I'm sure I'm doing everything right, I'll check all the relevant functions to make sure there aren't any errors in the calculations.

Share this post


Link to post
Share on other sites
Quote:
The dot products printed off usually range from -10 to 10.
Well, that's not right :)

If you're seeing values of that magnitude, then the problem is not drift or accumulated numerical error but rather an error in your code somewhere, in which case double-checking the various support functions for correctness is indeed a good idea.

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!