7

I have two 3D vectors called A and B that both only have a 3D position. I know how to find the angle along the unit circle ranging from 0-360 degrees with the atan2 function by doing:

EDIT: (my atan2 function made no sense, now it should find the "y-angle" between 2 vectors):

toDegrees(atan2(A.x-B.x,A.z-B.z))+180

But that gives me the Y angle between the 2 vectors. I need to find the X angle between them. It has to do with using the x, y and z position values. Not the x and z only, because that gives the Y angle between the two vectors. I need the X angle, I know it sounds vague but I don't know how to explain. Maybe for example you have a camera in 3D space, if you look up or down than you rotate the x-axis. But now I need to get the "up/down" angle between the 2 vectors. If I rotate that 3D camera along the y-axis, the x-axis doens't change. So with the 2 vectors, no matter what the "y-angle" is between them, the x-angle between the 2 vectors wil stay the same if y-angle changes because it's the "up/down" angle, like in the camara.

Please help? I just need a line of math/pseudocode, or explanation. :)

Arundel
  • 115
  • 2
  • 2
  • 9
  • Let's use [yaw, pitch and roll](http://tinyurl.com/cof3pkm) to name your different rotations. As I read your text, “X angle” refers to “yaw” (“pan” for the camera) and “Y angle” refers to “pitch” (“tilt” for the camera). Usually a rotation around the yaw axis will change the location of both pitch and roll axes. When you write “the x-angle stays the same no matter what the y-angle is”, then it seems that you're defining the yaw axis absolutely (always pointing “up”), but the other two relative. But it is unclear how they are defined. Can you rephrase the question using these terms? – MvG Sep 03 '12 at 19:58

3 Answers3

8
atan2(crossproduct.length,scalarproduct)

The reason for using atan2 instead of arccos or arcsin is accuracy. arccos behaves very badly close to 0 degrees. Small computation errors in argument will lead to disproportionally big errors in result. arcsin has same problem close to 90 degrees.

maxim1000
  • 6,297
  • 1
  • 23
  • 19
6

Computing the altitude angle

OK, it might be I finally understood your comment below about the result being independent of the y angle, and about how it relates to the two vectors. It seems you are not really interested in two vectors and the angle between these two, but instead you're interested in the difference vector and the angle that one forms against the horizontal plane. In a horizontal coordinate system (often used in astronomy), that angle would be called “altitude” or “elevation”, as opposed to the “azimuth” you compute with the formula in your (edited) question. “altitude” closely relates to the “tilt” of your camera, whereas “azimuth” relates to “panning”.

We still have a 2D problem. One coordinate of the 2D vector is the y coordinate of the difference vector. The other coordinate is the length of the vector after projecting it on the horizontal plane, i.e. sqrt(x*x + z*z). The final solution would be

x = A.x - B.x
y = A.y - B.y
z = A.z - B.z
alt = toDegrees(atan2(y, sqrt(x*x + z*z)))
az = toDegrees(atan2(-x, -z))

The order (A - B as opposed to B - A) was chosen such that “A above B” yields a positive y and therefore a positive altitude, in accordance with your comment below. The minus signs in the azimuth computation above should replace the + 180 in the code from your question, except that the range now is [-180, 180] instead of your [0, 360]. Just to give you an alternative, choose whichever you prefer. In effect you compute the azimuth of B - A either way. The fact that you use a different order for these two angles might be somewhat confusing, so think about whether this really is what you want, or whether you want to reverse the sign of the altitude or change the azimuth by 180°.


Orthogonal projection

For reference, I'll include my original answer below, for those who are actually looking for the angle of rotation around some fixed x axis, the way the original question suggested.

If this x angle you mention in your question is indeed the angle of rotation around the x axis, as the camera example suggests, then you might want to think about it this way: set the x coordinate to zero, and you will end up with 2D vectors in the y-z plane. You can think of this as an orthogonal projection onto said plain. Now you are back to a 2D problem and can tackle it there.

Personally I'd simply call atan2 twice, once for each vector, and subtract the resulting angles:

toDegrees(atan2(A.z, A.y) - atan2(B.z, B.y))

The x=0 is implicit in the above formula simply because I only operate on y and z.

I haven't fully understood the logic behind your single atan2 call yet, but the fact that I have to think about it this long indicates that I wouldn't want to maintain it, at least not without a good explanatory comment.

I hope I understood your question correctly, and this is the thing you're looking for.

MvG
  • 57,380
  • 22
  • 148
  • 276
  • Thanks I corrected my atan2 function, I mistakenly typed it wrong. Now it should get the "y-angle" between the 2 vectors. I will try to use your version which substracts the angles. I understand your orthogonal projection suggestion too. If it doesn't work after many attempts I'll try to explain it a bit more. – Arundel Sep 03 '12 at 18:45
  • Ok, it doesn't solve my problem but I must say we're getting close. So my camera example again: if the camera rotates up or down, the x-angle changes. If the y-angle changes, the x-angle doesn't. So no matter what the "y-angle" (like with my atan2 function) is between the vectors, x-angle between the vectors stays the same. x-angle between the vectors is always 0 if: the vectors y positions are the same, x-angle is always 90 degrees if: vector A is ontop of B, x-angle is always -90 if: A is below B. And you know, everything in between those values. – Arundel Sep 03 '12 at 19:20
  • @user1569781: Sounds like you want to project onto some plane which contains the *y* axis, but not necessarily the *z* axis as well. So that plane seems to be in some way defined by the *y* axis and your two vectors. But how? Is one of your vectors like the camera, so that you want to project onto the plane spanned by that vector and the *y* axis? Or are you looking for a symmetric solution, which yields the same result if you interchange *A* and *B*? – MvG Sep 03 '12 at 20:03
  • @user1569781, reading your comment again, I hope that I've finally gotten this right. Is the edited solution above what you're looking for? – MvG Sep 03 '12 at 20:12
  • Oh wow thanks so much @MvG, it's indeed the **altitude** that I wanted. I've heard of the terms azimuth and altitude, just not how they work. I'm sorry for the vague way I tried to explain it, but finally it works. Thanks very much. And I thank everyone else who contributed information. :D I hope others might learn from this if they find this thread. If you're curious what I'm gonna do with this: I've made a basic 3D game engine out of 2D Gui's, and this information will be VERY useful for the 3D camera and the 3D scene. :) – Arundel Sep 04 '12 at 14:32
4

Just like 2D Vectors , you calculate their angle by solving cos of their Dot Product

Dot product of a 3d vector
You don't need atan, you always go for the dot product since its a fundamental operation of vectors and then use acos to get the angle.

double angleInDegrees = acos ( cos(theta) ) * 180.0 / PI;
Christian
  • 1,492
  • 3
  • 16
  • 19
  • Thanks, but there are problems. When vector A is parallel (in front) to vector B, I tried with these vectors: A<4, 6, 17>; B<4, 6, -8> it should give 0 degrees, because the y axis is the same. But it gives approx. 24.19 degrees. When I tried: A<4, 6, 17>; B<4, 21, 17> it gives approx. 48.96 degrees. It's supossed to be 90, because vector B is ontop of A. Can you see what's wrong? Is theta the whole formula or how can I solve it if it isn't? – Arundel Sep 01 '12 at 18:50