Search code examples
vectorquaternions

How do I convert a Direction Vector to a Quaternion


Let's say I have a Vector v which points into a certain direction. My question is straightforward: How do I construct a Quaternion out of this direction Vector so an object would look into the direction of the vector? I suppose I need the forward Vector of the Object to point into the same direction as the direction Vector. How would I do that using Quaternions? Or am I supposed to do something completely different? Thanks in advance.


Solution

  • I have found the answer:

    Quaternion Quaternion::LookAt(Vector3f direction, Vector3f forward, Vector3f up) {
    
            Quaternion rot1 = RotationBetweenVectors(forward, direction);
            Vector3f right = Vector3f::CrossProduct(direction, up);
            up = Vector3f::CrossProduct(right, direction);
            Vector3f realUp(0, 1, 0);
            Vector3f newUp = rot1 * realUp;
            Quaternion rot2 = RotationBetweenVectors(newUp, up);
            Quaternion res = rot2 * rot1;
    
            return Quaternion(res.x, res.y, res.z, res.w);
    
        }
    
        Quaternion Quaternion::RotationBetweenVectors(Vector3f forward, Vector3f direction) {
            forward = Vector3f::Normalize(forward);
            direction = Vector3f::Normalize(direction);
    
            float cosTheta = Vector3f::DotProduct(forward, direction);
            Vector3f axis;
    
            if (cosTheta < -1 + 0.001f) {
                // special case when vectors in opposite directions:
                // there is no "ideal" rotation axis
                // So guess one; any will do as long as it's perpendicular to start
                axis = Vector3f::CrossProduct(Vector3f(0.0f, 0.0f, 1.0f), forward);
    
                if (axis.Length() * axis.Length() < 0.01)
                    axis = Vector3f::CrossProduct(Vector3f(1.0f, 0.0f, 0.0f), forward);
    
                axis = Vector3f::Normalize(axis);
                return Quaternion(axis.x, axis.y, axis.z, DegreesToRadians(0));
            }
    
            axis = Vector3f::CrossProduct(forward, direction);
            float s = sqrt((1 + cosTheta) * 2);
            float invs = 1 / s;
    
            return Quaternion(
                axis.x * invs,
                axis.y * invs,
                axis.z * invs,
                s * 0.5f
            );
        }