vendredi 27 décembre 2013

OpenGL with Eigen: re-implementing perspective and lookat

I am looking at OpenGL 3.3 and gluperspective and glulookat are deprecated in core 3.3

You can find them in GLM (as functions perspective and lookat)
but I am using Eigen, and after a long reflexion with myself, I decided to stay with Eigen.

I made a version of perspective and lookat for Eigen:

#include "Eigen/Core"

template<class T>
Eigen::Matrix<T,4,4> perspective
(
    double fovy,
    double aspect,
    double zNear,
    double zFar
)
{
    typedef Eigen::Matrix<T,4,4> Matrix4;

    assert(aspect > 0);
    assert(zFar > zNear);

    double radf = Math::degToRad(fovy);

    double tanHalfFovy = tan(radf / 2.0);
    Matrix4 res = Matrix4::Zero();
    res(0,0) = 1.0 / (aspect * tanHalfFovy);
    res(1,1) = 1.0 / (tanHalfFovy);
    res(2,2) = - (zFar + zNear) / (zFar - zNear);
    res(3,2) = - 1.0;
    res(2,3) = - (2.0 * zFar * zNear) / (zFar - zNear);
    return res;
}

template<class T>
Eigen::Matrix<T,4,4> lookAt
(
    Eigen::Matrix<T,3,1> const & eye,
    Eigen::Matrix<T,3,1> const & center,
    Eigen::Matrix<T,3,1> const & up
)
{
    typedef Eigen::Matrix<T,4,4> Matrix4;
    typedef Eigen::Matrix<T,3,1> Vector3;

    Vector3 f = (center - eye).normalized();
    Vector3 u = up.normalized();
    Vector3 s = f.cross(u).normalized();
    u = s.cross(f);

    Matrix4 res;
    res <<  s.x(),s.y(),s.z(),-s.dot(eye),
            u.x(),u.y(),u.z(),-u.dot(eye),
            -f.x(),-f.y(),-f.z(),f.dot(eye),
            0,0,0,1;

    return res;
}

and easy to use:


...

typedef Eigen::Matrix4f Matrix4;
typedef Eigen::Vector3f Vector3;

float fovy = ...;
float ratio = ...;
float near_plan = ...;
float far_plan = ...;

Matrix4 projectionMatrix = perspective<Matrix4::Scalar>(
    fovy,
    ratio,
    near_plan,
    far_plan
);

Vector3 eye, center, eyeUp;
... init code ...

Matrix4 cameraMatrix = lookAt( eye, center, eyeUp );


if you are using OpenGL 2.1 then you can use them as:

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glLoadMatrixf( projectionMatrix.data() );

and

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glLoadMatrixf(cameraMatrix.data());


Hope it will be useful for you as well, let me know if it was.
:-)