Jump to content
  • Advertisement
Sign in to follow this  
taby

OpenGL Model View Projection matrices

This topic is 1130 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

The following code retrieves the model view and projection matrices based on my camera, and I'm wondering if I have the right matrices in the get_:model_matrix, get_view_matrix and get_projection_matrix functions:

 

#include "matrix_utils.h"


void multiply_4x4_matrices(float (&in_a)[16], float (&in_b)[16], float (&out)[16])
{
 //   matrix layout:
 //    
 //   [0 4  8 12]
 //   [1 5  9 13]
 //   [2 6 10 14]
 //   [3 7 11 15]
    
    out[0] = in_a[0] * in_b[0] + in_a[4] * in_b[1] + in_a[8] * in_b[2] + in_a[12] * in_b[3];
    out[1] = in_a[1] * in_b[0] + in_a[5] * in_b[1] + in_a[9] * in_b[2] + in_a[13] * in_b[3];
    out[2] = in_a[2] * in_b[0] + in_a[6] * in_b[1] + in_a[10] * in_b[2] + in_a[14] * in_b[3];
    out[3] = in_a[3] * in_b[0] + in_a[7] * in_b[1] + in_a[11] * in_b[2] + in_a[15] * in_b[3];
    out[4] = in_a[0] * in_b[4] + in_a[4] * in_b[5] + in_a[8] * in_b[6] + in_a[12] * in_b[7];
    out[5] = in_a[1] * in_b[4] + in_a[5] * in_b[5] + in_a[9] * in_b[6] + in_a[13] * in_b[7];
    out[6] = in_a[2] * in_b[4] + in_a[6] * in_b[5] + in_a[10] * in_b[6] + in_a[14] * in_b[7];
    out[7] = in_a[3] * in_b[4] + in_a[7] * in_b[5] + in_a[11] * in_b[6] + in_a[15] * in_b[7];
    out[8] = in_a[0] * in_b[8] + in_a[4] * in_b[9] + in_a[8] * in_b[10] + in_a[12] * in_b[11];
    out[9] = in_a[1] * in_b[8] + in_a[5] * in_b[9] + in_a[9] * in_b[10] + in_a[13] * in_b[11];
    out[10] = in_a[2] * in_b[8] + in_a[6] * in_b[9] + in_a[10] * in_b[10] + in_a[14] * in_b[11];
    out[11] = in_a[3] * in_b[8] + in_a[7] * in_b[9] + in_a[11] * in_b[10] + in_a[15] * in_b[11];
    out[12] = in_a[0] * in_b[12] + in_a[4] * in_b[13] + in_a[8] * in_b[14] + in_a[12] * in_b[15];
    out[13] = in_a[1] * in_b[12] + in_a[5] * in_b[13] + in_a[9] * in_b[14] + in_a[13] * in_b[15];
    out[14] = in_a[2] * in_b[12] + in_a[6] * in_b[13] + in_a[10] * in_b[14] + in_a[14] * in_b[15];
    out[15] = in_a[3] * in_b[12] + in_a[7] * in_b[13] + in_a[11] * in_b[14] + in_a[15] * in_b[15];
}

/*
void multiply_4x4_matrices(float (&in_a)[16], float (&in_b)[16], float (&out)[16])
{
    for(int i = 0; i < 4; i++)
    {
        for(int j = 0; j < 4; j++)
        {
            out[4*i + j] = 0;
            
            for (int k = 0; k < 4; k++)
                out[4*i + j] += in_a[4*k + j] * in_b[4*i + k];
        }
    }
}
B*/
    

void init_perspective_camera(float fovy, float aspect, float znear, float zfar,
                             float eyex, float eyey, float eyez, float centrex, float centrey,
                             float centrez, float upx, float upy, float upz,
                             float (&model_matrix)[16],
                             float (&view_matrix)[16],
                             float (&projection_matrix)[16],
                             float (&projection_model_view_matrix)[16])
{
    get_model_matrix(eyex, eyey, eyez, centrex, centrey, centrez, upx, upy, upz, model_matrix);
    get_view_matrix(eyex, eyey, eyez, view_matrix);
    get_projection_matrix(fovy, aspect, znear, zfar, projection_matrix);

    float temp_matrix[16];
    multiply_4x4_matrices(model_matrix, view_matrix, temp_matrix);
    multiply_4x4_matrices(projection_matrix, temp_matrix, projection_model_view_matrix);
}





void get_model_matrix(float eyex, float eyey, float eyez, float centrex, float centrey, float centrez, float upx, float upy, float upz, float (&mat)[16])
{
    // https://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml
    // http://www.cs.virginia.edu/~gfx/Courses/1999/intro.fall99.html/lookat.html
    vertex_3 f, up, s, u;
            
    f.x = centrex - eyex;
    f.y = centrey - eyey;
    f.z = centrez - eyez;
    f.normalize();
    
    up.x = upx;
    up.y = upy;
    up.z = upz;
    up.normalize();
    
    s = f.cross(up);
    s.normalize();
    
    u = s.cross(f);
    u.normalize();
    
    mat[0] = s.x;  mat[4] = s.y;  mat[8] = s.z;   mat[12] = 0;
    mat[1] = u.x;  mat[5] = u.y;  mat[9] = u.z;   mat[13] = 0;
    mat[2] = -f.x; mat[6] = -f.y; mat[10] = -f.z; mat[14] = 0;
    mat[3] = 0;    mat[7] = 0;    mat[11] = 0;    mat[15] = 1;
}



void get_view_matrix(float eyex, float eyey, float eyez, float (&in_a)[16])
{
    // https://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml
    // http://www.cs.virginia.edu/~gfx/Courses/1999/intro.fall99.html/lookat.html

    in_a[0] = 1; in_a[4] = 0; in_a[8] = 0;  in_a[12] = -eyex;
    in_a[1] = 0; in_a[5] = 1; in_a[9] = 0;  in_a[13] = -eyey;
    in_a[2] = 0; in_a[6] = 0; in_a[10] = 1; in_a[14] = -eyez;
    in_a[3] = 0; in_a[7] = 0; in_a[11] = 0; in_a[15] = 1;
}

void get_projection_matrix(float fovy, float aspect, float znear, float zfar, float (&in_a)[16])
{
    // https://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml
    const float pi = 4.0f*atanf(1.0);
    
    // Convert fovy to radians, then divide by 2
    float       f = 1.0f / tan(fovy/360.0f*pi);
    
    in_a[0] = f/aspect; in_a[4] = 0; in_a[8] = 0;                              in_a[12] = 0;
    in_a[1] = 0;        in_a[5] = f; in_a[9] = 0;                              in_a[13] = 0;
    in_a[2] = 0;        in_a[6] = 0; in_a[10] = (zfar + znear)/(znear - zfar); in_a[14] = (2.0f*zfar*znear)/(znear - zfar);
    in_a[3] = 0;        in_a[7] = 0; in_a[11] = -1;                            in_a[15] = 0;
}

 

Share this post


Link to post
Share on other sites
Advertisement
Your model matrix should not need the eye to be calculated. A model matrix is the transformation that converts an objects local coordinates to world coordinates. The location of the camera is irrelevant to the model matrix.

Your view matrix should convert world coordinates to camera coordinates. (This is the inverse of the camera's model matrix)

I highly recommend you use a Matrix class instead of passing around float arrays everywhere. Finding an existing matrix library would be even better.

EDIT: It looks like the eye coordinates in your model code refer to the direction that specific object is looking. In that case that looks fine, your view matrix at the moment can only translate the camera. You have no code to rotate your camera, is this intentional? Edited by HappyCoder

Share this post


Link to post
Share on other sites

I rotate the camera around a fixed point (look_at = 0,0,0) and pass that rotation in as the eye position. This is calculated by the C++ code.

 

I think I figured out the right matrices for the right calls (in matrix_utils.cpp). Attached is the full code, including the shaders and a sample STL file to view.

 

 

Share this post


Link to post
Share on other sites

Here matrix functions I use ( left-handed ) :

void CMatrix4::PerspectiveFOV( const float Fov, const float Ratio, const float Near, const float Far )
{
  const float YScale = 1.0f / CMath::Tan( Fov * 0.5f );
  const float XScale = YScale / Ratio;
  const float Coeff = Far / ( Far - Near );
  m44[ 0 ][ 0 ] = XScale; m44[ 0 ][ 1 ] = 0.0f;   m44[ 0 ][ 2 ] = 0.0f;  m44[ 0 ][ 3 ] = 0.0f;
  m44[ 1 ][ 0 ] = 0.0f;   m44[ 1 ][ 1 ] = YScale; m44[ 1 ][ 2 ] = 0.0f;  m44[ 1 ][ 3 ] = 0.0f;
  m44[ 2 ][ 0 ] = 0.0f;   m44[ 2 ][ 1 ] = 0.0f;   m44[ 2 ][ 2 ] = Coeff; m44[ 2 ][ 3 ] = -Near * Coeff;
  m44[ 3 ][ 0 ] = 0.0f;   m44[ 3 ][ 1 ] = 0.0f;   m44[ 3 ][ 2 ] = 1.0f;  m44[ 3 ][ 3 ] = 0.0f;
}

void CMatrix4::LookAt( const CVector3& From, const CVector3& To, const CVector3& Up )
{
  const CVector3 ZAxis = ( To - From ).Normalized();
  const CVector3 XAxis = VectorCross( Up, ZAxis ).Normalized();
  const CVector3 YAxis = VectorCross( ZAxis, XAxis ).Normalized();
  m44[ 0 ][ 0 ] = XAxis.x; m44[ 0 ][ 1 ] = XAxis.y; m44[ 0 ][ 2 ] = XAxis.z; m44[ 0 ][ 3 ] = -VectorDot( XAxis, From );
  m44[ 1 ][ 0 ] = YAxis.x; m44[ 1 ][ 1 ] = YAxis.y; m44[ 1 ][ 2 ] = YAxis.z; m44[ 1 ][ 3 ] = -VectorDot( YAxis, From );
  m44[ 2 ][ 0 ] = ZAxis.x; m44[ 2 ][ 1 ] = ZAxis.y; m44[ 2 ][ 2 ] = ZAxis.z; m44[ 2 ][ 3 ] = -VectorDot( ZAxis, From );
  m44[ 3 ][ 0 ] = 0.0f;    m44[ 3 ][ 1 ] = 0.0f;    m44[ 3 ][ 2 ] = 0.0f;    m44[ 3 ][ 3 ] = 1.0f;
}
Edited by Alundra

Share this post


Link to post
Share on other sites
As has been pointed out, but will say again, model and projection matrices should have nothing to do with the camera. The camera should provide a view matrix. That's it.

An individual object should provide its own world matrix to be moved from model space to world space, and the projection matrix is likely to just be a constant for the lifetime of the game.

All the camera should be concerned with is using its position and orientation to provide a view matrix to take world positions to view space.

Share this post


Link to post
Share on other sites

A camera component has a view matrix and projection matrix.

The projection matrix is updated when the camera properties changes, the view matrix is updated when the camera moves.

You can also keep a ViewProjection matrix in the camera component to share it to avoid depth test issues.

Edited by Alundra

Share this post


Link to post
Share on other sites

Thanks for the information!

 

I moved the look_at + translate code into the view matrix, and the perspective code into the projection matrix. Finally, the camera uses an identity matrix for the model matrix.

Edited by taby

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!