# Revision history [back]

### OpenGL 4x4 camera matrix

In OpenGL, the camera matrix is a 4x4 matrix. Is the camera matrix in OpenCV a 4x4 matrix as well?

The following is the code needed to make a camera matrix (compatible with OpenGL ES 2.0):

float projection_modelview_mat[16];

init_perspective_camera(y_fov_degrees,
float(m_renderbufferWidth)/float(m_renderbufferHeight),
0.01f, 2.0f,
0, 0, 1, // Camera position.
0, 0, 0, // Look at position.
0, 1, 0, // Up direction vector.
projection_modelview_mat);


... where ...

void get_perspective_matrix(float fovy, float aspect, float znear, float zfar, float (&mat)[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.0*pi);

mat[0] = f/aspect; mat[4] = 0; mat[8] = 0;                              mat[12] = 0;
mat[1] = 0;        mat[5] = f; mat[9] = 0;                              mat[13] = 0;
mat[2] = 0;        mat[6] = 0; mat[10] = (zfar + znear)/(znear - zfar); mat[14] = (2.0f*zfar*znear)/(znear - zfar);
mat[3] = 0;        mat[7] = 0; mat[11] = -1;                            mat[15] = 0;
}

void get_look_at_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
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;

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

float temp[16];
multiply_4x4_matrices(mat, translate, temp);

for(size_t i = 0; i < 16; i++)
mat[i] = temp[i];
}

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];
}
}
}
*/

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 (&projection_modelview_mat)[16])
{
float projection_mat[16];
get_perspective_matrix(fovy, aspect, znear, zfar, projection_mat);

float modelview_mat[16];
get_look_at_matrix(eyex, eyey, eyez, // Eye position.
centrex, centrey, centrez, // Look at position (not direction).
upx, upy, upz,  // Up direction vector.
modelview_mat);

multiply_4x4_matrices(projection_mat, modelview_mat, projection_modelview_mat);
}


### OpenGL 4x4 camera matrix

In OpenGL, the camera matrix is a 4x4 matrix. Is the camera matrix in OpenCV a 4x4 matrix as well?

The following is the code needed to make a camera matrix (compatible with OpenGL ES 2.0):

float projection_modelview_mat[16];

init_perspective_camera(y_fov_degrees,
float(m_renderbufferWidth)/float(m_renderbufferHeight),
float(m_renderbufferWidth)/float(m_renderbufferHeight), // Screen width/height
0.01f, 2.0f,
2.0f, //Near, far distances.
0, 0, 1, // Camera position.
0, 0, 0, // Look at position.
0, 1, 0, // Up direction vector.
projection_modelview_mat);


... where ...

void get_perspective_matrix(float fovy, float aspect, float znear, float zfar, float (&mat)[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.0*pi);

mat[0] = f/aspect; mat[4] = 0; mat[8] = 0;                              mat[12] = 0;
mat[1] = 0;        mat[5] = f; mat[9] = 0;                              mat[13] = 0;
mat[2] = 0;        mat[6] = 0; mat[10] = (zfar + znear)/(znear - zfar); mat[14] = (2.0f*zfar*znear)/(znear - zfar);
mat[3] = 0;        mat[7] = 0; mat[11] = -1;                            mat[15] = 0;
}

void get_look_at_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
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;

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

float temp[16];
multiply_4x4_matrices(mat, translate, temp);

for(size_t i = 0; i < 16; i++)
mat[i] = temp[i];
}

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];
}
}
}
*/

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 (&projection_modelview_mat)[16])
{
float projection_mat[16];
get_perspective_matrix(fovy, aspect, znear, zfar, projection_mat);

float modelview_mat[16];
get_look_at_matrix(eyex, eyey, eyez, // Eye position.
centrex, centrey, centrez, // Look at position (not direction).
upx, upy, upz,  // Up direction vector.
modelview_mat);

multiply_4x4_matrices(projection_mat, modelview_mat, projection_modelview_mat);
}


### OpenGL 4x4 camera matrix

In OpenGL, the camera matrix is a 4x4 matrix. Is the camera matrix in OpenCV a 4x4 matrix as well?

The following is the code needed to make a camera matrix (compatible with OpenGL ES 2.0):

float projection_modelview_mat[16];

init_perspective_camera(y_fov_degrees,
float(m_renderbufferWidth)/float(m_renderbufferHeight), // Screen width/height
float(m_renderbufferWidth)/float(m_renderbufferHeight),
0.01f, 2.0f, //Near, far distances.
0, 0, 1, // Camera position.
0, 0, 0, // Look at position.
0, 1, 0, // Up direction vector.
projection_modelview_mat);


... where ...

void get_perspective_matrix(float fovy, float aspect, float znear, float zfar, float (&mat)[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.0*pi);

mat[0] = f/aspect; mat[4] = 0; mat[8] = 0;                              mat[12] = 0;
mat[1] = 0;        mat[5] = f; mat[9] = 0;                              mat[13] = 0;
mat[2] = 0;        mat[6] = 0; mat[10] = (zfar + znear)/(znear - zfar); mat[14] = (2.0f*zfar*znear)/(znear - zfar);
mat[3] = 0;        mat[7] = 0; mat[11] = -1;                            mat[15] = 0;
}

void get_look_at_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
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;

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

float temp[16];
multiply_4x4_matrices(mat, translate, temp);

for(size_t i = 0; i < 16; i++)
mat[i] = temp[i];
}

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];
}
}
}
*/

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 (&projection_modelview_mat)[16])
{
float projection_mat[16];
get_perspective_matrix(fovy, aspect, znear, zfar, projection_mat);

float modelview_mat[16];
get_look_at_matrix(eyex, eyey, eyez, // Eye position.
centrex, centrey, centrez, // Look at position (not direction).
upx, upy, upz,  // Up direction vector.
modelview_mat);

multiply_4x4_matrices(projection_mat, modelview_mat, projection_modelview_mat);
}


### OpenGL 4x4 camera matrix

In OpenGL, the camera matrix is a 4x4 matrix. Is the camera matrix in OpenCV a 4x4 matrix as well?

The following is the code needed to make a camera matrix (compatible with OpenGL ES 2.0):2.0 and higher):

float projection_modelview_mat[16];

init_perspective_camera(y_fov_degrees,
float(m_renderbufferWidth)/float(m_renderbufferHeight),
0.01f, 2.0f, //Near, far distances.
0, 0, 1, // Camera position.
0, 0, 0, // Look at position.
0, 1, 0, // Up direction vector.
projection_modelview_mat);


... where ...

void get_perspective_matrix(float fovy, float aspect, float znear, float zfar, float (&mat)[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.0*pi);

mat[0] = f/aspect; mat[4] = 0; mat[8] = 0;                              mat[12] = 0;
mat[1] = 0;        mat[5] = f; mat[9] = 0;                              mat[13] = 0;
mat[2] = 0;        mat[6] = 0; mat[10] = (zfar + znear)/(znear - zfar); mat[14] = (2.0f*zfar*znear)/(znear - zfar);
mat[3] = 0;        mat[7] = 0; mat[11] = -1;                            mat[15] = 0;
}

void get_look_at_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
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;

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

float temp[16];
multiply_4x4_matrices(mat, translate, temp);

for(size_t i = 0; i < 16; i++)
mat[i] = temp[i];
}

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];
}
}
}
*/

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 (&projection_modelview_mat)[16])
{
float projection_mat[16];
get_perspective_matrix(fovy, aspect, znear, zfar, projection_mat);

float modelview_mat[16];
get_look_at_matrix(eyex, eyey, eyez, // Eye position.
centrex, centrey, centrez, // Look at position (not direction).
upx, upy, upz,  // Up direction vector.
modelview_mat);

multiply_4x4_matrices(projection_mat, modelview_mat, projection_modelview_mat);
}


### OpenGL 4x4 camera matrix

In OpenGL, the camera matrix is a 4x4 matrix. Is the camera matrix in OpenCV a 4x4 matrix as well?

The following is the code needed to make a very simple camera matrix (compatible with OpenGL ES 2.0 and higher):

float projection_modelview_mat[16];

init_perspective_camera(y_fov_degrees,
float(m_renderbufferWidth)/float(m_renderbufferHeight),
0.01f, 2.0f, //Near, far distances.
0, 0, 1, // Camera position.
0, 0, 0, // Look at position.
0, 1, 0, // Up direction vector.
projection_modelview_mat);


... where ...

void get_perspective_matrix(float fovy, float aspect, float znear, float zfar, float (&mat)[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.0*pi);

mat[0] = f/aspect; mat[4] = 0; mat[8] = 0;                              mat[12] = 0;
mat[1] = 0;        mat[5] = f; mat[9] = 0;                              mat[13] = 0;
mat[2] = 0;        mat[6] = 0; mat[10] = (zfar + znear)/(znear - zfar); mat[14] = (2.0f*zfar*znear)/(znear - zfar);
mat[3] = 0;        mat[7] = 0; mat[11] = -1;                            mat[15] = 0;
}

void get_look_at_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
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;

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

float temp[16];
multiply_4x4_matrices(mat, translate, temp);

for(size_t i = 0; i < 16; i++)
mat[i] = temp[i];
}

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];
}
}
}
*/

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 (&projection_modelview_mat)[16])
{
float projection_mat[16];
get_perspective_matrix(fovy, aspect, znear, zfar, projection_mat);

float modelview_mat[16];
get_look_at_matrix(eyex, eyey, eyez, // Eye position.
centrex, centrey, centrez, // Look at position (not direction).
upx, upy, upz,  // Up direction vector.
modelview_mat);

multiply_4x4_matrices(projection_mat, modelview_mat, projection_modelview_mat);
}


### OpenGL 4x4 camera matrix

In OpenGL, the camera matrix is a 4x4 matrix. Is the camera matrix in OpenCV a 4x4 matrix as well?

The following is the code needed to make a very simple camera matrix (compatible with OpenGL ES 2.0 and higher):

float projection_modelview_mat[16];

init_perspective_camera(y_fov_degrees,
float(m_renderbufferWidth)/float(m_renderbufferHeight),
0.01f, 2.0f, //Near, far distances.
0, 0, 1, // Camera position.
0, 0, 0, // Look at position.
0, 1, 0, // Up direction vector.
projection_modelview_mat);


... where ...

void get_perspective_matrix(float fovy, float aspect, float znear, float zfar, float (&mat)[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.0*pi);

mat[0] = f/aspect; mat[4] = 0; mat[8] = 0;                              mat[12] = 0;
mat[1] = 0;        mat[5] = f; mat[9] = 0;                              mat[13] = 0;
mat[2] = 0;        mat[6] = 0; mat[10] = (zfar + znear)/(znear - zfar); mat[14] = (2.0f*zfar*znear)/(znear - zfar);
mat[3] = 0;        mat[7] = 0; mat[11] = -1;                            mat[15] = 0;
}

void get_look_at_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
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;

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

float temp[16];
multiply_4x4_matrices(mat, translate, temp);

for(size_t i = 0; i < 16; i++)
mat[i] = temp[i];
}

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];
}
}
}
*/

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 (&projection_modelview_mat)[16])
{
float projection_mat[16];
get_perspective_matrix(fovy, aspect, znear, zfar, projection_mat);

float modelview_mat[16];
get_look_at_matrix(eyex, eyey, eyez, // Eye position.
centrex, centrey, centrez, // Look at position (not direction).
upx, upy, upz,  // Up direction vector.
modelview_mat);

multiply_4x4_matrices(projection_mat, modelview_mat, projection_modelview_mat);
}


### OpenGL 4x4 camera matrix, OpenCV ?x? camera matrix

In OpenGL, the camera matrix is a 4x4 matrix. Is the camera matrix in OpenCV a 4x4 matrix as well?

The following is the code needed to make a very simple camera matrix (compatible with OpenGL ES 2.0 and higher):

float projection_modelview_mat[16];

