Talk:OpenGL:Tutorials:Using Quaternions to represent rotation
From GPWikiyesterday, someone (151.188.17.247) added the following comment to the normalise-function (btw.: normalise is british-english. please don't correct non-typos...): "// this is a waste of time becuase most of the operation is done already. it costs more proccessing time to check the length than to continue and normalize it. this code is very un-optimal" This is wrong. the check costs 1 substraction (cheap), 1 absolute (cheap), 1 comparison (cheap) and safes us 1 sqrt (very expensive) and 4 divisions (expensive). If we assume that the comparison comes out negative at least half the time, this saves a lot. If someone has an optimisation (<-- british english) to the code, please post it, I know the code isn't perfect. But that comment is misleading and if someone could revert that change (or tell me how to do that) I'd be grateful. --Tannin 02:57, 27 November 2007 (EST)
I've rolled back the edit. The maths is beyond me, but if required the discussion can continue here. Codehead 05:26, 27 November 2007 (EST)
The movement example doesn't work like it is shown in the example: For example 'movex(xmov * seconds * movespeed)' calculates an argument depending on the distance to move in x-direction. In the movex method the vector is multiplied by the rotation quaternion. In the multiplication method the first thing that is done with the provided vector is to normalize it. Evey calculation that is done for the step size before is lost now because it is always set to one. I bypassed this problem by applying the stepsize after the quaternion vector multiplication. I modified it like this: movex(1) * (xmov * seconds * movespeed). That works as expected and another benefit is that the normalization of the vector in the multiplication method is not needed anymore if this method is used nowhere else.
[edit] MultiplicationJust so that I log my findings... Applying the rotation q2 to q1 by, say, multiplying q1 = q_total; q1 = q1 * q2; q_total = q1; gave me incorrect result, always rotating around the "old" axis. I understand nothing about quaternions, so I might have been doing something wrong. However, after four days of epic newb battle I found that if I change Quaternion Quaternion::operator* (const Quaternion &rq) const {
return Quaternion(w*rq.x + x*rq.w + y*rq.z - z*rq.y,
w*rq.y + y*rq.w + z*rq.x - x*rq.z,
w*rq.z + z*rq.w + x*rq.y - y*rq.x,
w*rq.w - x*rq.x - y*rq.y - z*rq.z);
}
to Quaternion Quaternion::operator* (const Quaternion &rq) const {
return Quaternion(rq.w*x + rq.x*w + rq.y*z - rq.z*y,
rq.w*y + rq.y*w + rq.z*x - rq.x*z,
rq.w*z + rq.z*w + rq.x*y - rq.y*x,
rq.w*w - rq.x*x - rq.y*y - rq.z*z);
}
everything works great! Now, I'll just leave this here. :-) What you have changed the multiplication to is incorrect, please make a post in the forum http://gpwiki.org/forums/ to see if anybody can help in resolving your issue. The multiplication of two quaternions A and B where these are
A=[a,b,c,d] and B=[e,f,g,h] (note: this is not the same as the article, here they are stored in the order [w,x,y,z] or [s,i,j,k] if you prefer) A*B = [ae - bf - cg - dh, af + be + ch - dg, ag + ce + df - bh, ah + de + bg - cf]{Liam 06:49, 29 April 2009 (EDT)} [edit] Bug fixReported by Geveno in normalise function // normalising a quaternion works similar to a vector. This method will not do anything // if the quaternion is close enough to being unit-length. define TOLERANCE as something // small like 0.00001f to get accurate results // WARNING: There is a bug in this code, q(0,0,0,0) will return a division by zero // mag2 will be 0, fabs (0-1) will be 1 that is > TOLERANCE so mag will be 0!!! void Quaternion::normalise() { // Don't normalize if we don't have to float mag2 = w * w + x * x + y * y + z * z; if (fabs(mag2 - 1.0f) > TOLERANCE) { float mag = sqrt(mag2); w /= mag; x /= mag; y /= mag; z /= mag; } } The quaternion(0,0,0,0) is one of the identities(addition) {Liam 19:40, 6 August 2009 (EDT)} |


