Click to See Complete Forum and Search --> : Can you confirm I am rotating correctly
BodwadUK
Mar 19th, 2010, 06:56 PM
Hi guys, I was wondering if someone could help me out with the theory and maybe even some basic code to the following problem.
I start off with a vertex and a quarternion to rotate. I calculate a second vertex from the quartonion which is fine. Now I have two vectors, I would like to calculate the angle between the first vector and my new second vector.
I decided to calculate the length of the line between the two vertexes with the following code
LineLengthX = sqrt((Y * Y) + (Z * Z))
LineLengthY = sqrt((X * X) + (Z * Z))
LineLengthZ = sqrt((X * Y) + (Y * Z))
This calculates the length of the 3 lines following the 3 angles.
I then thought I could calculate the angle by using trigonometry using atan, I now know the coordinates of a 3rd vector pointing 0 degrees as its Y is the length of the line calculated above with x being zero.
Put simply, Is that right?
Ultimately I am trying to work out the difference between two angles and then splitting it down into parts. For example if I wanted to create 3 vectors sitting in between my 2 vectors I could split the difference between the two angles by 3 and rotate the point by the angles.
I hope that makes some form of sense, I find it hard to explain, I think I am tying myself in knots hence i want to check I am heading in the right direction
:confused::confused::)
jemidiah
Mar 19th, 2010, 09:12 PM
Now I have two vectors, I would like to calculate the angle between the first vector and my new second vector.
This is an often-used operation. One simple way to compute this is, given vectors v and w, calculating the angle theta between them is given with the formula
theta = arccos(v dot w / (|v| * |w|))
arccos = inverse cosine
dot = dot product of vectors
|a| = magnitude of a vector
For example if I wanted to create 3 vectors sitting in between my 2 vectors I could split the difference between the two angles by 3 and rotate the point by the angles.
That sounds reasonable. If you're already using quaternion rotation, you could do this by generating a rotation quaternion using the axis given by the cross product of your original vectors. The amount of rotation would then be calculated as you suggested, which could easily be plugged into an "axis-angle" quaternion rotation routine.
I've read the middle of your post twice ("I decided to calculate..." to "...x being zero."). I can't really make sense of it. Perhaps if you included a picture that might explain things more easily. Then again, perhaps the above arccos method is what you were after.
BodwadUK
Mar 24th, 2010, 04:31 AM
Thankyou for the help.
I think I have finally got the Quartonion code working, now I just need to sit down and work out the angle stuff.
I think I have to work out the z angle, perform the rotation on the z between the two points then work out the Y angle before doing a rotate along the Y and finally finding the x rotation. Oh the joy of 3D lol.
The middle bit was me trying to explain how I created the 3rd point of my triangles. If i know the length of the line of each axis then I can create a third point at 0degrees for example
'Calculate the line length for the X rotation of our vector (From origin 0,0)
L1X = sqrt((Y * Y) + (Z * Z))
See the attached image. I think this might be a complicated way of doing it mind.
Thanks for the help :cool:
edit: The text on the right of the image should say "Known Vertex Point"
jemidiah
Mar 24th, 2010, 06:46 AM
I'm not quite sure what you're trying to do with various rotations, but I'm glad the quaternion bit seems to be working. There is a *ton* of previous work on 3D rotations, so what you're doing has almost certainly already been done or nearly done. Your drawing shows an inclination angle if you use spherical coordinates (http://en.wikipedia.org/wiki/Spherical_coordinates). Perhaps they'll do the conversions you're trying to do more simply.
Again, though, if you're just trying to find the angle between the green and red lines, my first post gives the answer. It uses the dot product, but it turns out that's a really easy thing to compute. It works without having to decompose anything into several different rotations.
Perhaps it would help if I were more explicit. To answer the question,
Now I have two vectors, I would like to calculate the angle between the first vector and my new second vector.
suppose you have two vectors in 3D, (x, y, z) and (a, b, c). You want to find the angle between them. The angle is given, in radians, using VB.NET code by the following:
Math.Acos( (x*a + y*b + z*c)/( Math.Sqrt(x^2+y^2+z^2)*Math.Sqrt(a^2+b^2+c^2) ) )
The numerator is actually the dot product of the two vectors. The denominator is the product of the length of the vectors. This can be derived using the Law of Cosines and the projection interpretation of the dot product, which, if this is what you're trying to do, is most likely equivalent what you're reasoning through.
BodwadUK
Mar 24th, 2010, 09:50 AM
hmmm maybe I am mixing myself up here.
In order to rotate in 3d space would I not need 3 angles? I need an angle to rotate on the X-axis, an angle for the Y-Axis and an angle for the Z-Axis.
The example you have given only gives one angle back, which axis is this angle on?
jemidiah
Mar 24th, 2010, 06:59 PM
Now I understand somewhat more. I believe you're trying to use something like Euler angles (http://en.wikipedia.org/wiki/Euler_angles) to represent a point in 3D space, which is not quite right. As for
In order to rotate in 3d space would I not need 3 angles? I need an angle to rotate on the X-axis, an angle for the Y-Axis and an angle for the Z-Axis.
well, it depends on the situation. My guess is that you're projecting a given point onto the x, y, and z axes and trying to find the angle that the projection makes with the axis for reasons that aren't clear to me. I think you can use these three values to at least find the original point, but it's a headache of algebra and it doesn't offer you a very "convenient" way to change the point slightly by modifying the angles you found.
There are several related but different operations that you might be trying to perform. I'll explain them briefly and perhaps you'll be able to say which you want.
1. You have a point in 3D space. You want to rotate it, somehow. You want to be able to end up at any point in 3D space through some controlled rotations.
A standard method to do this is to take an axis of rotation and an angle specifying the amount of rotation. The axis is just a line drawn through the origin. Mentally, imagine grabbing hold of the axis with your right hand, making sure you're not covering the origin. Point your thumb along the line of the axis. Now take any slice through your thumb with the slice being perpendicular to your thumb. Take a point on the slice and rotate it some amount (the amount is given by your input angle) so that it stays on the slice, but also stays the same distance from the axis of rotation.
Rotating points in this manner is called an "axis angle" (http://en.wikipedia.org/wiki/Axis_angle) rotation. Unit quaternions accomplish this type of rotation directly. If you're not using quaternions like this, how are you using them?
2. Take a spaceship in 3D space. You're at some fixed point in space watching it rotate, and you want to describe its rotation in such a way that you could program its rotation in a computer simulation.
This situation requires a rotation of "coordinate frames". This is generally accomplished by use of Euler Angles as mentioned above. Unfortunately there are something like 24 different conventions for specifying Euler angles. If this is what you're trying to do, I'd suggest finding a book on it since it's complicated and short articles like the one I linked probably wouldn't give you enough background.
3. Angle finding: take two points in 3D space. Draw a line between each point and the origin. Now, suppose you're physically taking a compass (http://en.wikipedia.org/wiki/Compass_%28drafting%29) and aligning the two ends exactly with the lines you've just drawn. You want to find the angle the compass will measure.
This situation can be solved in a number of ways, but perhaps the simplest is to use the formula I gave above. You know the position of both the points exactly, so you can then find this "minimum" angle between them.
4. Angle bisecting (or trisecting, etc.). Take two points in 3D space and draw a line between each point and the origin as above. You want to find points in between these two points that are at regularly spaced angles between them. All points should lie on the same plane passing through the origin.
This situation is basically a combination of the above. You can find the angle in the plane the points lie in using (3). You can then rotate one of the points in small steps to produce an even spacing using (1). The axis you want to rotate around is the plane's normal (http://en.wikipedia.org/wiki/Normal_vector). The amount of rotation is some fraction of the angle between the original two points. You can accomplish this rotation using unit quaternions. Done.
If none of these situations describe what you're trying to do, perhaps you can use some of their terminology to more accurately sort out what you're trying to accomplish. Some of them are in a lot of ways quite complicated, but that's the nature of basic computer graphics: the math tends to hit you pretty hard unless you're really up on your linear algebra.
BodwadUK
Mar 25th, 2010, 03:31 AM
I guess i havent really described what I am doing.
I am reading in a 3d file format with animations. The positions of each vertex are read in. When we get to animating the object the rotation of the object is stored in the file as a quarternion, we take the quarternion and establish the point after the rotation has occured. Now I need to smooth out the animation.
The reason we have to do this is because the file format stores key frames, a key frame defines when the rotation changes direction of stops altogether. This means that frames in between the keyframes need to be filled in with code.
Example
Read in vertex starting X,Y,Z position
Read in animation quarternion
Calculated rotated position from the starting point and the quarternion
calculate in between positions to smooth out the animation (This is where I am stuck)
What I am currently trying to do is work out the Eular angles between the starting position and the new calculated position. From these I can create new Quarternion's to establish the positions in each frame
Does that make sense? :)
Sorry about the confusion, Bodwad
jemidiah
Mar 25th, 2010, 08:10 AM
Well, the first idea that comes to mind is to simply do only part of the rotation the quaternion describes. If it rotates a point by 45 degrees, first only rotate by 5 degrees, then by 10, etc. until enough frames have passed that you want the full 45 degrees. I can decompose a quaternion in this way for you if you need.
Euler angles are used to describe rotated *coordinate systems* instead of the rotation of an individual point. I'm not really sure what "working out the Euler angles between the starting position and the new calculated position" means.
So, let's take an easy example. Say that your start key frame has Point A at position (1, 0, 0) on the x axis. Say that your end key frame has Point A at position (0, 2, 0) on the y axis, and you have some nice quaternion Q which you can use in some routine, say RotateWithQuat, so that RotateWithQuat(Q, (1, 0, 0)) = (0, 2, 0). One important thing that's been left out is scaling. Quaternions only rotate points, and rotation, by definition, keeps the distance between the origin and a point that's getting rotated the same. However, in the above Point A goes from 1 unit away from the origin to 2 units away. I'm guessing that the quaternion also encodes the amount of scaling that's necessary. (A simple way to do this would be to encode the scale amount as the magnitude of the quaternion itself, dividing off by this magnitude to make a unit quaternion later for axis-angle rotation. You don't need to understand this parenthetical aside.) You want to generate some number of intermediate positions depending on your frame rate and the time between key frames.
Is the above setup correct? Would you be happy with something like the attached image, where the green point is Point A at position (1, 0, 0), the red point is Point A at position (0, 2, 0), the blue points are the intermediate points for a 3 frame interpolation, and we're just looking at the x-y plane (since I didn't want to draw in 3D)?
If so, and if the scale difference is encoded as above, I'll just write a quaternion "splitting" routine that will make the rotation only proceed a fraction of its total. As for scale, the scale can just be added in linearly. In the above example, for the first frame, make the scale 1.25 for the first interpolation (so the length of A at the first blue dot would be 1.25), then go up to 1.5 and then 1.75 for the second and final interpolated frames. This would transition naturally up to 2 when the key frame is displayed.
In the picture, the angle that each of the blue points makes with the original green point would be, in order, 90/4 = 22.5 degrees, 2*90/4 = 45 degrees, 3*90/4 = 67.5 degrees. The red point would then naturally make a 90 degree angle with the green point. The rotation routine I'm imagining would generate quaternions to accomplish these intermediate rotations, so that you would be able to use the RotateWithQuat routine to interpolate points. Note: the angles that my drawing gives might well not be the above idealized values. I draw poorly.
BodwadUK
Mar 25th, 2010, 08:58 AM
Hello. thats exactly what I need.
I am struggling to work out how the angle is stored in the quarternion so that I can do these divisions correctly :)
jemidiah
Mar 25th, 2010, 09:08 PM
Would you mind posting an example quaternion from your raw data? Something like
Quat = (0.3, 0.12, 0.34, 0.883) corresponding to 0.3+0.12i+0.34j+0.883k in common quaternion notation
This is so that I can see if the scale information is stored like I think it might be. In a unit quaternion, the sum of the squares of the components is 1, which the example actually satisfies since 0.3^2 + 0.12^2 + 0.34^2 + 0.883^2 =~ 1. If you're using unit quaternions, then there's no scale information to find, or it's stored elsewhere, so I suppose I'd ignore it for now.
For notation's sake, label the 4 components of a quaternion as r, i1, i2, and i3 (r = 0.3, i1 = 0.12, i2 = 0.34, i3 = 0.883 in the example). If the quaternion is a unit quaternion, the angle of rotation, theta, is 2*arccos(r). In the example, theta is ~145 degrees. The vector, w, giving the axis of rotation is magically w = (w1, w2, w3) = (i1, i2, i3)/sin(theta/2). (Note: if sin(theta/2) = 0, the axis physically could be anything and the rotation would work out the same; this special case avoids division by 0.) In the example, the axis of rotation is (w1, w2, w3) =~ (0.126, 0.356, 0.926). Note that this, too, is conveniently a unit vector: the sum of squares is ~1.000.
Alright, so that's how you decompose a unit quaternion back into its axis-angle representation. What about the reverse? Given an axis and an angle, how do you generate the unit quaternion? Just reverse the steps. Succinctly, given an angle thetaR (R standing for "reverse" if you were wondering) and a unit vector wR specifying an axis of rotation, the unit quaternion encoding that rotation is just
(cos(thetaR/2), sin(thetaR/2)*wR1, sin(thetaR/2)*wR2, sin(thetaR/2)*wR3) = (r, i1, i2, i3)
Combining this, say you have an initial quaternion (r, i1, i2, i3) and you want to interpolate the rotation it encodes by performing it in some number n even steps. Do the following. Python-style pseudocode used.
def getInterpQuats(Q, n):
''' Prints out interpolated quaternions encoding n successively more
complete partial rotations of the given input unit quaternion Q
'''
(r, i1, i2, i3) = Q
# Find angle of rotation of input quaternion
theta = 2*arccos(r)
# Find axis of rotation of input quaternion
if sin(theta/2) == 0:
# Any axis physically generates the same endpoint, so just pick one
(w1, w2, w3) = (1, 0, 0)
else:
# Reverse engineer the original axis of rotation
(w1, w2, w3) = (i1, i2, i3)/sin(theta/2)
# Find intermediate rotation quaternions
for i in range(n):
# Do part of the overall angle for each step, i, from 1 to n
thetaR = theta * i / (n+1)
# Keep the axis of rotation the same
(wR1, wR2, wR3) = (w1, w2, w3)
# Encode a new unit quaternion to specify this partial rotation
Q = (cos(thetaR/2), sin(thetaR/2)*wR1, sin(thetaR/2)*wR2, sin(thetaR/2)*wR3)
print "Rotation quaternion for interpolated frame " + str(i) + ": " + str(Q)
BodwadUK
Mar 26th, 2010, 04:58 AM
Hello, thanks
My querternion for a rotation of 90 degrees on the Y axis is
w: 0.707
x: 0.0
y: 0.707
z: 0.0
I am just putting this code in now to see if it works :bigyello::bigyello::D
Bodwad
jemidiah
Mar 26th, 2010, 06:08 AM
Cool, it seems like you're using unit quaternions after all and not worrying about scaling, which is the case my pseudocode should handle.
BodwadUK
Mar 26th, 2010, 09:45 AM
Its working really well until I have an angle over 180 degrees, the rotation runs back on itself instead of continuing. I have messed around trying to flip it when its over 180 degrees but cant find a solution.
I will keep trying though :)
Its looking good now, thankyou :D
jemidiah
Mar 26th, 2010, 06:20 PM
I can't think of anything that would cause it to rotate incorrectly after 180 degrees. You could try printing out "theta" to make sure it's recovering the original angle correctly even after 180 degrees, and you could see if you recover the original quaternion if you let i = n+1 in the loop. If you want to reverse the direction of rotation, you could try adding "if theta > pi: theta = 2*pi - theta", which assumes theta is in radians.
jemidiah
Mar 29th, 2010, 06:19 PM
I wanted to mention that in my previous post, setting "theta = 2*pi - theta" only reverses the direction of rotation if the axis is already inverted, which is equivalent to having the handedness of the coordinate system inverted. Sorry that I wasn't clearer.
BodwadUK
Mar 30th, 2010, 02:53 AM
Ok thanks, will have a look at that :)
vbforums.com
Copyright Internet.com Inc., All Rights Reserved.