The projection matrix describes the mapping from three-dimensional points of the scene to two-dimensional points of the viewport. The projection matrix is converted from view space to clip space. Clip Space Coordinates Homogeneous coordinates . The coordinates in the clip space are converted to normalized device coordinates (NDC) in the range (-1, -1, -1) to (1, 1, 1) by dividing the clip coordinates by the w component.
In a perspective projection, the projection matrix describes the mapping from three-dimensional points in the world, as they are visible from a pinhole camera, to the 2D points of the viewport. The coordinates of the eye space in the truncation of the camera (truncated pyramid) are displayed in a cube (coordinates of the normalized device).

If you want to know the angles of the truncation camera in the gaze, you need to convert the angles of the normalized space of the device (-1, -1, -1), ..., (1, 1, 1) using the matrix of the back projections . To get the Cartesian coordinates , the components X, Y and Z of the result must be divided by the W (4th) component of the result.
glMatrix is a library that provides matrix operations and data types such as mat4 and vec4 :
projection = mat4.clone( VRFrameData.leftProjectionMatrix ); inverse_prj = mat4.create(); mat4.invert( inverse_prj, projection ); pt_ndc = [-1, -1, -1]; v4_ndc = vec4.fromValues( pt_ndc[0], pt_ndc[1], pt_ndc[2], 1 ); v4_view = vec4.create(); vec4.transformMat4( v4_view, v4_ndc, inverse_prj ); pt_view = [v4_view[0]/v4_view[3], v4_view[1]/v4_view[3], v4_view[2]/v4_view[3]];
Coordinates of the type of transformation into world coordinates can be made using the matrix of the reverse lookup .
view = mat4.clone( VRFrameData.leftViewMatrix ); inverse_view = mat4.create(); mat4.invert( inverse_view, view ); v3_view = vec3.clone( pt_view ); v3_world = vec3.create(); mat4.transformMat4( v3_world, v3_view, inverse_view );
Note that the left and right projection matrices are not symmetrical. This means that the line of sight is not in the center of the truncated cone, and they are different for the left and right eyes.
In addition, the matrix of perspective projections is as follows:
r = right, l = left, b = bottom, t = top, n = near, f = far 2*n/(rl) 0 0 0 0 2*n/(tb) 0 0 (r+l)/(rl) (t+b)/(tb) -(f+n)/(fn) -1 0 0 -2*f*n/(fn) 0
Where:
a = w / h ta = tan( fov_y / 2 ); 2 * n / (rl) = 1 / (ta * a) 2 * n / (tb) = 1 / ta
If the projection is symmetrical , where the line of sight is in the center of the viewing port and the field of view is not shifted, then the matrix can be simplified:
1/(ta*a) 0 0 0 0 1/ta 0 0 0 0 -(f+n)/(fn) -1 0 0 -2*f*n/(fn) 0
This means that the field of view can be calculated as follows:
fov_y = Math.atan( 1/prjMat[5] ) * 2; // prjMat[5] is prjMat[1][1]
and aspect ratio:
aspect = prjMat[5] / prjMat[0];
Calculation of the field of view field also works if the projection matrix is symmetrical horizontally. This means that if -bottom is top . For projection matrices of two eyes, this should be so.
Further
z_ndc = 2.0 * depth - 1.0; z_eye = 2.0 * n * f / (f + n - z_ndc * (f - n));
substituting the fields of the projection matrix, it is:
A = prj_mat[2][2] B = prj_mat[3][2] z_eye = B / (A + z_ndc)
This means that the distance to the nearest plane and to the far plane can be calculated:
A = prj_mat[10]; // prj_mat[10] is prj_mat[2][2] B = prj_mat[14]; // prj_mat[14] is prj_mat[3][2] near = - B / (A - 1); far = - B / (A + 1);