Sign in to follow this  
Jiia

No need to normalize this quaternion

Recommended Posts

Just a quicky. I'm not gonna pretend like I know what I'm talking about. Quaternions are pretty new to me (Heh, [looksaround] ..matrices are pretty new to me). From what I understand, a normalized unit quaternion is where the square-root of the sum of x,y,z and w sqaured is 1, right? Or something like this..
(x*x) + (y*y) + (z*z) + (w*w) == 1
If I have two unit quaternions, and I want to add them together, do I need to normalize if the percentages I'm adding together will always be 1? Example..
float perc = 0.7f;
float opp_perc = 1.0f - perc;

// these two quaternions come from elsewhere, and are both
// always units and normalized..
QUAT a,b;

// interpolated result
QUAT c = (a * perc) + (b * opp_perc);


Will quaternion c always be a normalized unit? Testing it seems great, but my lack of knowledge in this area means there could be deep holes somewhere down the road. Thanks for any advice.

Share this post


Link to post
Share on other sites
I may have make a mistake in the following but...

a = (w,x,y,z) with ww+xx+yy+zz=1
b = (W,X,Y,Z) with WW+XX+YY+ZZ=1

c = p (w,x,y,z) + (1-p) (W,X,Y,Z)
= (W+pw-pW, X+px-pX, Y+py-pY, Z+pz-pZ)

||c|| = (W+pw-pW)^2 + (X+px-pX)^2 + (Y+py-pY)^2 + (Z+pz-pZ)^2

= WW + ppww + ppWW + 2Wpw - 2WpW - 2ppwW +
XX + ppxx + ppXX + 2Xpx - 2XpX - 2ppxX +
YY + ppyy + ppYY + 2Ypy - 2YpY - 2ppyY +
ZZ + ppzz + ppZZ + 2Zpz - 2ZpZ - 2ppzZ

= 1 + pp + pp + 2p ( Ww - WW - pwW +
Xx - XX - pxX +
Yy - YY - pyY +
Zz - ZZ - pzZ )

= 1 - 2p + 2pp + 2p(1-p) ( Ww + Xx + Yy + Zz )

= 1 + 2p(1-p)(a.b - 1)


Which won't be equal to 1, unless a.b = 1, p=0 or p=1.

[Edited by - Fruny on September 19, 2004 7:18:00 PM]

Share this post


Link to post
Share on other sites
Nope, you can't guarenttee that. Quaternion addition is no different to vector addition, so think of it like a 2D vector. (EDIT: Well, a 4D vector, but the number of dimensions doesn't matter and 2D is easy to do ASCII art for [smile])

^
|
| A
|
|
<--------
B

Is the length of A+B equal to the length of A + the length of B?
Nope.

Share this post


Link to post
Share on other sites
Hmm.. I think you'd more than likely need to renormalize it. I haven't checked, but I'm thinking unless A == B or perc == 0 or 1 then you'll never get a normalized result.

To visualize, think about the case of 2D vectors:

^___^___ ^
\ C| /
A \ | / B
\|/


If A and B are normalized (length == 1), then any vector between them (C) is going to have a length less than 1. Quaternions are 4D, but the idea is the same.

And just as an aside, if you're using a linear interpolation to interpolate quaternions for skeletal animation, you'd be able to get better (smoother) results by using spherical linear interpolation (slerp)

-nohbdy

Share this post


Link to post
Share on other sites
You're saying that the result of adding them will not be a unit, or that a unit is not calculated in the way that I mentioned?

I can't understand why. If the sum of 4 numbers is 1, and another sum of 4 numbers is 1, isn't this always true?

(sum1 * factor) + (sum2 * (1.0 - factor)) == 1?

// In other words, sum1 * 0.5 should makes the sum1 equal 0.5
// instead of 1. Right? sum1 * 0.7 makes the sum equal to 0.7.

(0.10 + 0.60 + 0.20 + 0.10) * 0.5 == (0.05 + 0.30 + 0.10 + 0.05)
(0.30 + 0.20 + 0.10 + 0.40) * 0.5 == (0.15 + 0.10 + 0.05 + 0.20)

// so
(0.05 + 0.30 + 0.10 + 0.05) + (0.15 + 0.10 + 0.05 + 0.20)
// results in
(0.20 + 0.40 + 0.15 + 0.25)

// HEAVILY edited - sorry for messing this up so bad


Where am I getting lossed?

Share this post


Link to post
Share on other sites
Quote:
Original post by Jiia
If the sum of 4 numbers is 1, and another sum of 4 numbers is 1, isn't this always true?


We don't care about the sum of the numbers, we care about the sum of their squares: (pw+(1-p)W)^2+(px+(1-p)X)^2+(py+(1-p)Y)^2+(pz+(1-p)Z)^2

Share this post


Link to post
Share on other sites
Here are some printed out values of real in-game quaternions. Am I accidently getting values that work? It always seems to work..?


