 Looking now at exercise 5.1 transformations, it's rendering the same thing except now it's being transformed. It's being rotated around at z-axis and then translated away from the origin. So the first thing that's different here is in our vertex shader we are now going to have a uniform which is a map 4. It's a 4 by 4 matrix representing a transform and we're going to apply that transform onto our position vector by multiplication. And that is what we are setting to the gl position. In C++ we're going to bring in a new dependency glm which is the open gl mathematics library. It's not officially part of open gl but it's used in conjunction with open gl and glm is going to bring in for us some vector and matrix types so that we can work with vectors and matrices in a convenient form. With this new dependency we're going to create a transform value of 4 by 4 matrix and that is what's going to be set for the value of our uniform and note here it's uniform matrix 4vf. That's what allows us to set a 4 by 4 matrix as the value of the uniform. Now to set up the transform we're combining two prior transforms, translation and rotation. So translation we're creating first with the call to translate and in the call we specify a vector of three floats, the noting translations for the xy and z-axis but the first arg is another 4 by 4 matrix and what the call to translate returns is this matrix multiplied with the translation matrix that is set up as defined by this vector and this is really quite strange to me because it has then the effect of creating a new translation matrix and then applying onto it another transform matrix. In this case calling map 4 with just a single float value of 1 that sets up an identity matrix because we don't want the translation matrix defined by this vector to be transformed we just want it as is. So when the multiplication is done it's the identity matrix times this new translation matrix and that's what we get back. For the rotate function it's a similar deal you pass in a vector of three floats which represents an axis of rotation. The second argument is the angle of rotation around that axis I assume expressed in radians rather than degrees but I'd have to check and the first arg is another 4 by 4 matrix just like with the translate and so we get to return from rotate is not necessarily the rotation matrix defined by these two parameters but that rotation matrix multiplied with transform and again in this case we don't want it modified we want it as is so we're passing in an identity matrix for the first argument. So with our translation and rotation matrix we want to combine them and because we want the rotation performed first and then the translation it's translation times rotation in that order if you flip the order here it would apply the translation and then the rotation and you'd get a different end result. Now because we just want to see the rectangle spin the angle is just the time and of course because time advances at an even rate then this number gets bigger and bigger at a steady rate and so this will make the rectangle rotate at a steady rate. So this is how we can set up the transform matrix but if I comment this out I'll comment here if instead we create our translation matrix and that is what we pass as the first argument to rotate then what rotate will call will effectively be this first matrix multiplied by the rotation matrix and that then will be what transform is assigned when we get down here same result as we had up here. Notice that effectively we're combining our transforms in reverse order the one that we're defining here first of the top translate that is the one that's applied last so it's in backwards order and I still do find it strange that they do the multiplication this way I would expect it to be the other way but nope this is how it works now if we look at 6.1 coordinate systems we are finally doing a 3d projection a rectangle here has been rotated on the x-axis and also the camera has been moved back a little bit so now in a vertex shader we're going to have three separate 4x4 matrix uniforms one for the model transform one for the view transform and one for the projection transform we multiply projection times view times model times the position and again remember that means that effectively the model transform is applied first to the vector then the view transform and lastly the projection transform now it may occur to you that we can combine these matrices together all in one go before starting our shader if they're not going to change from one vertex to the next it's wasted work to compute the same thing over and over again for each vertex down the line when things get more complicated and we start accounting for lighting it's going to be the case that for each vertex we want to compute not just the clip space coordinate but also its view space coordinate and so we're going to keep the projection matrix separate from the view and model matrix so that we can separately multiply a combination of view and model to get the view space coordinate and then apply the projection transform on that to get the gl position the clip space coordinate so in practice it is common to combine view and model together and feed that into the shader but we're generally going to keep the projection separate in this case we're just simplicity and demonstration we're keeping them separate and so we're feeding in three separate matte four uniforms to the vertex shader so to set up these uniforms on the c++ side we're creating a model transform a view transform and a projection transform and then we're setting each one to the respective uniforms what's being demonstrated here is three different ways to do so in the first case when we call uniform matrix 4vf we're using this value pointer function from the glm library and using that to get a pointer to our model matrix alternatively in the second example here we're simply just getting a pointer to the first byte of the matrix the the matrix has a subscript operator defined such that you can access its columns and rows with the subscript operator and then for the third case the shader class that's been defined has a convenience method set matte 4 for sending a matte 4 uniform in this case with the name projection and the value of the projection matrix so what about these matrices well for the model matrix what we're doing is we just want to rotate a little bit on the x-axis so here the rotate function we're specifying the vect3 of the x-axis the angle is negative 55 radians and again we're just plugging in an identity matrix because we don't want this rotation modified we just want to verbatim for the view matrix we want the camera to move backwards otherwise we're not going to see anything because if you recall our rectangle is starting on the xy plane so we need to move back to see it so to move the camera backwards you would add to the z value but of course we're not actually moving the camera there is no camera to move we're instead moving everything in the world in the inverse way so in the view transform we're going to move everything down the negative z-axis we're going to add negative 3 now when things get complicated at least if you want to fully understand it is setting up a projection matrix recall in here perspective which will return the perspective matrix which is defined such the horizontal field of view what the so called foe v fo v y is 45 degree radians it has an aspect ratio for its view plane which is equivalent to the aspect ratio of our output resolution 800 by 600 the near clipping plane is defined at 0.1 and the far clipping plane is defined at 100 and with this information the perspective function can return a projection matrix and this may be confusing because it's different from how I explained projection I explained projection in terms of a defined focal length and a width and height of the viewport but here we're not plugging those values in instead we're plugging in an angle for the field of view the horizontal field of view fo v y fo v and an aspect ratio for the view plane what's happening is from those two pieces of information the perspective function can compute a focal length and a width and height for the view plane looking at this illustration you can see that the rectangular cone of vision is diagrammed as a four-sided pyramid and you see also where our near plane is defined and the far plane creating our frustum and the angle in this pyramid between the top side and the bottom side that is the foe v the horizontal field of view and now we haven't defined any focal length consider that for this cone of vision defined by the field of view the view plane can go anywhere in the pyramid any rectangle bounded by the pyramid that's parallel to the x y plane would be a valid view plane and so in the diagram they are designating effectively the near clipping plane to also be the view plane but understand it would be the same projection if instead our view plane were defined to be the far clipping plane instead for given projection there's not just one possible combination of view plane width and height and focal length as the focal length increases the width and height scale up and as the focal length decreases width and height would effectively scale down we have effectively a whole continuum of options what's usually done however is we just simply select the near clipping plane to be our view plane and so then for our projection matrix we can compute what the focal length is it's simply equal to the length of the near clipping plane and then with the little trig we can compute half the height of the view plane and half its width because the z axis through the view plane forms the right triangle with the top of the pyramid we get the tangent of half the foe v and multiply that by the focal length which again is equal to n the distance to the near clipping plane and that gets us half our height because we also know what the aspect ratio between the width and the height is once we have half the height we can then multiply it by that ratio that aspect ratio to get half the width and so now we have all the information to set up our projection matrix following the formulas I showed you to get from view space to clip space because we now actually want to compute our projection matrix I'll show you exactly how to compute the z of the clipping plane so the problem again is that we want to scale z values from the range of n to f into the new range of negative n to f and we can do that first by adjusting the z values to a range that runs from n to f but oriented on zero so we subtract n from z and then for that adjusted z we want to know proportionally what percentage of the distance from n to f is that so we divide this value by f minus n and we have effectively a percentage which we want to then apply to the full new length that runs from negative n to f whose distance is equivalent to f plus n the last step is to subtract n because before we subtract n we have a value which is in the range from zero to f plus n not negative n to f so if we subtract n now it's in the range of negative n to f now we have the formula for z of clip space but the problem is it involves first subtracting from z then doing a multiplication and then another subtraction but for a projection matrix we're going to need to express this as a single multiplication in addition we can't have that subtraction between the multiplication fortunately if we go through a few steps we can work out an equivalent formula which is z times f plus n divided by f minus n minus two and f over f minus n and so now we have a formula we can plug into our projection matrix so what the projection matrix is going to look like then is x is going to get simply multiplied by n over half the width of the view plane the y values are going to get multiplied by n over half the height of the view plane the z values are going to get multiplied by f plus n over f minus n and then we subtract out two and f over f minus n and lastly the w values is just the z value multiplied by one so the z value verbatim and that's how we get from view space to clip space by applying this projection matrix except again actually i lied to you in the prior video the camera in open gel is presumed to be facing down the negative z axis so all of our z values are in the negative range not positive and so going to clip space first thing is we actually want to flip the sign over z values and then apply the formula so effectively that just means we need to flip the sign of f plus n and then for our w values because the x y z's of clip space are going to be divided by the w to get to n dc normalize device coordinates well we don't want the w values to be negative because then all the signs would flip so we're taking the z value flipping its sign and that is what the projection matrix calculates for w so now for the perspective call that was in our code sample if we actually run the numbers what we should get is a projection matrix that looks like this for the x values it's about 1.8 for the y values it's about 2.4 for the z values we multiply them by about negative one and then subtract 0.2 and for the w values as always we simply multiply the z by negative one so back in our code here i'm going to add this line that will print out the value of the projection matrix and we can verify if this is the case so i'm going to build the code run the program and what do we see well 1.8 checks out so far 2.412 that's good that's what we expected and then negative one negative one and wait a minute this is the third row something's off and then on a fourth row it's not negative one it's negative 0.2 so strange it looks like these two values are swapped to the negative 0.2 and the negative one well what's simply going on here is that for whatever reason when it prints out these four by four matrices what we're seeing are the columns not the rows so this first group of four numbers is the first column the second group of four numbers is the second column the third group of four numbers is the third column and then this is lastly the fourth column so it is correct it is what we expected it's just printed out in column major order rather than row major order like we expected