Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

RandomAxess

Quaternion over-rotation problem?

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

so i''ve been following some tutorials trying to make a quaternion-based system. I''m testing it out on my camera, but i''m getting a weird problem. I set the ''a'' and ''d'' keys to be my rotate "left" and "right" respectively, each rotating around the camera vUp 5.0 degrees or -5.0 degrees respectively. What i do is, i initially have the quaternion to be the unit quaternion (or as i do it, the vUp axis rotated by 0.0 radians). Then, i take the axis and angle i want to rotate by, turn that into a quaternion using the following formula: angle = angle * (M_PI / 180.0); Quaternion result; result.a = cosf(angle / 2.0); result.v[0] = vector[0] * sinf(angle / 2.0); result.v[1] = vector[1] * sinf(angle / 2.0); result.v[2] = vector[2] * sinf(angle / 2.0); then, take the current quaternion, current = result * current; and then construct a matrix out of this. the reason I want to construct the matrix is that eventually i want to use SLERP Anyway, when i hit the keys, they do infact rotate the camera, but on consecutive hits, it either over-rotates or rotates the wrong way in respect to rhe key (aka i hit ''d'' and it rotates left). help is very much appreciated

Share this post


Link to post
Share on other sites
Advertisement
What does your quaterion operator * do?
Why do you need a matrix to slerp?

I''ve found the following code in various places around the web, and modified it slightly such that the results match the D3DX functions. You could optimize the generation of return values to get a slight speed boost when using the MSVC.NET 7.1 compiler.


EQuat operator *(const EQuat &q)
{
EQuat ret;
EFloat A, B, C, D, E, F, G, H;

A = (q.w + q.x)*(w + x);
B = (q.z - q.y)*(y - z);
C = (q.w - q.x)*(y + z);
D = (q.y + q.z)*(w - x);
E = (q.x + q.z)*(x + y);
F = (q.x - q.z)*(x - y);
G = (q.w + q.y)*(w - z);
H = (q.w - q.y)*(w + z);

ret.w = B + (-E - F + G + H) / 2.0f;
ret.x = A - (E + F + G + H) / 2.0f;
ret.y = C + (E - F + G - H) / 2.0f;
ret.z = D + (E - F - G + H) / 2.0f;
return ret;
}


EQuat SLerp(EQuat &q, EFloat ratio)
{
EQuat ret;
EFloat omega, cosom, sinom, scale0, scale1;

// calc cosine

cosom = x * q.x + y * q.y + z * q.z + w * q.w;

// adjust signs (if necessary)

if ( cosom < 0.0 )
{
cosom = -cosom;
scale1 = -1.0f;
}
else
{
scale1 = 1.0f;
}

if ( (1.0 - cosom) > 0.0001f/*DELTA*/ ) // Must define delta.

{
// standard case (slerp)

omega = EACOS(cosom);
sinom = ESIN(omega);
scale0 = ESIN((1.0f - ratio) * omega) / sinom;
scale1 *= ESIN(ratio * omega) / sinom;
}
else
{
// "from" and "to" quaternions are very close

// ... so we can do a linear interpolation

scale0 = 1.0f - ratio;
scale1 *= ratio;
}

// calculate final values

ret.x = (EFloat) (scale0 * x + scale1 * q.x);
ret.y = (EFloat) (scale0 * y + scale1 * q.y);
ret.z = (EFloat) (scale0 * z + scale1 * q.z);
ret.w = (EFloat) (scale0 * w + scale1 * q.w);

return ret;
}

Share this post


Link to post
Share on other sites
Again, you don''t need a matrix to use SLERP - that''s one of the points of using quaternions.

What do you mean by ''over-rotate''? Do you mean it rotates too far?

Also, make sure you''re multiplying in the right order, i.e. current * result vs. result * current. Which one is right depends on how you have your quat mult function set up.

The problem could also be happening at the stage where you convert from your quaternion to a matrix.

Also, remember that you need to transpose the matrix to get your view matrix. If you forget to do this, your camera will probably rotate in the wrong direction.

Share this post


Link to post
Share on other sites
the quaternion is of this form:

float a (the "real" value)
Vec3f v (the 3 values cooresponding to i,j,k)

General answers to questions you guys raised:
I don''t rotate along the wrong axis, so i know the matrix is set in the right direction.
jyk:
I will try not using the matrix-form instead.

In any case, I used the tutorials under Quaternions from gamedev, so i''ll copy what they have, which is essentially exactly what i do:
quat1 * quat2
where quat1 = {w1, x1, y1, z1}
and quat2 = {w2, x2, y2, z2}

w=w1w2 - x1x2 - y1y2 - z1z2
x = w1x2 + x1w2 + y1z2 - z1y2
y = w1y2 + y1w2 + z1x2 - x1z2
z = w1z2 + z1w2 + x1y2 - y1x2

Share this post


Link to post
Share on other sites
neglected to answer one question:
When i say over-rotate, i mean, lets say i need to go 5 degrees to the left, it will go 5 degrees initially, but the next time i do it, it will go, say, 7 degrees. also, when i hit the button to go right (AKA -5 degrees) it will sometimes keep going to the left a few clicks, then start going to the right, but not at equal amounts.

Share this post


Link to post
Share on other sites
OK, so i removed the matrix, which was the problem, and now turning left and right works just fine.

However, looking up and down go slightly diagonally up or down, thus if i click up and down simultaniously a couple times, it looks like its moving on a jagged line.

the way i do my rotations is this:
unitize(rot_axis);
Quaternion rotation;
rotation = axis_to_quat(angle, rot_axis);
unitize_quat(rotation);

Quaternion vector;
vector.a = 0.0;
vector.v = direction; //direction is the camera "foreward"

vector = multiply_quat(multiply_quat(rotation, vector), conjugate(rotation));
direction = vector.v;


vector.v = up; //up is the camera up vector
vector = multiply_quat(multiply_quat(rotation, vector), conjugate(rotation));
up = vector.v;

Share this post


Link to post
Share on other sites
Hm. I''ve never rotated a vector directly with a quat before (I use the matrix form), but it looks like you''re doing it correctly. When you rotate up and down, what are you using for the rotation axis? The cross product of the direction and up vectors?

You also may need to normalize your direction and up vectors occasionally, although I doubt that''s your problem...

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
You are mixing up your representation of the camera orientation. There is no need to store a forward and up vector. All you need to store is a single quaternion. The quaternion contains all the information about rotation about all three axes.

A simple way to generate the forward and up vectors you really want would be to just choose a starting forward vector (maybe (0,0,-1)) and a starting up vector (possibly (0,1,0)). These vectors would never actually be altered. You would use the quaternion on those vectors to get the current forward and up vectors. The quaternion is the only thing that needs to be updated. Also this quaternion is what would be stored between frames.

The code could look something like this:

read input
pick rotation to apply based on user input
current = rotation * current

forward = rotation * (0,0,-1) * conj(rotation)
up = rotation * (0,0,-1) * conj(rotation)


Actually now that I look at it this looks similiar to what you had before. But maybe if this works then it means the bug was in how you were building the matrix or something? Really building the matrix directly is just an alternative to generating the forward and up vectors and having opengl generate the matrix for you...

Share this post


Link to post
Share on other sites
hrm, interesting, i will try implementing it that way anonymous.

Also, what you have is actually different than mine...in mine, i change the foreward and up vectors, in yours they are constant.

my question is, with this "constant" quaternion, what exactly do i do with that? in your code, you don''t do anything with it. Or, instead of

current = rotation * current

forward = rotation * (0,0,-1) * conj(rotation)

did you mean

forward = current * (0,0,-1) * conj(current)

Share this post


Link to post
Share on other sites
I''m pretty sure he meant to use current (correct me if I''m wrong, anon).

The only tricky part I see is "pick rotation to apply based on user input." In order to construct this quaternion, you''ll need to already know your forward, up, and side vectors (they will be the axes you rotate around for roll, yaw, and pitch, respectively). So you may have to calculate them twice...or something :-|

In any case, it''s probably better to do it as anon has said, that is, start from scratch with (0, 0, 1), etc. each frame rather than doing it cumulatively. This will help you avoid precision errors.

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

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

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!