Search code examples
c++openglmatrixrotationquaternions

Quaternion to Rotation Matrix, incorrect values using Eigen Library


I am trying to rotate an object by 45 degrees using quaternions about Y-Axis. After Specifying the Quaternion i am trying to get the Rotation Matrix. But the values I see are incorrect

Eigen::Quaterniond q;
q.x() = 0;
q.y() = 1;
q.z() = 0;
q.w() = PI/8;    // Half of the rotation angle must be specified, even IDK why

Eigen::Matrix3d R = q.normalized().toRotationMatrix();
std::cout << "R=" << std::endl << R << std::endl;

OUTPUT :

R=
-0.732    -0   -0.680
     0     1       -0
 0.680     0   -0.732


Since the OpenGL Rotation Matrix along Y-Axis should be :

enter image description here

Therefore my expected output should be :

R=
 0.707     0    0.707
     0     1        0
-0.707     0    0.707

Not only are the values off by a small percent the wrong signs on the values are causing some unexpected rotations. Because of the negative signs my cube is doing a 180 degree turn plus the specified angle. I have broken my head over this for the whole day. Can some one tell me what I am doing wrong ?


Solution

  • The way you initialize your quaternion is incorrect. If you directly initialize the coordinates of quaternion, you should take the definition into account:

    enter image description here

    Alternatively, the Quaternion class in Eigen provides a constructor from an axis-angle representation.

    This code:

    #include <Eigen/Geometry>
    #include <iostream>
    
    void outputAsMatrix(const Eigen::Quaterniond& q)
    {
        std::cout << "R=" << std::endl << q.normalized().toRotationMatrix() << std::endl;
    }
    
    void main()
    {
        auto angle = M_PI / 4;
        auto sinA = std::sin(angle / 2);
        auto cosA = std::cos(angle / 2);
    
        Eigen::Quaterniond q;
        q.x() = 0 * sinA;
        q.y() = 1 * sinA;
        q.z() = 0 * sinA;
        q.w() = cosA;    
    
        outputAsMatrix(q);
        outputAsMatrix(Eigen::Quaterniond{Eigen::AngleAxisd{angle, Eigen::Vector3d{0, 1, 0}}});
    }
    

    outputs what you expect:

    R=
     0.707107         0  0.707107
            0         1         0
    -0.707107         0  0.707107
    R=
     0.707107         0  0.707107
            0         1         0
    -0.707107         0  0.707107