 Welcome back cat from a scratch episode 14 topic today is cursor ray tracing Basically, I want to be able to use the cursor to pick a face on our cube body and change the color That's the objective today. There's a link in the description with a timestamp. You can click skip ahead and see the results First I want to talk about the bugs in the code. So if you run the program There are some orientations of our model for which the model is kind of skewed like this Which isn't correct and I thought maybe it was just the way we're Projecting the model, but no, this is because I'm just retarded and I made a typo So there's two typos actually one in the trigonometry.c, which doesn't affect anything apart from our Triangulation as this dot product is is incorrect. This should be a plus and then also in our draw.c At the very bottom in our rotations here. This magnitude quantity is Actually incorrect. This is what we're using to actually rotate the model and that's probably when you rotate it Looks a little bit whack and some orientations. This should be a plus In all these positions, obviously I copied and pasted the code when I was doing it live and I made a typo So if I close this recompile Rerun, there's now no weird skew effect in any orientation. Everything looks much more cubic anyway. So that's good I want to talk about the The rendering sort of framework that we have set up. So in our draw.c in our shader here, this GL position is quite Elegant how we're implementing our entire rendering. So we have simply a dot product So you see u1x, u1y, u1z dotted with the position of the vertex basically minus where we're looking This is extremely simple. I mean if you if you only knew how complicated some people make this very simple operation You'd be, you know, so shocked This is what they do. They do these like rotation matrices is some model matrix view matrix transformations projections, you know perspective stuff Scaling it doesn't make any sense Why they do so much complicated stuff for such a simple operation of an orthogonal projection So ours is much better than this boomer cringe stuff that they they pedal online So the way our thing works if you don't remember from before is we have this basically we have an origin in space We have a point. We're looking at called look at we're looking from called look from look from being the Center of our u1, u2, u3 frame and look at being the sort of model center ideally But when we pan the model we can move this around So the screen space here centered on u1, u2, u3 gives between negative one and one for both axes And obviously the point at this as zero zero is the center of our of our u1, u2, u3 frame and U3 points from look from to look at And it's perpendicular to this screen space And so the question is if we have a cursor location here is this cursor location over the body Or over any given triangle on the body and the answer is simply no this if you trace this point out along U3 it doesn't touch the the model at all Completely misses the model Now if you had a point, let's say right here and Trace that out along u3 obviously that hits the model and it goes right through But it hits the model and then it goes through the other side like that And so the question is how can we detect if the cursor is touching a face? And if so which face and where on that face and stuff like that It's actually quite simple to do that So how do you tell if your cursor is over a triangle well step one you find the intersection of that red line that cursor ray With a triangle plane so in this case, let me draw in yellow here This intersects the this cursor location intersects this triangle plane Let's certainly define the triangle the triangle that's going to be this triangle here. Let me define it in Pink this triangle of interest here This line intersects that plane right there and this line intersects that plane. I don't know right here or something Now question is which of these points is in the triangle now determinants in the triangle We have an algorithm from before I'll get into that in a few seconds So for this first one Finding the section of the the ray and the triangle plane how do you do that? So intersections are quite simple looking these two Primitives so a plane algebraically speaking is Set of points P and yellow such that this is satisfied P0 being the point any point on the plane and N being the normal of that plane a Line is any point in P yellow such that this is satisfied So P0 is a point on the line and defines the line's direction and T is a parameter along that That curve and so basically where this P and this P intersect is the intersection of the plane in the line That's this yellow star right here Just for example, let's solve for this you can substitute This quantity in for yellow P and then solve for T you get this and You can substitute this value for T. By the way, this T value is the distance from the point This is very important to the space You know the T value is the distance along the line To the intersection from the point that you're looking from that's very key for later And you can solve for that P value by using that expression there Now now that you've done this and found the intersection of the cursor and the triangle plane How can you check if that point is inside or outside of the triangle? For that you can use the algorithm from before basically you can compute these have a triangle ABC Take these sides a b b c and c c cross them with the face normal and you can get n1 n2 n3 Which are side normals now if you take those side normals and dot them with the vectors from the Vertices to the point of interest if all of those lines are Those components basically these components here are all the same sign That suggests that the point is inside the triangle if these expressions are not all the same sign that you that means You know that one or more of those lines takes the opposite side of this normal component and then differ your outside So if all these are positive or all the more negative point P is in the triangle So now you can tell how we can implement both these two Steps It's quite simple in code actually just do that plus we've already done this entire section So we can copy and paste that code from before hopefully without typos this time So I'll implement this function down here. We'll call it Face picker It will take in as inputs the body that we're looking from so passing the pointer to the body will pass in the Height and the width of our screen here. So in pixels then we'll pass in the X and Y coordinates of the cursor again in pixels Then we'll pass in let me just make this bigger. Let me zoom out of this good Then we passed in our Float look at or look from I should say Point that's the origin of our you one you two you three space And then we get past in this film factor, but it's also a float This function will return a pointer to that face. So we'll say stroke face And we zoom in a little bit on this so we can see better So first thing we start off with our cursor location in terms of pixels on the screen counting from zero zero at the top left I believe so in order to map those two Screens screen coordinates are negative one to one. You just have to scale that by half the width and half the height So I'll do that and I'll be right back So there you have it now. We have the X screen space and Y screen space We're basically subtracting the cursor location in pixels from half the width and half the height The only difference is that the walking point is negated because The zero Point is at the top of the screen, which means it's opposing the you two, you know vector So that's a little bit confusing, but there's a negative sign. They're not not not a positive sign. So At this point now that we have a location in the screen space of our Cursor location, we want to be able to compute the location in 3d space. So I'll do that and I'll be right back So here we go. I have this cursor 3d size 3 float Basically, we have our three components x y and z of our point in 3d space here Let me zoom in the question is how do we locate this this point in space? Well, we're taking the X and Y components in the screen space and we're taking them. Oh, that's a typo. That's not gonna work We're taking their components in the directions of you one and you two and adding them together for x y and z and that gives us our Cursor location in 3d space from the origin here in yellow. So that's good now basically have to loop through how all our Faces in the body in order to determine which faces if any intersect the Chris the the the ray coming out of this cursor 3d point Along you three. So we have to define some some iterator here. So we'll say struct face Itter equals body face. We'll start there the first face on the body. What we want to be able to save the closest face closest face Also want to save the distance to that face or something like it. So we'll say float this Zero or leave it blank And now we want to be able to loop through so we'll say while Itter is not equal null We will just do all the algorithm from before this algorithm here and Go from there. So We had to say well, I'll just start from the top. So The the first thing to do is to basically implement this expression here for T because we have a Basically, we have a plane plane being the triangle normal triangle. We already have in our data structure We have a value for the normal p0 can be any point on the triangle We can pick any of the vertices that we want we have that the line again p0 on the line is Cursor 3d and n on the line is the u3 normal So we have all these quantities we can actually solve for T. So I'll do that and I'll be right back Okay, here we are I created a Float T and I've created this expression here again. We're using components from our Face structure. So we have our face normal here x y and z components We're taking the first vertex. So no to raise zero x y and z component And we're basically subtracting the curse for your location and we're basically computing this quantity here for T Now that we have T we can solve for P. So the yellow P there. So I'll say float P size 3 And so P is very simple P equals As you can see here on the top left P P zero equals top right should say cursor 3d zero plus T times u3 new Zero and then the same thing for y and z. Okay Now Now that we have the P location, that's the first step of this algorithm here We found P P is the intersection of the cursor ray and the triangle plane P Now we can go to our old function our Save this our Geom dot C You had a function called triangulate something Triangulate face and we have this algorithm here, which is what I showed down below So I'm gonna copy all of this Hopefully without typos this time into this Function here. I'm gonna clean this up a little bit and I'll be right back Okay, I copy the code and I defined a P P Node that we're passing in the coordinates of P. So that's our our point of intersection basically this point of section right here Then as before we're taking the vector of a b b c c a And the vectors a p b p and c p taking the cross product of some of them Taking the dot products and seeing if they're all the same sign Now if they're all the same thing is we're in the triangle and then we have to a couple things So we say if we haven't upon closest face yet if closest face equals null or Distance is Greater than C That means it if our save value for the distance for the look for the previous for anyone that we had before that happened to be Closer is greater than this one and we can set a new value for this The new value being closest face equals Itter and then Dist equals T. It's very nice that we have T as the distance To from the the point to the plane that we can actually use it to calculate the distance. That's very nice property there Now here We have to iterate through so it or equals it or next and then lastly once we're almost out of this function We can Return Closest face so that should wrap up this function a face picker Now how are we going to call this function? Well, that's going to happen in our draw body routine so In our render loop Which is down here Actually, I want to add another parameter here first So believe it or not. We haven't actually been tracking This look from vector yet So I want to keep we've been tracking look at but look from kind of falls out of the expression once you know you three and the scaling factor You don't really have to know look from because look from is a determined by Something that's perpendicular in this frame in this frame here You want you you want you to you three to look at coordinates So you don't need to keep track of you look from but let's keep track of it now because we used as an input in the previous function So I'll make a new value here called Look magnitude Because we have to rotate around whenever we're rotating the model So say look mag size or just just you know size zero and that will equal basically the magnitude of the look from to look at Vector so between the problem look at what's what's the the size here? So I'll code this up and I'll be right back Okay, we got that look magnitude just very simple expression there square some of the squares Now I want to have some some variables here to monitor if a face is selected if so what face etc. So Struct face star Selected face then we'll say int selected face Number just just for you know keep track of it and then we'll have a Boolean is face selected We'll start that at zero just to make sure We can set these values in our Well, we have to keep some space here. Hold on. Let me add some space need to edit that In our event handling here. So it's not just mouse anymore. It's mouse and key. I'll change that mouse and key event handling I want to make a new a new thing here. So in this button Yes, so we'll make a new thing here. So we're to copy this middle mouse click code And get rid of some of this garbage inside Change button to which is the middle mouse button to button one because we're gonna use the left mouse button to click on on stuff on the screen Select things we have to pass in a few things here So we will use the same query X query if I have it somewhere Probably have it Copy this Up here, we're going to create a location of the cursor It's the first thing Have the cursor location in X cursor and Y cursor now. I want to Basically use the function before so selected face equals face picker and the inputs I recall our body Was a height first if so height minus 20 because we have 20 pixels for the the menu bar with Next was X cursor and Y cursor Then we had Oh, we should do minus 20 for this one as well Then we had our look from and our scaling parameter Yeah, so the final from it's not up to date yet, but we'll do that in a second So we have selected face. So then we'll say If selected face, oh, you know what I have an idea Let's let's make a new function here in our our John dot C Faces So I want to make a function here just like this one But basically it different in that it gives us the number of a face not the number of faces in the body So I'll do that and I'll be right back Okay, I have this function get face number now We pass in the body and the face Starting at zero and it basically loops through until it finds a face in the body that equals the base that you've passed in And it returns that number. Otherwise it returns negative one Then I went and I added that to the jump that h header Right here and now we go back to our draw. See down to the bottom ish and Add that in here. So We'll add a line here We will add a selected face Number equals Get face number body Selected face. I believe that should be correct And I will say if selected face number is Greater than or equal to zero. So if it's not negative one We've actually found a face, you know, that's you know We've we found one by clicking and we've also found that in terms of it being in the in the body then we can say is face selected equals one and Then we can say printf you just clicked on face number percent d slash n Select their What's it called? Is it second face number? selected face number Now if it's not can say is face selected Equal zero So now we have a Boolean here that tells us if face is selected and if it's one we know that this in this It's in this structure here selected face face structure So we can go up here into this draw style And I'm gonna code up some fancy like hack together stuff to be able to draw In this same draw loop Different colors for different faces. I'll be right back in a second. Okay, so basically the way this works is We do the same as I've asked before in terms of enabling the polygon offset and the uniform is for the color but we Have this sort of if statement here if is face selected If it's not we do what we did before if it's likely we change our draw Routine so basically we say draw elements and then by the way the parameters here. This is triangle So what's what we're drawing this this input here is the number of vertices to draw? this input is Sort of like the the type and then this is the offset So basically the way this works is we're I draw as many vertices are up until the selected face in the initial color fill color then we are Drawing just three vertices so one triangle is worth At this offset so 12 as there are 12 entries per face So 12 times the face number and then we go back to the original RGB draw style for fill color And we draw back the original the remaining triangles in the in the body So this should work. It's all hacked together. I did have to add in this select color. So let's Let's go to our header file and change that so Want to add in Another line here so that we have we have fill line background. I also want to add in select color Maybe highlight color now. We can go back to our draw. See we have this draw style here. I Want to make another draw style For the select color so make a color. We'll call it select and we'll make it. I don't know make it green so 0.1f1 fine Sure, and we'll change this to select color Select that's good Now we did pretty much everything, but I do want to go back and add some logic here to keep track of the look from Quantity like our look from a ray So that's just gonna be at the at the bottom here. I'll say look from zero equals look at this is a very simple relationship minus u3 new x-coordinate Times look mad. So where we saved before the original magnitude of the look vector now We're using that again to compute the location of look from this off. Look at in u3. So x y z x y z x y z Is that it all we have to do? Let me think. I I think it is Let's compile and let's run What I do wrong here. All right, I'll take a look Okay Obviously doesn't make any sense. Now that makes sense Okay, that worked got our model. Let's see if I click if it changes colors. Let's see Click on face six. Look at that face seven face 10 So they all seem to work Let me check at weird angles. Look at that at almost no angle at all. We can click on faces. That's pretty nice So isn't that pretty cool? We just made a way to basically detect our cursor's ray intersect it with a plane of a given triangle then determine if our point of intersection is in the triangle or not Then we change it so we can actually change the color of the model on the screen That's pretty cool. Anyway, thanks for watching. Have a great day