How to find a position's angle around an arbitrary axis?
So I'm setting an object's position using Quaternion.AngleAxis(angle, axis). Sometimes the object moves in other ways, so I can't just cache the angle. Later on I want to essentially do the reverse of Quaternion.AngleAxis to get the thing's angle relative to the arbitrary axis it's been rotated around. How do I do this?
This question was asked a while ago, and somewhat unhelpfully resolved because the person had been rotating around a basic world axis and EulerAngles happened to give them what they needed. It was also asked here and never answered.
Answer by streeetwalker · Sep 24, 2020 at 07:29 AM
First, by "arbitrary axis" do you mean the axis could be the x, y or z axis, our you mean literally any axis? Because there are an infinite number of axes. If you mean x, y, or z then your job is easier
Conceptually you project the point on to any plane that is orthogonal to axis, get the value one of the point's coordinate dimensions on that plane, and use Arc Cosine or Arc Sine on that value (depending on which dimension you get) to come up with the angle in radians. Then convert to degrees.
There is an arbitrary factor to this, and that is where do you measure the angle from? You have to decide that. There are some conventions. For example, in 3D trigonometry, rotation about the y axis in the xz plane is measured counter-clockwise from the positive x axis. However, Unity flips this around and starts from the positive z axis and moves clockwise.
To take the easy case, for example: you want to know how the point has been rotated about the y axis. The plane you use is the xz plane. You don't need to go through the process of projecting the point onto that plane, because the point's coordinates are already given in those dimensions.
In this example, You will get either the point's x or z dimension coordinate value, and then use that value in the Mathf.Acos or Asin - you'll have to decide which. Each will return the complementary angle of the other measured from either x or z, depending on which dimension you choose (to clarify: Mathf.Acos( x ) = compliment of Mathf.Asin( x ); and Mathf.Acos( x ) = Mathf.Asin( z ) ). Lastly, those angles are given in trigonometric counterclockwise based measures, and you'll need to convert that to the clockwise measure that Unity uses.
For an intuitive look at how this works, play around with the 2D widget near the top of this page. In that widget, you'd be measuring rotation on the z axis. https://mathinsight.org/polar_coordinates
That's the theory, and you'll have to work out the details of how to choose an arbitrary axis, which plane you then use, and which calculations.
If you are actually talking about any arbitrary axis, the concept is the same, but you will need to do an actual projection onto the plane orthogonal to the axis of rotation. I've done that before in Unity, so it is possible, but a little bit more of code than if you stick with only x, y, or z rotation.