Thread: Confuted/Blackrat: quaternion question

  1. #1
    Banned
    Join Date
    Jan 2003
    Posts
    1,708

    Confuted/Blackrat: quaternion question

    this is aimed towards confuted/blackrat, I saw jdinger do the same thing aimed towards me (but others answered) so this is aimed at confuted but anyone can answer.

    Anyway before I got so friggin sick I read finding the quaternion itself is actually extremely simple, that it is just:

    q = cos(theta/2) + A sin(theta/2)

    of course they had to go through a ton of confusing theory and complex equations first, and then they just used identities to break it down

    A is the unit axis you are rotating about

    However I have no clue how to apply this. It says I have to use the 'homomorphism'
    q P q-1

    to perform the rotation, where P stands for the point/vector you are rotating. However, I'm not entirely sure what I'm doing!!! Is q-1 the inverse of the quaternion or the conjugate of the quaternion? In my math book they seem to use q-1 as the conjugate, when it should mean the inverse. and my understanding is that the inverse is:
    conjugate over modulus squared

    the modulus of a complex number is z is:
    z * conjugateofz

    and the conjugate is where the imaginary part is negated, and using the definition i = sqrt(-1) you get:
    z * conjugate = (a + bi) ( a - bi) = a^2 + b^2

    anyway back to quaternions, if you can just explain what I'm doing here with :
    q P q-1 and how to actually carry out that multiplication I'd be happy!

  2. #2
    Pursuing knowledge confuted's Avatar
    Join Date
    Jun 2002
    Posts
    1,916
    You're in luck. Some people over at gamedev just helped me out with this

    If I understood what you just said correctly, you just need to know how to multiply them. I posted the method for performing the actual multiplication in another thread, here's the order to do it in and such.

    First, you'll need to have a permanent quaternion which represents all of the rotations (cumulative) that your object has undergone. Initialize it to (1,0,0,0) (w,x,y,z) to represent no rotations. That part is important
    Quaternion = (1,0,0,0)

    Then, when you want to represent a rotation, you'll make a temporary quaternion. Here's the way to do that (example is for the X axis, it's easy enough to change)
    local_rotation = ( cosf( fDeltaX/2), sinf( fDeltaX/2 ), 0, 0 )
    where fDeltaX is the amount of rotation.

    Then, just do this:
    Quaternion = local_rotation * Quaternion

    That will update your quaternion correctly, and the axes will rotate with the primitive.... like they should. And it won't gimbal lock. Woot woot.

    I'm not really sure what you were trying to do with some of what you posted... but what I just said is the way to do it. What math book do you have that has quaternions in it? Does it have other cool math in it? (not the standard stuff they teach us in high school...) That isn't your pizza and calculus book, is it?
    Away.

  3. #3
    Banned
    Join Date
    Jan 2003
    Posts
    1,708
    no my pizza and calculus book is just calculus. this one is "mathematics for 3d game programming and computer graphics" by eric lengyel. It has (literally) everything in it, from ray tracing to binary space partitioning algorithms to radiosity calculations to liquid simulation to software rasterization calculations...everything!

    EDIT:
    local_rotation = ( cosf( fDeltaX/2), sinf( fDeltaX/2 ), 0, 0 )
    does that mean the w coordinate is the cosine and the x component is the sin? Doesn't the sin just cancel when you multiply it by the original quaternion used to represent all of the rotations?

    EDIT1:
    and where does all of this come in:
    q = cos(theta/2) + A sin(theta/2)
    ?
    Last edited by Silvercord; 08-17-2003 at 09:32 PM.

  4. #4
    Crazy Fool Perspective's Avatar
    Join Date
    Jan 2003
    Location
    Canada
    Posts
    2,640
    > mathematics for 3d game programming and computer graphics

    is that book good? i was gonna buy it but then i saw this
    its the second edition and it comes out decemberish. I think im gonna wait for it.

  5. #5
    Pursuing knowledge confuted's Avatar
    Join Date
    Jun 2002
    Posts
    1,916
    is it a good book? Accurate and such? Does it have any source in it?

    local_rotation = ( cosf( fDeltaX/2), sinf( fDeltaX/2 ), 0, 0 ) // (w,x,y,z)

    does that mean the w coordinate is the cosine and the x component is the sin?
    Yup

    Doesn't the sin just cancel when you multiply it by the original quaternion used to represent all of the rotations?
    To quote my post in this thread:
    The quaternion which represents no rotation is (1,0,0,0) (that's w,x,y,z) It's possible to find the quaternion that represents the total rotation given by two quaternions by multiplying them together. Here's the formula for quaternion multiplication
    Code:
    (Q1*Q2).w = w1w2 - x1x2 - y1y2 - z1z2
    (Q1*Q2).x = w1x2 + x1w2 + y1z2 - z1y2
    (Q1*Q2).y = w1y2 + y1w2 + z1x2 - x1z2
    (Q1*Q2).z=w1z2+z1w2+x1y2-y1x2
    It's not communitive. w1*w2 != w2*w1.
    You can work it out on paper if you'd like, but for the short answer: no, it doesn't. Remember, though, order of multiplication matters. Order of multiplication matters. Order of multiplication matters. Yes, it matters. It matters, and if you mess it up, you'll end up writing code like what I originally had Here's a bit of clarification about how the quaternion works.

    You make a local_rotation quaternion, which represents the CHANGE that you want. You have another quaternion which represents all the other changes that have happened. Multiplying two quaternions which represent two different rotations will produce one quaternion representing the total rotation. But order of multiplication matters. Remember that

    Suppose you took (1,0,0,0) (w,x,y,z) and rotated it 90 degrees over the X axis. The W and X compents in the local_rotation quaternion would be sqrt(2)/2, but Y and Z would be 0. After the multiplication, the total quaternion would be (sqrt(2)/2,sqrt(2)/2,0,0) Then you make a new local_rotation quaternion representing a 90 degree rotation on the Y axis. This local_rotation quaternion will be (sqrt(2)/2,0,sqrt(2)/2,0) Extending the example, when you multiply this local_roation quaternion with the total quaternion, you'll get a new total quaternion according to the following math:
    Code:
    (note: (sqrt(2)/2)^2 = .5)
    total.w = .5 - 0 - 0 - 0 = .5
    total.x = .5 + 0 + 0 - 0 = .5
    total.y = 0 + .5 + 0 - 0 = .5
    total.z = 0 + 0 + 0 - .5 = -.5
    This represents the one axis about which a rotation will create the composite of the other two rotations. If you have strong visualization skills, pick something up and rotate it around in your hands according to what I said above, and then try to visualize the one axis that would do this totally. You'll find that it's what I just computed And, to show that the magintude is still 1 (still a unit quaternion), I'll do this
    Code:
    |Q| = sqrt( (.5)^2 + (.5)^2 + (.5)^2 + (-.5)^2)
    |Q| = sqrt ( .25 + .25 + .25 + .25)
    |Q| = sqrt ( 1 )
    |Q| = 1
    Make sense now?
    Away.

  6. #6
    Banned
    Join Date
    Jan 2003
    Posts
    1,708
    To answer your questions about the book, yes it is accurate, yes it has some source in it (both in assembly and C++), and yes it is awesome. You may as well wait for the second edition. However, this book is very up to date, it is geforce3 era (its copyright date is 2002). Just to be cool I might buy the updated one as well.

    confuted: I basically just forgot that you have to do all sorts of special things when multiplying quaternions (all of which you have nicely posted for us).

  7. #7
    Pursuing knowledge confuted's Avatar
    Join Date
    Jun 2002
    Posts
    1,916
    Alright, so you've got it?
    Away.

  8. #8
    Banned
    Join Date
    Jan 2003
    Posts
    1,708
    I think I understand it more than I did, but you've got to correct me where I'm wrong. The questions I had about conjugates and inverses above are still unanswered, but I've got a good idea about what is going on with those, but this is what I think I got out of what you said:

    You have a single quaternion that represents all of the rotations that represent the change this frame. You must multiply your quaternion (which is set to <1, 0, 0, 0> each frame) by each of the other quaternions that represents a rotation. Then finally you multiply your single quaternion by your vector and it rotates it for this frame.

    Now, exactly how do multiply your quaternion by the view vector? I assume your view vector is just a quaternion with a w value of 0?

    EDIT:
    and to turn the vector you are rotating about into a quaternion it seems you always have cos(theta/2) as the w value, then the Vector * sin(theta/2), or as you said for the rotation about the x axis:
    qx = <cos(theta/2), sin(theta/2), 0, 0>
    qy = <cos(theta/2), 0, sin(theta/2), 0>

    q = <1, 0, 0, 0> //cumulative rotation for this frame
    qview = <0, view.x, view.y, view.z>

    using properties of quaternion multiplication:
    q *= qx;
    q *= qy;
    qview *= q
    Last edited by Silvercord; 08-18-2003 at 12:51 PM.

  9. #9
    Pursuing knowledge confuted's Avatar
    Join Date
    Jun 2002
    Posts
    1,916
    I'm not sure about the notation that you were using in the first post. They conjugate of a quaternion is
    w-x-y-z
    but I don't know why you even need it :-/

    Here's what you need to have in a program.

    A quaternion which will represent ALL of the rotation your object/camera has undergone. At the beginning of the program this will be initialized to (1,0,0,0) It won't be initialized again after that. We'll call this quaternion qTotal. When initialized, it represents no rotation at all.

    Then, you have a temporary quaternion, which we'll call qTemp. (I called it local_rotation in the last post. Perhaps that was confusing.) qTemp won't need to be initialized to (1,0,0,0) because you'll be assigning the values to it. qTemp will be changed each frame. Perhaps several times if you design your system like mine (I'll attach the code, and I'll even comment it ) Suppose you're changing the rotation of your object/camera 1 degree over the x axis in a certain frame. You'll build a qTemp quaternion which represents a 1 degree rotation over the x axis. (See some of my other posts for how to do this) To reitterate, qTemp will just be representing the CHANGE each frame. qTotal will represent the total rotations that the object has undergone, cummulative, over every frame. So i you rotate over x, then over y, then over z, then over x some more, qTotal will represent all of that. qTemp will just represent the most recent change.

    After you've generated qTemp for the change you want, you'll need to update qTotal.
    Code:
    qTotal = qTemp * qTotal;  //note: the order matters, don't mess it up.
    //qTotal *= qTemp will not produce the same results, and will mess your code up
    To turn the vector you are rotating about into a quaternion, you had it right. w=cos(theta/2); and vector*sin(theta/2).

    I'm not sure what you mean by multiplying the quaternion by the view vector. Right now, I haven't implemented my camera class with quaternions yet - just a transformation class. Why do you need to multiply the quaternion by the view vector? What are you trying to accomplish by that?
    Away.

  10. #10
    Pursuing knowledge confuted's Avatar
    Join Date
    Jun 2002
    Posts
    1,916
    Darn, I forgot that I was going to post source. I stuck a couple links in the comments. I haven't read the thing on matrices yet, but it looks interesting, so I'm off to do that now...
    Away.

  11. #11
    Banned
    Join Date
    Jan 2003
    Posts
    1,708
    You didn't exactly confirm or deny if what I was gathering from what you said is correct, but I am assuming everything I said is correct except for:

    q *= q1 really means
    q = q1 * q

    (that was from my last post)

    i.e the whole thing I said about w always being cos(theta/2) and then axis * sin(theta/2) seems to be correct
    You also didn't confirm if the view vector is treated as a quaternion with a w value of 0, but I check in my math book and sure enough any directional vector has a w value of 0

  12. #12
    Pursuing knowledge confuted's Avatar
    Join Date
    Jun 2002
    Posts
    1,916
    i.e the whole thing I said about w always being cos(theta/2) and then axis * sin(theta/2) seems to be correct
    It is.


    You also didn't confirm if the view vector is treated as a quaternion with a w value of 0, but I check in my math book and sure enough any directional vector has a w value of 0

    I'm not sure what you're trying to do with this :-/ I think I might know now, but I'm not sure. Are you going to be rotating your view vector with the quaternions? I don't have experience with quaternions that are just a direction vector, but I guess go with what your math book says, because it seems correct.

    Now, to turn the tables a bit... I have a camera class, but parts of the general concept of cameras aren't clear to me. I'd like to convert my camera class to quaternions in the (somewhat) near future. Which will probably involve me writing a lot of stuff I haven't had to write, because I'm not sure D3D will handle it by itself. Okay, so the view vector represents the direction you're looking - the camera's Z axis. The up vector is the camera's Y axis. The strafe vector is the camera's X axis. Mouse movements would translate into rotation on the strafe and up vectors of the camera - right? (FPS controls, not flight sim) What information do you store in your camera class, silvercord? Ha, I'm not really sure what my question is.
    Away.

  13. #13
    Banned
    Join Date
    Jan 2003
    Posts
    1,708
    What I do is I calculate how far the mouse has moved this frame (from the center of the screen), convert it to radians, add those radians this frame to my member variables that keep track of the total radians to rotate about the y axis and strafe vectors. The latter is capped at PI/2 radians (looking straight up or straight down). The point (0, 0) is at the top left of your screen in screen coordinates, with the positive Y axis extending down towards the bottom of the screen.

    To convert from screen change to radians use this proportion and cross multiply and divide to get the answer that solves for radians

    radians / PI = deltaX / SCREEN_WIDTH/2;
    radians / PI = deltaY / SCREEN_HEIGHT/2;

    No gimbal lock, allows for role, I can even post some code that jinks the player in a helicopter like effect when strafing by rotating the Up vector about the View vector slightly

    EDIT: it is also important to note that a rotation through a positive number of radians about an axis is in the counter clockwise direction, not clockwise. Keep that fact and what I said about screen coordinates in mind when performing these calculations.

    EDIT1: also note the RotateVector prototype:
    RotateVector(float Angle, Vector3 *VectorToRotateAbout, Vector3 *VectorToRotate)


    Code:
    bool	Camera::CheckMouse() 
    {
    	POINT MousePos;
    	GetCursorPos(&MousePos);
    	SetCursorPos(MIDDLEX, MIDDLEY);
    	if(MousePos.x == MIDDLEX && MousePos.y == MIDDLEY)
    		return false; 
    	
    	float YDeviation = (MIDDLEY - MousePos.y);		
    	float XDeviation = (MIDDLEX - MousePos.x);		
    	
    	XDegRad = (PI * YDeviation) / (SCREEN_WIDTH/2); //radians to rotate view vector about X axis
    	xRadians += XDegRad; 
    
    	
    	if(xRadians > HALFPI)
    	{
    		xRadians = HALFPI;
    		XDegRad = 0;
    	}
    	
    	else	if(xRadians < -HALFPI)
    	{
    		xRadians = -HALFPI;
    		XDegRad = 0;
    	}
    
    	YDegRad = (PI * XDeviation) / (SCREEN_HEIGHT/2); //radians to rotate view vector about Y axis	
    
    	yRadians	+=	YDegRad;
    	float cosXTheta = (float)cos(XDegRad);	
    	float sinXTheta = (float)sin(XDegRad);	
    	
    	float cosYTheta = (float)cos(YDegRad);	
    	float sinYTheta = (float)sin(YDegRad);	
    
    	mView = Vector3(0, 0, 1);
    	mUp	  = Vector3(0, 1, 0);
    	
    	RotateVector(yRadians, &mYAxis, &mView);
    	mStrafe = CrossProduct(mView, mYAxis);
    	RotateVector(xRadians, &mStrafe, &mView);
    	mUp = CrossProduct(mStrafe, mView);
    	
    	return true;
    }
    Last edited by Silvercord; 08-18-2003 at 06:08 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Alice....
    By Lurker in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 06-20-2005, 02:51 PM
  2. Debugging question
    By o_0 in forum C Programming
    Replies: 9
    Last Post: 10-10-2004, 05:51 PM
  3. Quaternion question
    By Mr Q in forum Game Programming
    Replies: 15
    Last Post: 04-21-2004, 09:34 AM
  4. Camera problem: rolling
    By darksaidin in forum Game Programming
    Replies: 37
    Last Post: 08-15-2003, 08:49 AM
  5. Question...
    By TechWins in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 07-28-2003, 09:47 PM