Quick Math Angle From Vectors Question

Started by
8 comments, last by Zakwayda 17 years, 3 months ago
Hi All, How can I get 3 independent euler angles from two vectors? I know the dot product of the normalized vectors will give me the difference in angle, but I need to the difference in angle in each of the x, y, z planes so I can build a rotation matrix from it. Is this possible? Thanks! Rael
Advertisement
Oh, as an addendum, I did get the angle for the rotation around 'y', by doing...
		// calculate y rotation		Vector2 directionZx=Vector2(direction.z, direction.x);		directionZx.Normalize();		m_rotation.y=acos(Vector2(1.0f, 0.0f).Dot(directionZx));		if (direction.x < 0.0f)			m_rotation.y=-m_rotation.y;

But when I try and get the rotation around x the same way...
		// calculate x rotation		Vector2 directionZy=Vector2(abs(direction.z), direction.y);		directionZy.Normalize();		m_rotation.x=-acos(Vector2(1.0f, 0.0f).Dot(directionZy));		if (direction.y < 0.0f)			m_rotation.x=-m_rotation.x;

Is has strange results as 'z' passes through zero when 'y' is close to zero because they seem to move closer together which confuses the dot product (if that makes sense?).
Hmm, it seems I got it to work, though I'm not sure why. Maybe someone could explain? I inserted the code...
		// try rotate direction by y		direction=NWVectorTransform(NWMatrixRotateY(-m_rotation.y), direction);

between the two calculations. I assume I'm somehow lining up the vector into the zy dimension? I can't really visualize it, so I'm not sure exactly why it is working.
Quote:Original post by Raeldor
Hi All,

How can I get 3 independent euler angles from two vectors? I know the dot product of the normalized vectors will give me the difference in angle, but I need to the difference in angle in each of the x, y, z planes so I can build a rotation matrix from it.
I didn't look at your code examples too carefully, but I am curious as to why you think you need an Euler angle triple in order to build a rotation matrix.

I'm also wondering what you mean exactly by getting angles 'from two vectors'. Do you mean you want a rotation that rotates from one vector to the other?

If your current code is working as you want it to then I suppose there's no need to mess with it, but I kind of suspect that Euler angles are not the optimal (or most conceptually appropriate) solution to the problem you're trying to solve.
Quote:Original post by jyk
Quote:Original post by Raeldor
Hi All,

How can I get 3 independent euler angles from two vectors? I know the dot product of the normalized vectors will give me the difference in angle, but I need to the difference in angle in each of the x, y, z planes so I can build a rotation matrix from it.
I didn't look at your code examples too carefully, but I am curious as to why you think you need an Euler angle triple in order to build a rotation matrix.

I'm also wondering what you mean exactly by getting angles 'from two vectors'. Do you mean you want a rotation that rotates from one vector to the other?

If your current code is working as you want it to then I suppose there's no need to mess with it, but I kind of suspect that Euler angles are not the optimal (or most conceptually appropriate) solution to the problem you're trying to solve.

Thanks for the reply. I basically have a base camera class that works using position (vector3) and rotation (vector3), same as any other class based on Node. I sub-classed this camera to provide a 'TrackCamera' class, which can follow and/or track (point to) an object. I have calculated the camera position and the target position, but I now need to work out the rotation of the camera to point the camera towards the target as the 3 euler angles required by the base class. The rotation of the camera is based off a base vector of (0,0,1), ie looking straight down the z axis.

Hope this clarifies a little; sorry for the confusion.
Quote:Original post by Raeldor
Thanks for the reply. I basically have a base camera class that works using position (vector3) and rotation (vector3), same as any other class based on Node. I sub-classed this camera to provide a 'TrackCamera' class, which can follow and/or track (point to) an object. I have calculated the camera position and the target position, but I now need to work out the rotation of the camera to point the camera towards the target as the 3 euler angles required by the base class. The rotation of the camera is based off a base vector of (0,0,1), ie looking straight down the z axis.
I see. I'm assuming 'Node' is your own class and not part of some API that you're using? I also assume that when you say you're representing your orientations as a 'vector3' you mean as three Euler angles that just happen to be stored in the x, y, and z elements of the vector.

My next question would be, why choose Euler angles as the fundamental representation for rotations and orientations in your base Node class? IMO, of the possible choices that immediately spring to mind (Euler angles, quaternion, two orthonormal vectors, three orthonormal vectors, 3x3 matrix, axis-angle pair, compressed quat, compressed axis-angle pair), Euler angles are the least useful and the hardest to work with, generally speaking. For a generic scene graph (i.e. no particular assumptions about the nature of the environment it represents) Euler angles would be my last choice.

That said, maybe there are constraints on your environment or on the particular problem in question that make Euler angles a not-so-bad choice. For example, perhaps you want your camera to track the target while remaining more or less upright (that is, it can yaw and pitch, but not roll).

If that is the case, then you only need to compute two angles, not three. For the purpose of working with your existing Euler-angle based interface you can just set the third angle to zero.

To compute the angles, you need to perform a cartesian-to-spherical coordinate conversion using the vector from the camera position to the target. If you need any hints or specifics on how to do this I'll be glad to try and help further if I can.
Yes, you are right on the money with your assumptions. As for why I chose euler angles, well I guess because it's easier to visualize when debugging. Also, yes I do not really have camera roll ability (at least not yet).

I am not familiar with cartesian-to-spherical coordinate conversion. It sounds like it somehow treats the co-ordinate as a point on a sphere? I would love some more information on this if you have it.

Thanks!
Quote:Original post by Raeldor
Yes, you are right on the money with your assumptions. As for why I chose euler angles, well I guess because it's easier to visualize when debugging. Also, yes I do not really have camera roll ability (at least not yet).
Yeah, many people find Euler angle rotations easier to visualize then arbitrary rotations in whatever form. That can be a good reason for using them in an editor or interface of some sort, but for actually working with arbitrary rotations I think other representations should usually be preferred. Just IMO (and perhaps something to consider in the future).
Quote:I am not familiar with cartesian-to-spherical coordinate conversion. It sounds like it somehow treats the co-ordinate as a point on a sphere? I would love some more information on this if you have it.
If you google 'spherical coordinates' you'll find a number of good explanations of the general concept, along with how to convert to and from cartesian coordinates. However, being math rather than programming references the conversions are usually not expressed in the most useful way (e.g. use of atan() rather than atan2()). Plus, there are varying conventions for how the conversion is to be performed that can lead to confusion.

Here's some C++ code for performing the conversion. I'll add some comments to clarify some things; from there you should be able to strip out the things you don't need and make any other changes that are necessary.

template < class VecT, typename Real > voidcartesian_to_spherical(    const VecT& v,      // The vector from which to convert    Real& radius,       // The radius on output (you can ignore this)    Real& theta,        // The 'yaw' angle on output    Real& phi,          // The 'pitch' angle on output    size_t axis,        // Which axis (0, 1, or 2) should be treated as 'up'    SphericalType type, // You can ignore this argument    Real tolerance = epsilon<Real>::placeholder()){    typedef Real value_type;    size_t i, j, k;    cyclic_permutation(axis, i, j, k);    // cyclic_permutation() does the following:    // i = axis;    // j = (i + 1) % 3;    // k = (j + 1) % 3;    // length(x,y) just does what you think it does...    value_type len = length(v[j],v[k]);    theta = len < tolerance ? value_type(0) : std::atan2(v[k],v[j]);    radius = length(v, len);    if (radius < tolerance) {        phi = value_type(0);    } else {        phi = std::atan2(len,v);        // You want phi as the colatitude, not latitude, so you can just        // remove this block of code:        if (type == latitude) {            phi = constants<value_type>::pi_over_2() - phi;        }    }}

These conversions can be a little tricky to get right in context, so I can't guarantee that if you plug the above into your code you'll get the correct results (although you very well may - it's just that there might be other factors involved that I'm not aware of).

So you can try the above, or just google 'spherical coordinate conversion' and see what you come up with - I'm sure there's code for this floating around online somewhere.
That's awesome, thank you. It looks a lot more elegant than my code! :P. I'll give it a shot and then try and break it down and see how it's working from a geometry point of view.

OOI, what would be your preferred method of storage for rotations? Quaternions?

Thanks
Rael
Quote:Original post by Raeldor
OOI, what would be your preferred method of storage for rotations? Quaternions?
For a generic scene graph (and assuming that memory is not at a premium) I think either a quaternion or a 3x3 matrix would be a good choice. If you're doing a lot of interpolation or concatenation of rotations, quaternions might come out a bit ahead in terms of efficiency and ease of use.

Presumably you'll need a matrix representation of the node transform at some point, so you also have to factor in the expense of converting the quaternion to a matrix. It's not a particularly costly operation, but if you store your orientations as matrices in the first place, then of course no conversion is necessary.

In short, whatever representation you choose, there will be tradeoffs in terms of efficiency, stability, convenience, and storage requirements.

This topic is closed to new replies.

Advertisement