Why is this multiplication of two quaternion rotations not working correctly
Hey guys, I have the following problem: I want to rotate a coordinate system relative to a sphere with the following constraints:
a) y-Axis points away from the center of the sphere (priority1)
b) z-Axis matches with the spheres z-Axis as well as possible (priority2)
Unitys LookRotation() basically does this job, but in the opposite way. While I need to perfectly align the coordinate Systems y-Axis and secondary the z-Axis, this method perfectly aligns the coordinate Systems z-Axis and secondary the y-Axis.
To finally meet my conditions I had the idea to first use LookRotation and afterwards rotate the coordinate System around its x-Axis to align the Vectors correctly, but this doesn´t work as expected. Can you please help me with this problem? Am I doing anything wrong or do I misunderstand the multipication of quaternions?
Thats the code i wanted to use:
CoordinateSystem.transform.rotation = Quaternion.LookRotation(CoordinateSystem.transform.position, Vector3.back) * Quaternion.AngleAxis(90, CoordinateSystem.transform.right);
Answer by SilverLife · May 09, 2019 at 08:26 AM
First of all I am really thankful for your help, I really appreciate it! THANK YOU! Secondly, I think I might haven´t explained the Problem detailled enough and I am really sorry about this!!! Finally I figured out a way to make it work. Now I will share my solution with you, but first of all I will again explain my problem in detail. Currently I am developing a Flight Simulator. Therefore I receive my position-data as lat-long geo-coordinates. To create a local coordinate System for my plane where I can apply pitch, bank and yaw angles the basic plane coordinate System has to be always parallel to a spheres surface which in my case is the Earth .
Secondly this plane coordinate System has to aways point towards the Earth´s North-Pole with it´s z-Axis, but it still has to be parallel to the Surface. (see the Picture, the red dot is the North pole, the xyz-axis is the one of my plane-coordinateSystem as it should be)
I guess there are 3 ways to reach this goal:
The first is a complex combination of rotations, manually calculated (what I tried in the beginning but my calculation(which obviously was not correct) didn´t work at each earth hemisphere so I was looking for another solution)
The second, which we discussed here is, to combine the lookRotation() with another one to just swap the z and the y axis make it point in the correct direction.
Finally my solution was, to add a parent gameObject. I applied the lookRotation() to this parent Object. The parent's child is my basic plane coordinateSystem and as default I gave it the Rotation x = Now the parent has x pointing away from the earth Center and y pointing towards the South Pole. With the Default x-rotation of the child object I swapped those two vectors and got what i was Looking for.
If you can help me with the second solution way (the one where lookRotation is used with a second Rotation) to learn how this would have worked it would be great, just to enhance my knowledge, because I don´t like the current solution with the extra GameObject.
I get nice results with the code I gave you in my comment, I've reworked it a little bit
public Transform Earth;
public Transform NorthPole;
public Transform CoordinateSystem;
void LateUpdate()
{
Vector3 up = (CoordinateSystem.transform.position - Earth.position).normalized;
Vector3 forward = (NorthPole.position - transform.position).normalized ; // Or Earth.forward if you know the north pole is located at the surface of the +Z axis of the earth;
Vector3 right = Vector3.Cross( up, forward );
forward = Vector3.Cross( right, up );
CoordinateSystem.transform.rotation = Quaternion.LookRotation( forward, up );
}
Your reworked code gives me perfect results too, I don´t know why it didn´t behave correct the first time, it might be my fault ;)
Thank you very much man!
Answer by Hellium · May 07, 2019 at 09:39 AM
The quaternion product is not commutative, and the correct order is this one:
CoordinateSystem.transform.rotation = Quaternion.AngleAxis(90, CoordinateSystem.transform.right) * Quaternion.LookRotation(CoordinateSystem.transform.position, Vector3.back) ;
Hey Hellium, thank you for your answer! Unfortunately this doesn´t work either. It still results an unexpected roatation! Is there maybe another way to reach my goal?
I got correct results when I tried in an empty project.
$$anonymous$$y first suggestion was the following, but I think you will get the same results:
void LateUpdate()
{
Vector3 up = CoordinateSystem.transform.position - SphereTransform.position;
Vector3 forward = SphereTransform.forward;
Vector3 right = Vector3.Cross( up, forward );
forward = Vector3.Cross( right, up );
CoordinateSystem.transform.rotation = Quaternion.LookRotation( forward, up );
}
If you don't have a SphereTransform
:
void LateUpdate()
{
Vector3 up = CoordinateSystem.transform.position;
Vector3 forward = Vector3.forward;
Vector3 right = Vector3.Cross( up, forward );
forward = Vector3.Cross( right, up );
CoordinateSystem.transform.rotation = Quaternion.LookRotation( forward, up );
}