all right everyone we just learned in previous lectures that we use matrices to encode these ideas of translating the vectors rotating vectors scaling vectors so by multiplying these matrices by our original vector we just go there we change the x's y and z's by those multiplication and we scale rotate translate we perform those transformations right those are fine transformations very well but the thing is i told you that we can use also a matrix to represent that projection phase remember where we have all these objects in the world space we want to go and project everything into this 2d screen into our image space into our screen space i am claiming that we can use a matrix as well we are going to find all the correct values to populate this projection matrix so we go we multiply by every vector that we have achieving perspective projection well it doesn't have to be perspective you can have different matrices for different things you could have a matrix that performs an orthographic type of projection so we have different values here that we have to populate you have perspective projection of course this is the one we're going to learn but if you have a different type of projection that you want to achieve if you have the correct values you can just go populate and achieve that projection by creating a matrix for that thing so we are going to look at perspective projection right this is the one that we're implementing right now but i'm going to tell you something perspective projection matrix there are several different goals there are several objectives that we can achieve by using a perspective projection matrix so far the perspective that we have been achieving is very is what we call weak projection which it doesn't take into account anything else other than perspective divide we need to take into account and a projection matrix is responsible for three important things so there are three steps that the projection matrix is going to help us achieve the first one is accounting for the aspect ratio of our monitor our screen right the device so the the projection matrix we are going to use the projection matrix to adjust the x and y values we're going to shrink or grow the x and y values based on our screen width and height dimension right so we have the width the height the resolution different monitors different devices have different resolutions they have different aspect ratios uh some monitors are 16 by 10 others are 16 by nine others are four by three right whenever we were programming in ms-dos back in the day we didn't have to worry too much everyone every user that is going to play your game was going to play in a 4x3 aspect ratio but now with different monitors different drivers different devices we have to take into account this aspect ratio right so that is the first task of the perspective projection matrix we have to use the perspective projection matrix to encode and to adjust the x and y values to take into account the aspect ratio right the second task is to take into account the field of view when i say field of view is the angle of opening right so if we're talking about perspective projection we have this angle of opening which we're going to perceive the object in front of us what is that opening what is that angle of the field of view is it 60 degrees is it 90 degrees so we're going to see less or more of the objects based on this field of view angle so we're going to adjust the x and y values based on this field of view angle as well this is another thing that we have to take into account and our perspective projection matrix is going to help us do that the third thing and which is probably the most important thing that i think is what we call normalization of our values when i say normalization is usually we're going to go and map those values right so we have all these objects in world space they have different x coordinates different z coordinates y coordinates i want to normalize all these values i want to adjust x's and y's and z values to sit to map everything in this range between -1 and 1 which means that after we go and we perform the perspective divide i want to end up with what we call image space which is this almost like a cube that has all these values of x y and z between minus one and plus one this imaginary cube like thing with all these coordinates normalized between minus one and one in x y and z this is what we call normalized device coordinates if you ever read a book or read an article that they mentioned the ndc these normalized device coordinates it means this coordinates this vertices after perspective divide well let me rephrase that after projection and after perspective divide right we have to project them and divide by that z component so we get this normalized between minus one and one cube lightning this is what we call image space right so these are the three tasks that we're gonna have to achieve let's start looking at them one by one right let's just look at the easiest one which is the aspect ratio look aspect ratio is not hard to understand is just the ratio between the width and the height or the height and the width depending on how you want to look at things let's just go ahead and say that our aspect ratio what i'm calling a is the ratio between the height divided by the width of our monitor resolution this is going to give us a value of a and then let's just think about what that means in terms of adjusting and modifying the values of our original vertex if i have my original vertex in world space to get this conversion from world space to what i call screen space or image space i need to multiply my x's by that aspect ratio and in this case is just axis right because i just want to kind of shrink things or grow things based on that aspect ratio since my aspect ratio is height divided by the width in this case oh good so keep this in mind right this thing right here where we are multiplying this aspect ratio scaling factor we have to multiply the original axis by this scaling factor keep this in mind we're going to revisit this very soon this is going to be part of our projection matrix right so this is aspect ratio the next thing i want to look is field of view again it's not hard either it's just that we have to look at that field of view angle and based on how we kind of open that field of view is it 60 degrees is it 90 degrees you can peak what is the field of view opening right so how much do we see opening that angle we have to look at it almost like zooming out and zooming in right how much we can see of the objects in our screen so we have to find also a scaling factor for the field of view and this scaling factor we are going to multiply the x's and y's to grow the x's and y's or shrink the x's and y's depending on how big or how small that field of view really is right so given that we want right if we have this world space this is almost like this minus one two plus one and then we want to kind of project everything right here the field of view that we have right here we need to kind of shrink or grow these objects and these vertices based on this field of view angle how do we get this scaling factor well the way i look at it right since we have this it's almost like we have this triangle right here and if we look we can kind of divide this triangle into we're going to have these two right triangles and then we're probably going to have to divide this angle by 2 as well so we have half of the field of view and half of the field of view here what we are really interested in right if we look at those dimensions we can kind of think of it as the ratio between the opposite and the adjacent right so if i get that ratio it's going to give me this factor and what is the opposite over the adjacent well it is all right so katoa it is the tangent so the tangent of well half of my field of view angle that is going to give me this kind of scaling factor so how big or how small i have to go and shrink or grow those x and y values but there is just a small contradiction here let's think about this we want a scaling factor right we want a factor that we can go and scale x's and y's and then it's going to grow and shrink our objects basically that's what we want but the contradiction is this look at what i'm saying the bigger the field of view right the bigger my angle of field of view do you agree that i have to look and see more objects but i have to see more of my objects meaning that the bigger the field of view the smaller my objects have to be so i can see more of them and they occupy i'm less space in the screen let me rephrase this the bigger the angle of the field of view the less my objects are going to be right the smaller my objects have to be because i have to see more of them and also the smaller my field of view is almost like i'm zooming in right the smaller my field of view the bigger my objects have to be they have to occupy more space in the screen so i have to see less objects so do you see how this contradiction is almost like the inverse right the bigger the field of view the smaller my objects have to be so i can see more of them the smaller the field of view angle the bigger my objects have to be they have to buy more space so i see less of them so the smaller the field of view the bigger the objects the bigger the field of view the smaller the objects this is inversely proportional all right so i can basically fix that by saying that my f field of view scaling factor has to be the inverse of the tangent of my angle divided by 2. that f right there is what we're going to use as this field of view scaling factor so we're going to have to multiply that scaling factor f by x's and y is to shrink things or grow things that is what we're going to use this is going to be part of our projection matrix as well so let's just put everything together we have from before the aspect ratio which was high divided by width and now we have this f which is the field of view scaling factor which is one divided by the tangent of half of my field of view angle so how do this all play a part in the transformation of my vertices well if i have my original x y and z values in world space to convert things into this image space i have to multiply my x's by the aspect ratio and the field of view scanning factor and my y only by the field of view scaling factor do you see where we're going with this so these two scaling factors are going to have to multiply x this scaling factor of the field of view has to multiply my y's and now we have to also look at the z because we have to think about that normalization right keeping the values of z mapping all those values of z into this kind of minus one to one that right normalizing all those z values as well so i want you to keep this thing here in mind we're going to use this is going to be part of our perspective projection matrix so we have taken into account aspect ratio done we have taken to account field of view done let's look at the normalization of my z component right we have to normalize the z values and to start the discussion right to also think about normalizing the z values let's say that we have all these objects in world space they can be super far super near they have their original depth values right so regardless of where they are in space they have this depth value what i want to achieve is i want to map all these objects between these values right here and the way that i look at it it's almost like i'm going to map these things this is going to be my zero and this has to be my one but i have to map these things between this kind of zero and one everything that is in front of me is zero and two one we are going to have this concept of this two important planes in the z domain we have something called zfar which is this plane way there far from us which is basically what is the maximum value that we can visualize in our 3d scene that is what we call the z far plane right the thing way down in the distance uh we can only visualize things that are inside closer to the zfar and we also gonna have something very here close to us which is our zener plane and the zener plane is responsible for kind of determining uh what is the closest value that we have to have inside our visualization our 3d scene so everything has to be between z near and z far well the way i look at it is we have to normalize everything to this kind of zero to one right we have this values between zero and one here everything that is in front of me i have to normalize these values very well so we have to find a formula to take into account the z-far does it near maybe the total distance and then map everything into this kind of zero and one right is minus one to one in image space i am going to call this thing lambda you could call it anything you want i'm just i picked lambda just because i am going to start by saying that if i get my z far and i divide by the total distance from z far to here right this total length right here is if i minus in here that is going to give me this kind of scaling factor right so if i go and i scaled everything from z far divided by z phi minus in here which is this total distance right here that is going to give me this kind of scaling factor that is going to effectively adjust things right between this kind of zero and one normalized values not that bad right i kind of think it kind of makes sense intuitively we understand that we have this zifar divided by the total distance between z far minus india but there is one thing missing which is i also need to take into account the zener and the z near i have to basically just perform a little offset right so i kind of i get this near and offset to take into account this near plane as well and you will see that we only have to add a couple of extra terms here so i am going to subtract right i'm going to offset i'm going to account for this almost like a translation for accounting this in here so it is z far divided by z far minus in here do you see how this thing right here is exactly the same as what we had before so i had the same thing as before but now multiplied by zener this second term right here which i have to subtract i have to offset is what takes into account this zener distance right here i have to go and move things inside the zener this is what i'm calling lambda this is my scaling factor that is going to help us normalize this z original z values we want look at what we want eyes on the price what we want is a value that we have to multiply by z by the original zs so after we perform the perspective divide after we divide everything by z the values are going to be all in this healthy range between 0 and 1. this is what this lambda is going to help us so this lambda right here the way i look at it right now that we have aspect ratio scaling factor we have the field of view scaling factor and now we have this lambda scaling normalizing scaling factor i look at it right what do we have to do with x y and z converting everything into image space i have to multiply x's by both a and f done i have to multiply y by f and i have to multiply my original z by that lambda thing that is going to normalize my z because after i multiply lambda and then after i perform the perspective divide then i'm gonna have all these values hopefully between this kind of minus one one and then the z between zener and z far this zero to one values right normalized whenever i say normalized is usually values that are in this kind of zero to one or minus one to one range this is what usually normalize means in kind of graphics programming oh good there's a lot here right there's a lot packed in this lecture right here there's a lot of details we learned about aspect ratio we spoke about this field of view scaling factor we have this z normalization i want to pause right now and i want to look at how do we convert these operations right here these multiplications by x multiplication by y and multiplication by z how do we transform this how do we encode this in matrix form because we know already the formulas that we have to multiply by x y and z it's just a matter of going and kind of encoding this in matrix form right and do we end up with these things right here and i already color coded everything so do you see the aspect ratio is the height divided by the width the field of view scaling factor it is the inverse of the tangent of half of my field of view angle so this is what i have to multiply by my original x the inverse of the tension of the field of view divided by two is what i have to multiply by my original y's and the z i have to multiply by that whole ugly thing right which is basically that uh considering the zifar the distance to the zener and then minus that offset for the zener this is what's going to help us kind of normalize the values of the z after we divide right after the perspective divide very well look this thing right here is what our perspective projection matrix need to accomplish we are only going to choose to represent the same thing into matrix form meaning that we're going to have to find a matrix and we're going to have to populate the entries of that matrix in the correct places so whenever we multiply that matrix by our vector we achieve exactly the same thing that we're seeing right here and you will see that is not rocket science is super simple all we have to do is find these matrix that you're seeing right here and it's pretty easy to understand right understanding that the matrix multiplication is the row times the column plus the row times the column the row times the column we achieve at this result which is the first row right that first term multiplied by x plus zero plus zero plus zero and then the second row multiplied then multiplies by the y plus zero plus zero you see by simple matrix multiplication just by correctly placing these elements and formulas and all these variables correctly placed in the correct entries of the matrix matrix multiplication just opening the row times the column the row times the column the row times the column we are going to achieve exactly the same thing as before remember i always wanted to look at this i wanted to look beyond the matrix right a matrix is just a way of encoding and placing things in this tabular form and we know that by multiplying these things row times column row times column we're going to achieve the same multiplications and additions that we were doing before that is how i wanted to look at matrices just a different way of representing of encoding the same thing very well so this thing that you're seeing right here is our projection matrix we're going to go in our code we're going to open a function that goes and populates the correct values right the first position with that value the second position with the field of view value and then we're going to have a value for zfr a value for zener we're going to subtract everything and then everything we just place in the correct elements that is pretty much what we need just keep that in mind let's just move here to the next slide i'm just kind of shrinking a little bit our projection matrix with those values we need to find a way of encoding that projection matrix we need to create this projection matrix so we go and we multiply by every vertex of our 3d scene and i'm going to already show how i think that should look this thing right here that you're seeing on the screen this is our matrix for make perspective i am going to add one more function to our arsenal which is called met for make perspective and do you see how we have the freedom of passing what is the float field of view angle what is the float aspect ratio that we have when what is the float zener and the float zfar so we can pass this as parameter and then this function is going to be responsible for creating a matrix and populating in the correct elements there in the correct entries the formulas that we have before so if you look here in this first four lines i just added some comments this is exactly just a translation of how our matrix is going to look like so this is basically the same as this thing up here so let's look here matrix m position zero zero it is look at up there in the position zero zero it is the aspect ratio right h divided by w which is our parameter that we receive aspect ratio times 1 divided by tangent of the field of view divided by 2. simple right basically just a direct translation of what we have in that position right so what about position one one it is just the inverse of the tangent of the angle divided by two exactly what we have right here what is position two two well position two two is this one right here it is the z far divided by z far minus in here absolutely it's that scaling factor and then position two three is this thing right here which is minus z far uh times in here right i just multiply here the numerator divided by the totals if r minus zener that's it okay gustavo there's still one thing right that you mentioned that 1.0 at position the fourth row third column why do we have a one there well i don't know if you noticed but where is perspective divide in this whole thing here do you see how our projection matrix our perspective projection matrix does not perform the perspective divide do you remember how the perspective divide is that thing that goes and divides x and y's by the z component we have to create this perspective right things that are closer or bigger things that are far away they're smaller where is that division by z and you're right we do not perform perspective divide in our perspective projection matrix the perspective divide happens after so we are going to divide is going to be separate we are going to first create the perspective we multiply the perspective projection matrix by our vertices and only after we perform the perspective divide and there is a reason for that because some things happen between the perspective projection and the perspective divide and we're going to learn what those things are very soon in our course so there are some steps that are going to happen between this projection and the actual perspective divide where we go and we divide everything by z but just to give you a spoiler of how these things are going to work i have that thing right there so the reason why i have that one in that position is because we are going to save we are going to store we are going to create a backup of the original unchanged z component value inside the w of my resulting vertex do you agree that we're going to have this homogeneous right with four dimensions here this vertex at the end and i am going to choose to save we're going to have that one right there because by multiplying that one by these values i'm going to multiply that one by z and i store on the fourth row which is the w so i am going to effectively store i'm going to create a backup i'm going to save that original unchanged unnormalized z value the one before everything we're going to save the z value of our objects in the w component of our vector gustavo why are we going to do that well because this original z value is going to be super important for us in the future we don't want to lose it because there are things that we need to perform with texturing whenever we create a perspective texture correction we need to use that original unchanged unnormalized unmodified z value that is why i go there and i put a 1 in that position because then it multiplies by z and saves it in the fourth row at the w okay and just so you understand look at this code right here i am going to have a new function which i'm just creating a function which is responsible for multiplying my vector by the projection matrix and also performing the perspective divide right here so this is just already a snippet of code for you to see how we multiply the projection matrix by my vertices and also perform the perspective divide here at the bottom so look at what this function is telling us i'm calling this function matrix 4 multiply vect4 and project so i'm i receive the projection matrix as parameter and i receive my v vector first the first thing i do is i multiply the projection matrix by our original vector v which is i just have to call mat4 multiply vect4 so i multiply a matrix by a vect4 which is this matproj and v i pass these two things i get a result the result of this multiplication is taking into account aspect ratio field of view and z normalization scaling factor right so this is what i did with this perspective projection multiplication and then after that i go to the perspective divide stage which is here is where i perform perspective divide with the original z value that is now stored in w do you see where we're going with this see how i'm checking if the result.w which has my original z value is different than 0.0 so i just want to prevent division by zero result.x i divide by result.w so i am performing the perspective divide dividing everything by the z component but i'm using what is stored in w so i divide x's and y's by the original z vector which i just stored in the w component so i divide x's by w divide y by w and i divide the z as well by w reaching that normalization that i want after we create this perspective divide by adjusting all those normalizations scaling factors and everything i hope to see this result value to have those values in that range of minus one and one right so this is where after the perspective divide this is where i get my normalized things in this kind of image space that i want right that cube like thing that has all the values between minus one and 1 in both x y and z and this is something that i wanted to always remember the perspective projection stage of our graphics pipeline