init_perspective_camera(y_fov_degrees,
float(m_renderbufferWidth)/float(m_renderbufferHeight),
0.01f, 2.0f, //Near, far distances.
0, 0, 1, // Camera position.
0, 0, 0, // Look at position.
0, 1, 0, // Up direction vector.
projection_modelview_mat);


... where ...

void get_perspective_matrix(float fovy, float aspect, float znear, float zfar, float (&mat)[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.0*pi);

mat[0] = f/aspect; mat[4] = 0; mat[8] = 0;                              mat[12] = 0;
mat[1] = 0;        mat[5] = f; mat[9] = 0;                              mat[13] = 0;
mat[2] = 0;        mat[6] = 0; mat[10] = (zfar + znear)/(znear - zfar); mat[14] = (2.0f*zfar*znear)/(znear - zfar);
mat[3] = 0;        mat[7] = 0; mat[11] = -1;                            mat[15] = 0;
}

void get_look_at_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
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;

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

float temp[16];
multiply_4x4_matrices(mat, translate, temp);

for(size_t i = 0; i < 16; i++)
mat[i] = temp[i];
}

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];
}
}
}
*/

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 (&projection_modelview_mat)[16])
{
float projection_mat[16];
get_perspective_matrix(fovy, aspect, znear, zfar, projection_mat);

float modelview_mat[16];
get_look_at_matrix(eyex, eyey, eyez, // Eye position.
centrex, centrey, centrez, // Look at position (not direction).
upx, upy, upz,  // Up direction vector.
modelview_mat);

multiply_4x4_matrices(projection_mat, modelview_mat, projection_modelview_mat);
}


... and the vertex and fragment shaders are:

// vertex shader
attribute vec3 position;
attribute vec2 tex_coord;
uniform mat4 mvp_matrix;
varying vec2 frag_tex_coord;

void main()
{
frag_tex_coord = tex_coord;
gl_Position = mvp_matrix*vec4(position, 1);
}

uniform sampler2D tex;
varying mediump vec2 frag_tex_coord;

void main()
{
gl_FragColor = texture2D(tex, frag_tex_coord);
}


### OpenGL 4x4 camera matrix, OpenCV ?x? camera matrix

In OpenGL, the camera matrix is a 4x4 matrix. Is the camera matrix in OpenCV a 4x4 matrix as well?

The following is the code needed to make a very simple camera matrix (compatible with OpenGL ES 2.0 and higher):

float projection_modelview_mat[16];

init_perspective_camera(y_fov_degrees,
float(m_renderbufferWidth)/float(m_renderbufferHeight),
0.01f, 2.0f, //Near, // Z near, far distances.
0, 0, 1, // Camera position.
0, 0, 0, // Look at position.
0, 1, 0, // Up direction vector.
projection_modelview_mat);


... where ...

void get_perspective_matrix(float fovy, float aspect, float znear, float zfar, float (&mat)[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.0*pi);

mat[0] = f/aspect; mat[4] = 0; mat[8] = 0;                              mat[12] = 0;
mat[1] = 0;        mat[5] = f; mat[9] = 0;                              mat[13] = 0;
mat[2] = 0;        mat[6] = 0; mat[10] = (zfar + znear)/(znear - zfar); mat[14] = (2.0f*zfar*znear)/(znear - zfar);
mat[3] = 0;        mat[7] = 0; mat[11] = -1;                            mat[15] = 0;
}

void get_look_at_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
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;

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

float temp[16];
multiply_4x4_matrices(mat, translate, temp);

for(size_t i = 0; i < 16; i++)
mat[i] = temp[i];
}

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];
}
}
}
*/

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 (&projection_modelview_mat)[16])
{
float projection_mat[16];
get_perspective_matrix(fovy, aspect, znear, zfar, projection_mat);

float modelview_mat[16];
get_look_at_matrix(eyex, eyey, eyez, // Eye position.
centrex, centrey, centrez, // Look at position (not direction).
upx, upy, upz,  // Up direction vector.
modelview_mat);

multiply_4x4_matrices(projection_mat, modelview_mat, projection_modelview_mat);
}


... and the vertex and fragment shaders are:

// vertex shader
attribute vec3 position;
attribute vec2 tex_coord;
uniform mat4 mvp_matrix;
varying vec2 frag_tex_coord;

void main()
{
frag_tex_coord = tex_coord;
gl_Position = mvp_matrix*vec4(position, 1);
}

uniform sampler2D tex;
varying mediump vec2 frag_tex_coord;

void main()
{
gl_FragColor = texture2D(tex, frag_tex_coord);
}


### OpenGL 4x4 camera matrix, OpenCV ?x? camera matrix

In OpenGL, the camera matrix is a 4x4 matrix. Is the camera matrix in OpenCV a 4x4 matrix as well?

The following is the code needed to make a very simple camera matrix (compatible with OpenGL ES 2.0 and higher):higher, see the camera matrix applied in the code https://github.com/sjhalayka/blind_poker):

float projection_modelview_mat[16];

init_perspective_camera(y_fov_degrees,
float(m_renderbufferWidth)/float(m_renderbufferHeight),
0.01f, 2.0f, // Z near, far distances.
0, 0, 1, // Camera position.
0, 0, 0, // Look at position.
0, 1, 0, // Up direction vector.
projection_modelview_mat);


... where ...

void get_perspective_matrix(float fovy, float aspect, float znear, float zfar, float (&mat)[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.0*pi);

mat[0] = f/aspect; mat[4] = 0; mat[8] = 0;                              mat[12] = 0;
mat[1] = 0;        mat[5] = f; mat[9] = 0;                              mat[13] = 0;
mat[2] = 0;        mat[6] = 0; mat[10] = (zfar + znear)/(znear - zfar); mat[14] = (2.0f*zfar*znear)/(znear - zfar);
mat[3] = 0;        mat[7] = 0; mat[11] = -1;                            mat[15] = 0;
}

void get_look_at_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
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;

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

float temp[16];
multiply_4x4_matrices(mat, translate, temp);

for(size_t i = 0; i < 16; i++)
mat[i] = temp[i];
}

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];
}
}
}
*/

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 (&projection_modelview_mat)[16])
{
float projection_mat[16];
get_perspective_matrix(fovy, aspect, znear, zfar, projection_mat);

float modelview_mat[16];
get_look_at_matrix(eyex, eyey, eyez, // Eye position.
centrex, centrey, centrez, // Look at position (not direction).
upx, upy, upz,  // Up direction vector.
modelview_mat);

multiply_4x4_matrices(projection_mat, modelview_mat, projection_modelview_mat);
}


... and the vertex and fragment shaders are:

// vertex shader
attribute vec3 position;
attribute vec2 tex_coord;
uniform mat4 mvp_matrix;
varying vec2 frag_tex_coord;

void main()
{
frag_tex_coord = tex_coord;
gl_Position = mvp_matrix*vec4(position, 1);
}

uniform sampler2D tex;
varying mediump vec2 frag_tex_coord;

void main()
{
gl_FragColor = texture2D(tex, frag_tex_coord);
}


### OpenGL 4x4 camera matrix, OpenCV ?x? camera matrix

In OpenGL, the camera matrix is a 4x4 matrix. Is the camera matrix in OpenCV a 4x4 matrix as well?

The following is the code needed to make a very simple camera matrix (compatible matrix. Compatible with OpenGL ES 2.0 and higher, see higher. See the camera matrix applied in the full code https://github.com/sjhalayka/blind_poker):https://github.com/sjhalayka/blind_poker:

float projection_modelview_mat[16];

init_perspective_camera(y_fov_degrees,
float(m_renderbufferWidth)/float(m_renderbufferHeight),
0.01f, 2.0f, // Z near, far distances.
0, 0, 1, // Camera position.
0, 0, 0, // Look at position.
0, 1, 0, // Up direction vector.
projection_modelview_mat);


... where ...

void get_perspective_matrix(float fovy, float aspect, float znear, float zfar, float (&mat)[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.0*pi);

mat[0] = f/aspect; mat[4] = 0; mat[8] = 0;                              mat[12] = 0;
mat[1] = 0;        mat[5] = f; mat[9] = 0;                              mat[13] = 0;
mat[2] = 0;        mat[6] = 0; mat[10] = (zfar + znear)/(znear - zfar); mat[14] = (2.0f*zfar*znear)/(znear - zfar);
mat[3] = 0;        mat[7] = 0; mat[11] = -1;                            mat[15] = 0;
}

void get_look_at_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
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;

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

float temp[16];
multiply_4x4_matrices(mat, translate, temp);

for(size_t i = 0; i < 16; i++)
mat[i] = temp[i];
}

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];
}
}
}
*/

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 (&projection_modelview_mat)[16])
{
float projection_mat[16];
get_perspective_matrix(fovy, aspect, znear, zfar, projection_mat);

float modelview_mat[16];
get_look_at_matrix(eyex, eyey, eyez, // Eye position.
centrex, centrey, centrez, // Look at position (not direction).
upx, upy, upz,  // Up direction vector.
modelview_mat);

multiply_4x4_matrices(projection_mat, modelview_mat, projection_modelview_mat);
}


... and the vertex and fragment shaders are:

// vertex shader
attribute vec3 position;
attribute vec2 tex_coord;
uniform mat4 mvp_matrix;
varying vec2 frag_tex_coord;

void main()
{
frag_tex_coord = tex_coord;
gl_Position = mvp_matrix*vec4(position, 1);
}

uniform sampler2D tex;
varying mediump vec2 frag_tex_coord;

void main()
{
gl_FragColor = texture2D(tex, frag_tex_coord);
}


### OpenGL 4x4 camera matrix, OpenCV ?x? camera matrix

In OpenGL, the camera matrix is a 4x4 matrix. Is the camera matrix in OpenCV a 4x4 matrix as well?

The following is the code needed to make a very simple camera matrix. Compatible with OpenGL ES 2.0 and higher. See the camera matrix applied in the full code https://github.com/sjhalayka/blind_poker:

float projection_modelview_mat[16];

init_perspective_camera(y_fov_degrees,
float(m_renderbufferWidth)/float(m_renderbufferHeight),
static_cast<float>(screen_width)/static_cast<float>(screen_height),
0.01f, 2.0f, // Z near, far distances.
0, 0, 1, // Camera position.
0, 0, 0, // Look at position.
0, 1, 0, // Up direction vector.
projection_modelview_mat);


... where ...

void get_perspective_matrix(float fovy, float aspect, float znear, float zfar, float (&mat)[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.0*pi);

mat[0] = f/aspect; mat[4] = 0; mat[8] = 0;                              mat[12] = 0;
mat[1] = 0;        mat[5] = f; mat[9] = 0;                              mat[13] = 0;
mat[2] = 0;        mat[6] = 0; mat[10] = (zfar + znear)/(znear - zfar); mat[14] = (2.0f*zfar*znear)/(znear - zfar);
mat[3] = 0;        mat[7] = 0; mat[11] = -1;                            mat[15] = 0;
}

void get_look_at_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
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;

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

float temp[16];
multiply_4x4_matrices(mat, translate, temp);

for(size_t i = 0; i < 16; i++)
mat[i] = temp[i];
}

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];
}
}
}
*/

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 (&projection_modelview_mat)[16])
{
float projection_mat[16];
get_perspective_matrix(fovy, aspect, znear, zfar, projection_mat);

float modelview_mat[16];
get_look_at_matrix(eyex, eyey, eyez, // Eye position.
centrex, centrey, centrez, // Look at position (not direction).
upx, upy, upz,  // Up direction vector.
modelview_mat);

multiply_4x4_matrices(projection_mat, modelview_mat, projection_modelview_mat);
}


... and the vertex and fragment shaders are:

// vertex shader
attribute vec3 position;
attribute vec2 tex_coord;
uniform mat4 mvp_matrix;
varying vec2 frag_tex_coord;

void main()
{
frag_tex_coord = tex_coord;
gl_Position = mvp_matrix*vec4(position, 1);
}