How on Earth one converts 3x3 matrix to quaternion?

Yes, eigen decomposition is something quite complex. It’s sad that 3b1b’s Linear algebra series only mentions what eigenvalues / eigenvectors are, but not how to calculate them :slight_smile: The Wikipedia article mentioned that a 3x3 rotation matrix has at least one eigenvalue with the value 1, the others are actually complex numbers (because the trace / square root is negative). The article also used the example of using the usual trace of the matrix and just states that if it’s zero it doesn’t work -.-

The actual vector is essentially similar to the crossproduct. So the x component is always the result of y and z, y is the result of x and z and finally z is the result of x and y. Though choosing which components seems to be a bit tricky. I found this post on Unity Answers / Discussions which seems to have a working version of LookRotation (which starts by constructing the 3x3 matrix).

I took your example direction and made this test case with the method I found on Discussions:

Test Example

using UnityEngine;

public class QuaternionTest : MonoBehaviour
{
    void Start()
    {
        var target = new Vector3(2f, 8f, 2f);
        var fwd = target.normalized;
        var up = Vector3.up;
        var rgt = Vector3.Cross(up, fwd);
        up = Vector3.Cross(fwd, rgt);

        var q1 = Quaternion.LookRotation(fwd, up);
        Debug.Log(q1.ToString("f8"));

        var q2 = QuaternionLookRotation(fwd, up);
        Debug.Log(q2.ToString("f8"));

    }

    private static Quaternion QuaternionLookRotation(Vector3 forward, Vector3 up)
    {
        forward.Normalize();

        Vector3 vector = Vector3.Normalize(forward);
        Vector3 vector2 = Vector3.Normalize(Vector3.Cross(up, vector));
        Vector3 vector3 = Vector3.Cross(vector, vector2);
        var m00 = vector2.x;
        var m01 = vector2.y;
        var m02 = vector2.z;
        var m10 = vector3.x;
        var m11 = vector3.y;
        var m12 = vector3.z;
        var m20 = vector.x;
        var m21 = vector.y;
        var m22 = vector.z;


        float num8 = (m00 + m11) + m22;
        var quaternion = new Quaternion();
        if (num8 > 0f)
        {
            var num = (float)System.Math.Sqrt(num8 + 1f);
            quaternion.w = num * 0.5f;
            num = 0.5f / num;
            quaternion.x = (m12 - m21) * num;
            quaternion.y = (m20 - m02) * num;
            quaternion.z = (m01 - m10) * num;
            return quaternion;
        }
        if ((m00 >= m11) && (m00 >= m22))
        {
            var num7 = (float)System.Math.Sqrt(((1f + m00) - m11) - m22);
            var num4 = 0.5f / num7;
            quaternion.x = 0.5f * num7;
            quaternion.y = (m01 + m10) * num4;
            quaternion.z = (m02 + m20) * num4;
            quaternion.w = (m12 - m21) * num4;
            return quaternion;
        }
        if (m11 > m22)
        {
            var num6 = (float)System.Math.Sqrt(((1f + m11) - m00) - m22);
            var num3 = 0.5f / num6;
            quaternion.x = (m10 + m01) * num3;
            quaternion.y = 0.5f * num6;
            quaternion.z = (m21 + m12) * num3;
            quaternion.w = (m20 - m02) * num3;
            return quaternion;
        }
        var num5 = (float)System.Math.Sqrt(((1f + m22) - m00) - m11);
        var num2 = 0.5f / num5;
        quaternion.x = (m20 + m02) * num2;
        quaternion.y = (m21 + m12) * num2;
        quaternion.z = 0.5f * num5;
        quaternion.w = (m01 - m10) * num2;
        return quaternion;
    }
}

This is the result:
9922137--1435146--upload_2024-7-3_22-33-53.png

So it seems to generate the same result. Now we should test this with random directions to see if it actually works out in all (most) cases.