Format is
(Ax, Ay, Az, Aw) * opp_perc
+ (Bx, By, Bz, Bw) * perc
= (Cx, Cy, Cz, Cw) (sum of C's sqaured values)

(-0.016, -0.197, 0.007, 0.980) * 0.210
+ (-0.016, -0.218, 0.006, 0.976) * 0.790
= -0.016, -0.214, 0.006, 0.977 (sum of sqaures = 1.000)

(-0.016, -0.229, 0.006, 0.973) * 0.320
+ (-0.015, -0.248, 0.008, 0.969) * 0.680
= -0.016, -0.242, 0.008, 0.970 (sum of sqaures = 1.000)

(-0.015, -0.259, 0.011, 0.966) * 0.460
+ (-0.013, -0.267, 0.015, 0.964) * 0.540
= -0.014, -0.263, 0.013, 0.965 (sum of sqaures = 1.000)

(-0.012, -0.281, 0.020, 0.959) * 0.540
+ (-0.010, -0.289, 0.025, 0.957) * 0.460
= -0.011, -0.285, 0.022, 0.958 (sum of sqaures = 1.000)

(-0.006, -0.313, 0.033, 0.949) * 0.590
+ (-0.000, -0.320, 0.040, 0.947) * 0.410
= -0.004, -0.316, 0.036, 0.948 (sum of sqaures = 1.000)

(0.012, -0.021, 0.080, 0.997) * 0.880
+ (0.006, 0.035, 0.079, 0.996) * 0.120
= 0.011, -0.015, 0.079, 0.996 (sum of sqaures = 1.000)

(-0.015, 0.149, 0.061, 0.987) * 0.810
+ (-0.017, 0.174, 0.054, 0.983) * 0.190
= -0.016, 0.154, 0.060, 0.986 (sum of sqaures = 1.000)

(-0.016, -0.197, 0.007, 0.980) * 0.990
+ (-0.016, -0.218, 0.006, 0.976) * 0.010
= -0.016, -0.197, 0.007, 0.980 (sum of sqaures = 1.000)




[Edited by - Jiia on September 19, 2004 8:19:08 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Jiia
Here are some printed out values of real in-game quaternions. Am I accidently getting values that work? It always seems to work..?

*** Source Snippet Removed ***

First, those test quaternions are all very similar, so they will produce similar results. Second, you're cutting off precision.
-0.004^2 + -0.316^2 + 0.036^2 + 0.948^2 = 0.999872
Try using extreme cases, such as a rotation of 90 degrees around the X axis interpolated with a 90 degree rotation around the Y axis. You may be luck in that in-game values are 'close enough' that occasionaly normalisation to avoid numerical errors will hide the problem. But then again, you may not.

Share this post


Link to post
Share on other sites
Quote:
Original post by joanusdmentia
First, those test quaternions are all very similar, so they will produce similar results. Second, you're cutting off precision.
-0.004^2 + -0.316^2 + 0.036^2 + 0.948^2 = 0.999872
Try using extreme cases, such as a rotation of 90 degrees around the X axis interpolated with a 90 degree rotation around the Y axis. You may be luck in that in-game values are 'close enough' that occasionaly normalisation to avoid numerical errors will hide the problem. But then again, you may not.

Actually, those are in-game bones animating while running. But that's all I needed to hear. Thanks [smile]

Share this post


Link to post
Share on other sites
A really obvious example would be

Q1 = (1, 0, 0, 0)
Q2 = (-1, 0, 0, 0)

Both have unit length

Add them together

Q3 = 0.5*(1, 0, 0, 0) + 0.5(-1, 0, 0, 0)
= (0, 0, 0, 0)

Which isnt unit length by any stretch of the imagination.

Share this post


Link to post
Share on other sites
My math lib will provide two separate classes to avoid such mistakes. xUQuat and xQuat. Thus every function of UQuat will ensure that the norm predicate is maintained (with switchable asserts to debug your code). In general there is no need for a sqrt, each operator will contain a custom and optimized renormalization code. To make it more efficient, one can use explicit casts and avoid much of the intermediate renormalizations. Well one still has to know what he computes.

Example (stupid physics like) code :

xUQuat myFunc(xUQuat &_A, xUQuat &_B)
{
xQuat &A=(xUQuat)_A;
xQuat &B=(xUQuat)_B;
// constructor normalizes automatically
xUQuat C(A*B + 2.0f*B + slerp(A,B, 0.3f));
return C;
}

Share this post


Link to post
Share on other sites
Yes,summ of two quaternions *0.5 is not unit-length, unless
both quaternions is equal or very close to be equal.

Length of (A+B)*0.5 in fact is equal to cosine of half-angle between A and B. (where A and B may be quaternions or vectors of any dimension)

Quote:
Original post by Charles B
My math lib will provide two separate classes to avoid such mistakes. xUQuat and xQuat. Thus every function of UQuat will ensure that the norm predicate is maintained (with switchable asserts to debug your code). In general there is no need for a sqrt, each operator will contain a custom and optimized renormalization code. To make it more efficient, one can use explicit casts and avoid much of the intermediate renormalizations. Well one still has to know what he computes.

Example (stupid physics like) code :

xUQuat myFunc(xUQuat &_A, xUQuat &_B)
{
xQuat &A=(xUQuat)_A;
xQuat &B=(xUQuat)_B;
// constructor normalizes automatically
xUQuat C(A*B + 2.0f*B + slerp(A,B, 0.3f));
return C;
}

that's good idea, maybe will add that thing to my math lib too - currently i renormalize too often. Doesn't matter for camera but may matter for some other things....if normalization takes about 200 computer cycles, that's 15M normalizations per second on 3GHz system...

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this