I've been trying to construct a perspective projection matrix myself and finding it extremely difficult.

I realize that a perspective projection matrix is by default a frustum in OpenGL 3.3+ that is transformed into a unit cube and I need to divide x , y and z by -z too project x y z into -z then I need to divide by w after I've done some equations on I believe these values top , bottom , left , right , zFar and ZNear however I don't exactly know what those equations are and I'm not exactly savy in all the maths required to do this persay also I've read that this is not the full perspective projection matrix and I need some kind of clipping planes?

GLfloat x = 1.0-z;
GLfloat y = 1.0-z;
GLfloat z = 1.0-z;

GLfloat projm[16] = {0};

//crazy equations that I don't know with values
//that I don't know where to place exactly:
//top , bottom , left , right , zFar and ZNear 

x / w;
y / w;
z / w;

projm[] ={x, 0.0 , 0.0, 1.0,
          0.0, y , 0.0, 1.0,
          0.0, 0.0, z,  1.0};

I'm very aware of GLM , I'd prefer too do it myself for learning , curosity and potential benefits please be gentle.


3 Answers 3


OpenGL already handles the division by W part, you don't need to do anything about that.

So, this is what a perspective projection matrix should look like:


FOV is the vertical angle of the frustum.

Near and far are the distance from the camera to the cutting planes. Nothing gets rendered beyond those. Make sure fo set the near plane to a small value, but not too small, or you will lose precision because of how the depth buffer works.

Aspect is the aspect ration of the window (windowWidth/windowHeight)

The best explanation about how all this works I found was on this website (yes it's about webgl, but it can be read without knowledge of it)http://webglfundamentals.org/webgl/lessons/webgl-3d-perspective.html

  • \$\begingroup\$ I'll go through all this and hope I find some use out of it : ) @Bálint \$\endgroup\$ Commented Apr 23, 2016 at 17:33
  • \$\begingroup\$ Bálint What is : var f = Math.tan(Math.PI * 0.5 - 0.5 * fieldOfViewInRadians); for? Is that too compute the angle of some part of the cone or field of view?. \$\endgroup\$ Commented Apr 23, 2016 at 20:53
  • \$\begingroup\$ @DominicHughes I'm not actually sure, simply put fieldOfView / 2 instead of that \$\endgroup\$
    – Bálint
    Commented Apr 23, 2016 at 21:02
  • 1
    \$\begingroup\$ I thought it was divide too be honest lol wasn't shore though, sorry for my variable naming errors : <. GLfloat x = screenWidth / screenHeight * tan(FOV / 2); Is that much better? : D \$\endgroup\$ Commented Apr 23, 2016 at 21:10
  • 1
    \$\begingroup\$ @DominicHughes -far + near / far - near this is wrong, you divide near with far, thne you add a negative far and subtract near from it, use parentheses \$\endgroup\$
    – Bálint
    Commented Apr 24, 2016 at 7:02


Note the perspective projection matrix is a transform like any other. The difference compared to orthogonal matrix is that the xy-displacement is dependent on the z coordinate. If you figure out what a perspective is and have a good idea about what shearing transforms do perspective projection matrices are no magic at all. Good luck!

  • \$\begingroup\$ That doesn't even come close too answering what I asked for but thanks for your mellow helpful tip. Obviously I wouldn't be here if those links were working for me in my honest opinion they are full of abstractions that are hardly explained and they expect way too much infact all tutorials should be written for noobs every time in my opinion. @Andreas \$\endgroup\$ Commented Apr 23, 2016 at 9:32
  • \$\begingroup\$ I'll consider making a more "physical" explaination. How familiar are you with matrices? Do you know what happens when multiplying a matrix with a vector? \$\endgroup\$
    – Andreas
    Commented Apr 23, 2016 at 10:11

I eventually, figured out a way to do this here's what I've written about this subject on my youtube channel:

Basically the idea with perspective projection

your clipping and or attaching the znear and or zfar plane on the x (width), y (height) and z (depth) axis with the clipping (perspective boundary) and perspective volume (perspective shape which is kinda like a 3D weird cube with a pyramid at the top) which is helped by the distance between zfar and znear planes but the equations are weird and confusing.

  • translation = positioning
  • transforms = various kinds of visual transformations (rotation,size,etc)

First lets understand the matrix :

var matrix = [
xx, xy, xz, xw,
yx, yy, yz, yw,
zx , zy, zz, zw,
wx, wy, wz, ww
  • x(anything) is for width and any other transform including projection.

  • y(anything) is for height and any other transform including projection.

  • z(anything) is for depth (not perspective) and any other
    transform including projection.

  • w is for perspective (growing and shrinking geometry) and any other transforms including projection

any combination of xyzw are just obvious xy will work on width of height or yz will work on the depth of height, I think, etc.

Now depending on if it's in row or column order. will determine which w's are used for translation in this case for WebGL row is

var matrix = [
xx, xy, xz, xw,
yx, yy, yz, yw,
zx , zy, zz, zw,
(wx, wy, wz, ww)

if it was column then it would be

var matrix = [
xx, xy, xz, (xw,
yx, yy, yz, yw,
zx , zy, zz, zw,
wx, wy, wz, ww)

To create the actual plane you use variables

float top = 1.0, 
bottom = -1.0
left = -1.0
right = 1.0

These are all the variable declarations:

        var top = 1.0; // top of cube
        var bottom = -1.0; // bottom of cube
        var zfar = -2.0; // distance of furthest boundary of perspective shape
        var znear = 4.0; // distance of closest boundary of perspective shape
        var width = 1.0; // width of cube
        var height = 1.0; // height of cube
        var left = -1.0; // left side of cube
        var right = 1.0; // right side of cube
        var zoomfactor = 2.0; // amount zoomed in and out

The cube formation is a consequence of creating a plane with these equations (I think) and the pyramid part and perspective projection is all in these equations also zfar and znear equations are here too:

var PersMat = [
    //ROW 1
    znear / width / 4.0 * zoomfactor, 0.0, left+right/width/2, 0.0,
    //ROW 2
    0.0, znear / height / 4.0 * zoomfactor  , top+bottom/height/2, 0.0,
    //ROW 3
    0.0, 0.0, - (zfar + znear) / (zfar - znear), 2*zfar*znear / zfar - znear,
    // ROW 4
    0.0, 0.0, -1.0, 0.0

Hope that helps.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .