Rotation according to gravity

I am trying to make my transform always have its bottom part point to where the gravity vector is pointing (like doing transform.up = -gravity) and to do so I would like it to rotate around its Z axis until it is in the correct position.

I don’t have much experience with quaternions, so any idea would be appreciated even if it’s just a theoretical one.

If I understand your question, you want to rotate an object around it’s local Z axis to align it’s local -Y axis with your gravity vector. The problem with LookAt() is that it reverses the priorities of the Z and Y axis. It rotates around the local Y axis to align the Z axis with a vector.

We can avoid the problem of axis priorities by giving LookAt() two vectors that are already perpendicular. One of these will be your transform.forward vector. The other needs to be based on the gravity vector, but we need to constrain it to be perpendicular to transform.forward.

So how do we do it?

  1. Project the gravity vector onto transform.forward. This gives you the component of the gravity vector that is acting along the object’s local z axis.
  2. Subtract that vector from the original gravity vector. This leaves you with the component of the gravity vector that is acting in the object’s local x/y plane.
  3. Make your object LookAt it’s own transform.forward, specifying the calculated vector as the up direction.

Here is the code:

Vector3 gravityAlongLocalZAxis = transform.forward * Vector3.Dot(gravity, transform.forward);
Vector3 gravityInLocalXYPlane = gravity - gravityAlongLocalZAxis;
transform.LookAt(transform.forward, -gravityInLocalXYPlane);

If you want to learn more about how I did the calculation, check out the following links:

Vector Projection

Vector Addition & Subtraction