Math for Game Devs [2022, part 9] • Solutions to the final assignments

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
thank you okay all of my students react to the message show your presence are you here or did you escape to the secret meeting that I had no idea but okay cool cool I need to go open a window so hold bareback foreign all right okay everyone's here great all right I presume everyone is here I'm guessing everyone is not here but as a figure of speech um how do the assignments go because now we had a lot of time and a lot of assignments and I'm hoping you were doing quite a few of them um and learned something along the way bad oh no that's not good okay mesh stuff is hard it is pretty hard um the um the tricky thing about meshes is you have to like juggle indices quite a lot and it gets kind of abstract and that's a little bit complicated um didn't manage to do many of them I got so confused when I had to convert the math to code gotcha what salad hey what's up what salad was yelling hey that was a weird yell are you okay all right are you okay really what does that mean um I'm still counting this as a win beautiful looks great um okay all right um then we should go through quite a few of the assignments I think um I think the I'm not sure if I we have time to go through all of them uh but I think it's good to cover some of them because knowing how to do these things is super super useful um and so I think that's the plan we'll go through the assignments before lunch and then after lunch we're going to jump into the new topics how does that sound I think that's that's the that's the route we should go goodness actually I did math 2 last year um but of all things trigonometry was the one thing we didn't go through oh God why would you not go through trigonometry um okay excuse me um as usual my throat is dead it's I'm just now built to talk this much um all right I guess we can just do them one by one like go through the assignments um oh I need to open my notes um where are my assignments here there okay um okay so um should we start from the top or is there any any specific ones you would really like me to cover because I'm not sure if we have time to do all of them but I think we should at least do the spring because I don't know some of you struggle with that one um and probably the convex polygon triangulation at the very least donut spring okay mesh surface area right sounds good we can do this um all right should we start with the spring then or what do you think I'm not sure how I went with a health bar I hope most of you managed to do that one uh busy image okay that one might take a little bit longer um so we'll see how much time we have but we can do that uh all right okay let's do the spring uh so the assignment for the spring was to draw well the spring uh where you specify the height of the spring the radius and the number of turns it should coil around the center right uh that is uh yeah so that's that's the full assignment um and there are of course as usual there are many different ways of solving this um there's no one right answer but one thing that I would recommend when it comes to uh drawing your own shapes like this like there's no Unity function for drawing a like spring or the spiral like this right um and so the one of the things you have to do in order to do this one is a function that can draw any function um kind of similar to what we did with the bezier Curve um cats have Zoomies in the background um so Jesus Christ um so so what we did with the bezier Curve was that the drawing function itself is entirely separate from the function for the bezier Curve and so the function this is just a mathematical function given some input parameters we output a point um and then always Don't Unplug the computer they've done that before um so the function is entirely separate and this makes it really really useful because one thing you might run into if you start writing your math function in here um is that you might start coupling the um the detail level and the point drawing with trying to figure out okay if we're on point number six uh what point should we get from the bezier curve and that can get really confusing and you tend to like mix up all your indices and offsets and all of that stuff and so usually it's much more straightforward to separate that out entirely and just make the math function in isolation and then you just call it when drawing your thing um so so I would recommend doing this as the first step of like having your drawing entirely separate from the math function that defines the shape that you want to draw now so that's kind of the first step so so let's make a script um the math we need to use is hooke's law uh no I'm pretty sure hooke's law is for oscillating motion right but in this case that's just the drawing of the spring right all right um so no functionality is needed for this one nope it is just to draw the Gizmo itself so no Dynamics or anything like that no physics all right so first we need to need our drawing function um and so we're going to make it similar to The bezier Curve where um we have a for Loop in this for Loop we iterate for some number because we we have to specify the density of at which we want to sample the math function and so I think the this kind of just depends on how detailed you want it to be if you draw only like 10 points then it's going to look very coarse and not very good if you have 100 points it's going to look pretty okay um so usually we want to be able to specify the detail level of drawing this curve because we're approximating drawing a curve using just small line segments let's make it let's make it details okay and we're gonna have our function return a point um and so so now we also need to decide uh for this math function what should the input parameter be um and this is actually a choice we can we can make it could be almost anything um so if we go back um I don't know Photoshop open let's let's open Photoshop you know I updated Photoshop in hopes of them having fixed the bug where when I zoom the flickers um they have not fixed that so we still have the flickering and I've had this issue for three years thanks Adobe can you tell this this bug it's really annoying um you know we are running out of space here I think I think we have some room to squeeze some stuff in um what is up with my brush okay cool um so for our assignments we have a number of turns in our coil right um apologies for not being able to draw a coil very accurately uh great this is this is our spring we did it um sorry spring has a few parameters right we have the height um should make sure to use the same colors as the assignment um so the height is how tall it should be so we got got the height and then we also have the radius so the radius is as always the distance from the center out to the edge so that's going to be the radius and then we have the number of turns um and so this number um should is something you should be able to tweak so you should be able to tweak all of these um Jesus Christ they're just flying around hey hey goober goober scooter we go fast okay okay I'm just waiting for something to shatter um and so we need a number to specify how many turns this should have so in this case uh I don't even know three this is like three and a half um so um maybe call it N I don't know what to call it um so this is the number of turns okay um and so so now that we need to create this math function we need to decide what should the input parameter be um like the number of rings it creates uh yes the number of times it should make a full turn so it's doing that here one two um and a little bit more than three so this is like 3.5 um um and so when we make this math function we need to decide what should the input parameter be because that could actually be many different things um we could make it based on the height so so that we give it a height so maybe maybe we sample we want the height at a given value and then we return the point at that height um and then when we want to get the next point we we move the height further up and we get the next point and so forth right um this is one way of doing it um another way of doing it is that you can specify this based on angle um because if you consider if you look at this from top down then you could actually Traverse this based on an angle so if this is top down um and you give it some some angle and then we want the point that that angle should return and that would give us this point right here so we could do that as a well um so if the input allows angles that are greater than a full turn um then we could actually know the height given the angle as well so assuming we we pass in an angle that goes beyond 360 Degrees that's one way of doing it so then we're parameterizing this by angle um or like I said before we could parameterize it by height or the one that is likely the easiest for this assignment is to parameterize it from 0 to 1. uh in other words the input value of 0 should be the start of the spring and the input value of 1 should be the end of the spring so this is more akin to what we had in the bezier curve we pass in something called a t value and T is in the range of 0 to 1 right um I guess you would specify that like this if you if you like math um so so a t value is probably easiest in this case and this choice of how to parameterize functions can sometimes be a little tricky but usually a good fallback is to use the this formulation for just pass in a t value you have a range from zero to one zero is to start one is the end and then you work from there right um okay so um and that's going to be our input parameter we're just going to call that t and that's it speaking of I need to have some tea I made some teeth and I need to drink tea okay any questions so far hey boys hey hey here's a cat [Music] nice podcast [Music] um so are we using angles to determine height or another sort of value right now um so we could use angle but in this case we're going to use the percentage a t value from zero to one that represents um the percentage from start to end basically um we could parameterize it by angle or we could parameterize it by a height value but we're gonna we're choosing to parameterize it from zero to one and that's going to represent the start and the end or the the range of the full screen um uh so something like that um so you wouldn't have to or I guess it depends on what your input value is there um if your input value from is from zero to one I think I would have to see the rest of your code to tell because generally you would use LARP for that or just multiply a height by value it might be equivalent to a loop in that case um just because you have zero at the start but I could be wrong um I'm not sure what that function is used for if your value is a is a y coordinate then that would give you the zero to one range if that's what the input is to that function um author is yelling too oh no um okay uh so let's implement this or or actually I guess we first need to think about what we actually want to do so from 0 to 1 that's our input value so what we then need to figure out is where is this point as we increase this value from 0 to 1. right we need to figure out this location that's here and there are a few observations we can make that are really really useful um and so so first off um one of them is that the the three main axes are actually treated very differently um so so if you consider the um the axes here when we have my Gizmo um so if you consider that the axis we have we have the x-axis and we have the y-axis I'm drawing it a little bit rotated now um and then we have the z-axis um if we think about what happens to these three coordinates as we increase T from zero to one in other words as we Traverse this coil all the way up um and you can see that if we only focus on the X and Y coordinates then it kind of looks like this right we just have a circle we have our x-axis and we have our y-axis um and as we increase t we should just get the vector pointing in a specific Direction so we want to convert from our T value to an angle and then we get our point out of that so that's what it looks like when we look top down right so if we look at this from above all we see is a point that is rotating in a circle right um and so what you're seeing here is usually what's called a projection similar to what we've done with the dot product project something onto another thing so this is the orthographic projection the top down view of our spring and so in order to calculate what angle this should be um this is purely based on the T value um and the number of turns across the whole thing um so if we just do it based on T on the T value in other words the um let's call this uh let's call this angle Alpha um so if we base our angle off of um if we say that our angle should be our T value the input T value to this function uh multiplied by Tau and then we have an angle in radians um and what this is going to do is that it's going to Traverse one turn around the whole circle um one turn around the whole circle across zero to one so this would just be one turn so this would be this would not actually do the number of turns that we wanted to do right um I should probably give this a different color because we use green for the Angle now um why is not y pointing up uh because I decided to orient this um because I decided to orient this spring along the z-axis specifically because the um the X Y plane has kind of a special behavior compared to the z-axis in this case you could Orient whatever way you want um because again you can rotate objects and it all depends on how you want to orient your Spring right if you wanted to point forwards then you would Orient it like this because in unity Z is forward in other words the blue one is forward but how we draw this one is kind of up to us right and then if we rotate the coil then obviously it's going to change orientation right um so it's just an arbitrary choice um okay so we we now have have a way to get a an angle from our T value so again T is from zero to one and then tau is the a full turn in radians and so as we increase t uh the angle is going to increase all the way around to a full turn but that's just one turn we wanted to turn n number of turns right um and so all we have to do is to multiply this by n so if this if n has a value of 2 then it's going to turn twice as far right if n has a value of 3 it's going to turn three times as far and since angles repeat it's going to repeat a number of times and so if we just look top down on our Circle or on our spring this is effectively the solution for that um but of course that's just half of the solution we also need to deal with the vertical aspect of this um but if we think about the coordinate of the point here it is actually moving upwards at a linear rate um and so if we ignore the X and Y axis or x and z axis I meant X and Y sorry um so if we just consider the vertical component here or the lengthwise component um then all that's going to do is that as we increase it it's going to just move upwards just linearly based on um based on the T value um and so the Z coordinate in this case um is just the T value times height um and so so now we have all three components we have X and Y from our angle to Vector formulation um and then we have the y coordinate simply from T times height and so our final function um so this is a function of T right um so this is going to be a vector and so the x coordinate is going to be the um cosine of alpha and the y coordinate uh sorry and then we need to multiply by the radius I kind of forgot about the radius so let's just let's just slap that in um because cosine of Alpha and then sine of alpha this is what we use to convert from a uh from an angle to a direction right so sine of alpha times the radius that's the X and Y coordinates um and then for the Z coordinate which is the lengthwise coordinate um then we just take our height and multiply by T so height multiplied by T um and so this is our final function there we go and of course we need to include this because this is also part of that equation um okay all right did that make sense the process of getting here are there any are there any questions we're also going to implement this in code um um okay no no questions so far all right uh if some of these things seem kind of arbitrary um it's because like sometimes you um it's mostly about like getting used to sort of a problem-solving mindset because quite often the the solution when you look at it looks pretty simple and obvious once you see it right but getting there is the hard part and that kind of goes for all of the assignments we've done for the most part um and so so usually that's it's something you kind of have to practice and learn it's kind of hard to come up with general like ideas for how to solve any math problem um but yeah it's something you usually get used to after a while um all right so let's implement this and see if this works uh we didn't quite finish our drawing function so we should do that first um so let's see uh we want to first get the starting point of of this because if we wanted to be a little bit more optimized we probably need the previous points um so get spring point at T equals zero and then we start the for loop at one because we're skipping the first one because we just did that one right um and then we we want our new point or actually we need the T value first so this is going to be a a percentage it's going to go from zero to one all the way from the start of the spring uh we're zero and then all the way up to one at the end of the spring so we want a value from 0 to 1 as we Traverse this for a loop so we need to specify that here and that's going to be I divided by detail um minus one the minus one is to make sure that it ends at exactly one um all right and then we get our new points so this is the point we sample in the spring so get spring points at T and then we want to draw that line so we draw a line from the previous point to the point we just sampled and then we assign uh the currents point to the previous point so we have that next time around you could do it this way or you could have a list where you store every Point first and then you draw between every point and there are many different ways of doing this in this case I'm just calculating the next Point drawing a line calculating in the next one Drawing the Line and so forth um okay so this this method right here the the code that we've written here can be used for any math function we can replace get spring points with basically whatever we want um and it's gonna it's gonna draw this function so so what this does it's basically drawing a math function from zero to one that's what this this whole thing is doing um and so this this again could be anything so um so now we're kind of ready to just shove in a room with you um okay um so first I might want this to draw in local space just so we can move this around so I'm going to set the Gizmo Matrix to transform dot local world um and then we need the parameters we need the height of the spring so uh height uh we I don't know what to set that to let's give it a let's give it a range from uh zero to four and then we need the radius and it's going to be a range of 0 to 2. and then we need the the number of turns um all right or maybe turn counts this could be an integer or a float up to you the math will work either way but we might just keep it afloat to to make it smooth um okay so now I believe we are ready to to do our our spring function and we basically have uh two steps one is to get this angle right here uh so let's let's first calculate that uh and so that is going to be T times Tau times the number of turns so T is our input value times uh Tau which we have somewhere else where's where do we put that it's in the clock you know what um we're gonna take our math utilities and we're going to move them into new Scripts because that's what you usually do all right we got our our future games math script here we go all right now we have a Tau we can access from other places isn't that neat so now we do math fg.2 mythfg.angle to Direction uh okay so uh we do T times Tau times the number of turns [Music] okay so math FG dot Tau multiplied uh by the number of turns so turns or turn kept okay um we got the ankle and this is the angle in radians thing to keep in mind all right um then we need the um Winnie the the X Y Direction and we could actually we could actually make use of our function that we wrote before the angle two direction function and because that's effectively what we need here right um we have an angle and then we need a direction this is only a vector two because we're if we just look at the top down projection um we just we just have in an angle and a 2d direction right if we ignore height um so um so we can call this um the uh what what do we call this this is the the XZ vector um so we can use our math FG now angle to Direction pass in the angle and then we multiply that by the radius and then finally we can return our new Vector 3 we do XZ vector.x um this would be slightly shorter if you wrote this in a Shader but fortunately we're not in a sheeter right now so we get the X and Y components from the XZ vector and then for the Z component we that's our height and the height is simply height times the T value or total height times the T value right um so T times height this should be it um I don't think there's anything more to this unless I missed something and then we have a fun bug to work on um all right let's let's see if it actually works um turn on some grid and snap it and recompile this looks like some sort of spring um the radius is very large so let's make that smaller let's rotate it as well um all right let's increase the turn count we gone we got more turns and we can change the Heights and then it's going to compress and stretch um and and there we go that's our that's our spring we did it um you know just becomes a line at zero all right um that's it any questions about that don't look so satisfying it does doesn't it especially changing the turn count this looks really nice what's this useful for uh the spring itself is pretty much useless but knowing how to use sine and cosine this way is really useful um so sine and cosine you use that any time you need to go from like an angle to a direction like maybe you have a bullet spread and you need to specify like angular offsets like on two axes um and then all of a sudden you need trigonometry to do that um or anytime you need to like Place something in an arc kind of like the uh the budget cuts assignments where you have to make the inventory like thing right um or if you actually want to animate something in this fashion then you could also make use of this um so yeah I guess curved arcs you could also use the director of darks yeah um like you might be making a like I don't know a game with like railroads or roads that have like very clean 90 degree turns um you could use trigonometry to to get a position along um that turn as well um so you can use that for that and so there are many use cases for um sine and cosine like that any any time something circular is involved or something uh something involving angles then you're going to make use of this uh all right um I hope that made sense I hope it sort of makes sense at least um all right should we move on to the next or uh I'm guessing we should move on I'm interpreting the the silence as I'm not sure I think everything's fine um all right so the next one uh is to create a oh wait we have the the color blending as well um yeah let's do the let's do the color blending why not that's a suspicious sound from the bedroom okay I just need to make sure the kittens are not chewing on cables or something um can we make it a gradient color uh yeah we can do both let's start with the easy one and then we can do the actually also kind of easy one um so when you want to blend between two different things either you're gonna blend from a position to another position then the most simple blending function is called lerp so this is the one we talked about earlier where you can you can use this function to blend from one state to another based on a percentage um so in this case it would be from zero to one not one hundred so it's kind of like a fraction so 0.0.75 would be 75 of the way from A to B and that's so that's a lerp or linear interpolation uh linear meaning that we draw a straight line from the first data points to the second data point um and so that's what we need to do we need to do this with colors so we want to have one color at the start and one color at the end and fortunately we kind of parameterize this already with the T value so we can use that directly in our blending function uh so if we start with a alert then we need two colors so start color or color start and then color end then let's just give them some nice colors and make sure to make make sure to make sure to set the alpha Channel um if the alpha channel is not set uh it defaults to zero so it's usually invisible um and so so you you want to set this to some some reasonable value and then the end to some other reasonable value um okay and so we have our T value here right and so all we need to do is to to get a color given our T value so uh color C equals or just color actually we can just do gizmos dark color equals color dot lerp um and we could also in this case we could use lerp unclamped um clamped just means that if your T value is outside of zero to one It clamps it to zero to one It confines it to that range on the clamped means that if you have a t value that's outside of zero to one it's going to extrapolate as in it's going to go further than the line itself um and so this is a really important thing to keep in mind because quite often which one you use matters um and so if you consider a lerp between um if you consider a layer between two points you have a point here then a point here then zero to one would be the range here right but if you allow for extrapolated values or unclamped lerps if you pass in the T value um of like 1.5 then that's actually going to extrapolate all the way out here because this is the range of one and then this 0.5 is halfway along this line um and so it kind of just multiplies the vector from A to B by 1.5 and that's the the final Point you're getting um and so so you can extrapolate using using unclamped lips and the same thing goes for if you have t equals um T equals negative uh 0.5 then you would end up over here and so so you can use you can use lerp to extrapolate as well uh unity's lerps are generally clamped by default unless you use the unclamped variants the um when you when you're coding in shaders however shaders are unclamped by default there's a bit of a difference there that you might need to keep in mind anyway the unclamped loop is also a little bit cheaper so if you know that your values are going to be between 0 to 1 unclamped is going to be more performance in case you're writing performance performance sensitive code long story short we want to interpolate between color start and the color end based on t and there we go um all right so recombine and there we go now we're our spring has a it's a nice little little color gradient to it isn't that cute um yeah we we did it I might want to increase turn count um and then he also asked about how to deal with a gradient uh so we can do that as well um so Unity has a type called a gradient you can use so you can we can just do color gradients and this actually has an inspector thingy where we can actually Define the color gradient um so if we recompile and then we have a color gradient here so if you click this you get the um the gradient editor in unity um so here you can kind of Define your own color stops and specific color functions and whatnot um and then um instead of doing a color.lurp on clamped we can simply do color gradient dot evaluate and then this one has a has an input value from 0 to 1. and so that's just our T value so we can recompile and there we go so now it's actually using the gradient we have here so we can swap out the gradient and we get a different different vibe um so there we go can make this LARP color work with a handle so I draw a polyline yeah that one it's kind of annoying that they don't expose colors um uh what happens happens if you tie the color to Delta sign will it flash or will it flow along the lines um remember that Delta time is just a number um that represents the time since last frame and so it kind of depends on what you want to do with it like what do you what do you want to animate um you could animate the T value for the color sure you could do that um you could animate the um you could animate an angular offset for the spring point so it all kind of depends on like what you want to do with time uh but but yes you can animate whatever you want basically um like it acts like a pendulum back and forth on the color chart um you could do that as well um where you think of like the entire thing should change color so just as one color and then that one color is sampled back and forth across the across the gradients or oh salmon hey hey come on up then uh yeah right at the bottom then it becomes red at the top as it flows um yeah I mean you can do that um so this again kind of depends on how you would want to Define this um but sure we could do something like um so then we have a separate T value for the color um so here um we could do something like um t plus time dot time um and then I want to repeat this within an interval right because we want to keep this between 0 to 1. so then we can call math. repeat and so now we can pass this value into our gradient um and then if we go back recompile turn on always refresh we now have uh uh whatever this is why is this not updating real time am I getting the same bug as that other person got I think I might or am I misinterpreting the I might have to use um this one that's weird that it's not continuous okay there we go that works um okay so it's just that time.time doesn't work well in edit mode I think that's it um so then we should probably make a gradient that like repeats so then we might want something like like a like something like this so now it's smoothly repeats um uh this might be a stupid question but why is green use in RGB instead of uh instead of yellow um so oh this I don't know how much indeed in depth you want me to go on this um but um uh here here's a the short version of it is that our eyes are actually can actually be subdivided into sensitivity for those three primary colors uh when it comes to um when it comes to additive blending we're going to talk about this in when we talk about shaders but there's a concept in um when dealing with colors um where oh I actually don't have the primary colors on my on my thing um but so so when you have a color red um for instance um and then you have the color green then if we add these together um like as if they're light sources so if you're shining a light that has a pure red wavelength and a light that has a green wavelength uh these the sum of those two will actually become yellow and so this type of blending is called additive blending so it's as if you're shining light onto something so you can see that the color in the middle is yellow um and then if we also add blue um then you can see that we oh I need a new layer uh so if we also add blue you can see that we now get more colors than that we now have magenta which is the additive color between blue and red and then we have cyan which is the additive color between green and blue and then white is adding all three together and so this is a very natural way of splitting up the primary colors for the way that our eyes work so this is called additive blending um the the other option um is called uh subtractive blending um and that is used when you're doing print so that's when you have CMYK instead of RGB um and that is the um I guess we can just multiply in this case same thing and so that has a similar thing but but in this case the you have four primary colors where you have a yellow um and then you have the name magenta and you can see that when you when you multiply these together or when you do subtractive blending you actually get red when you blend these colors this way and you can get colors in between as well like this is something you can smoothly blend between um and then finally uh we need uh cyan and so if we do that then you can see that we now have um all of our primary colors basically uh so so when you when you are rendering things in games or when you're using light sources and you know your your monitor is a light source um so so pixels are divided up into red green and blue and then if you increase the brightness or decrease the brightness of each of those LED lights you can combine any color uh within the range that those LED lights support basically um and then when you're you're printing something on paper paper is white usually um and so when you're when you're blotting ink to it you actually only need these three primary colors um in order to blend um in order to to create any color on paper within the range of these primary colors um so that's how printing Works um usually they also have black separately because it's a very common color and you don't always want to mix all three every time you want to draw black um so usually the you also have black on top of those three primary colors anyway so that's that's color mixing um also we should go on our first break because we haven't had a break so so maybe maybe that that's where we we should do it so let's do a break until 10 15. um okay all right how's YouTube chat doing I don't know of any books for math I'm sorry um I did not really learn from books and so I don't have any book recommendations so it's I just don't know I'm sorry I'm sure there are great books out there uh it's just not something I'm aware of black is not a color you know How Deep Is Your Love Freya I don't know what that means that's a very confusing question it's very Broad and ambiguous ah do I make more tea I think I might have to make more tea foreign it's a song okay okay why did you post so many names of songs in chat before we started I'm really confused uh so when they told us in elementary school the red blue and yellow are three basis colors they kind of lied uh yeah so when you're when you're in like School painting uh for the basis colors um then you're kind of these are kind of your primary colors um because then if you're painting on white paper this is similar to how colors blend um when you're doing pigment mixing because if you have pigments in your paint the pigments combine more similarly to this than they do like this um yeah and so that's why when you when you mix blue and yellow you get green and that's exactly what you see here right you have yellow and then technically cyan you get green um aren't those colors negative uh yes they are the the inverse of the additive one yeah um okay color color blending as a whole is a whole topic um the so this is usually called additive blending and this is usually called subtractive blending or um multiplicative blending um yeah and it's kind of interesting that most painting apps actually have incorrect blending which is kind of frustrating um like if you're a traditional painter there are very very very few like painting apps that actually do correct pigment mixing um there's been a few models recently that some people have developed that can actually mix colors in a very performant manner in a way that is similar to how paint Blends um I forgot what the what the name of the app was um oh here it is okay this is super neat so there's been developments in this very recently um with color mixing um and how to like convert the um the more traditional types of mixing that you have in in the real world um in a painting app and this is actually surprisingly complicated to do it's not just about setting things to like additive or subtractive or whatever um and they actually worked out a really efficient algorithm for doing this which is really cool and it's kind of a shame that most painting apps don't do this and they don't support this which kind of sucks um but I'm hoping it's gonna get a wider adoption soon um but I think it's a really cool technology um yeah there is an app um I think the technology is called mixbox but there was an app that implemented this um where is it um uh yes that's the one Rebel thank you um this I think was one of the first painting apps that implemented this um might even still be one of the few that has it in general um but yeah this one this one has proper color blending it's pretty cool stuff um okay I haven't used it yet I'm still stuck using procreate and Photoshop okay if I need to make tea I should make tea now otherwise I'm gonna run overtime again I'm so bad at keeping time where's my cursing some some voice happening I think that might be in the bathroom kids okay hopefully you're gonna get some flying cats oh oh hey boys hey what toast hey hello no wait hey that's my Gizmo no no install my Gizmo no here we go no no still okay I'm just gonna get my teeth uh okay foreign foreign let's let's resume I just need to make sure Thor is water okay he was actually almost out of water look at look at this boy oh kids all right how do we get into color I forget we were doing gradients and then we got into color mixing oh yeah someone asked why is it RGB um specifically right okay that's how we got into this uh all right uh let's let's continue or do you want the cat camera let's do it let's do toast um all right let us resume react show your presence GameCube why a GameCube of all things [Music] all right okay looks like we have people are somewhat here okay GameCube uses a gradient color on its menu is that why all right um where were we right we were doing the spring um and we got a little bit Side Tracks because we were doing we were doing doing some color gradient stuff um yes okay we can do more of stuff like this depending on how much we want to get into procedural animation after the break so we can continue doing doing similar things like this um if you want um but we should move on to the donut spring um so I'm gonna turn off our flashy gradient thing and we're just going to go back to the static ingredients to make it a little bit less distracting um okay let's let's bring it back to just white for now to make it a little bit more readable okay so uh we now have a challenge we're gonna make a donut shaped spring um and so when you want the shape of a Taurus the Taurus has a two radii um so it has a major radius and a minor radius and so we need to we need to be able to specify both of these and then all of this should adapt right um so let's let's start by setting up those parameters um so I guess the the radius we have right now would be equivalent to our minor radius right um and so I'm just going to rename that um so that's going to be a radius minor and then we have radius major then maybe we want to be able to toggle between these two modes um um Taurus mode so we can toggle tours on and off um okay so got our radius Miner set up and we have our height turn count okay everything's working so now we want to be able to enable a Taurus mode where we can then set a major radius and then we want this to coil around a circle effectively and that kind of creates the shape of a Taurus um all right so how do we approach something like this um so this is actually not that different from what we had before um let's just merge some layers because I don't need those um okay so um I think that the first thing we need to uh kind of realize is that the only difference is really how we handle height and what coordinate the center of the coiling should be at um so for for this height the center of rotation kind of the axis is just a straight line uh but if we make a Taurus it's going to be a circle right and then the Taurus will coil around kind of like this right um and so the first thing we need to do is figure out okay what is the center point of our um what is the center point of this coiling based on our T value right because we have a t value for going from start to finish uh and in this case the um the start to finish is around this circle effectively um and so from T equals zero over here so zero um and then 0.25 0.5 and then 0.75 and then back to one at the start um and so the first thing we need is that Center Point and we've kind of already done this right it's a very similar situation as this um except this time we don't factor in the number of turns because now we want one turn around this like donut Center um for across the the range of zero to one for t um so that's kind of the first step um but then we also need to do the coiling itself so previously we could kind of just hand wave the way that we do this we're like okay we have our coiling and we wanted to coil um we want we wanted to rotate and set values for specifically the y-axis and the x-axis um but this time the we can't use the local space Y and the local space X anymore because now uh we basically want those direction to depend on where we are on um where we are on this donut right um so effectively what we need to do is that for a given point in our donut um we need to be able to get an x-axis and a y-axis because now this depends on where we are on the donut itself um and so we could also Define a z-axis that's tangent to the center donut um and then this will basically Define the new coordinate space that we need to coil around so if you sort of Imagine The the circle that this forms along the local y and x coordinates then in this space we can then get our Point based on the same type of coiling that we did before but the crucial thing is that this coordinate system changes depending on where we are in the Curve um like this right so it's kind of like rotating and moving around um the donut um and so we need to figure those out um and the we we can notice a few things so first off we don't really need the z-axis in this case we just need a point on the in this case the X and Y plane right like this disc right here is where we need a point um on the circle around um the um so the z-axis is kind of unnecessary here the y-axis is always pointing in the same direction that's always pointing uh up right no matter where we are it's pointing in the same direction so the only one we really need to figure out is the x-axis here um so given a point on on this whole circle how do we figure out the x-axis um well the x-axis is simply the direction from the center to that point um that is the x-axis so we we just have to take that direction and normalize it and then we have our our new axis um and then of course the y-axis will get for free because that's just always pointing in the same direction so we can just hard code that um and then then there we go so that gives us the kind of the local coordinate system of um the point along the donut itself and then once we have that we can kind of apply basically the same math as we did before where we just rotate around this local Circle um and then we end up with our with our coil coiling around the donut shape okay that's what we need to do so let's do this in code oh the kitten's left okay uh is the forward just a tangent yes the forward will be tangents to this circle [Music] um all right um so let's see what actually has to change here um the angle here is going to be the coiling angle right like the the angle for the minor uh twisting um so let's call this coil angle and this can actually stay the same we can actually make use of um can actually make use of this XZ Vector even if we're doing the donuts um so so all we need to change is what we return after this so not doing up mode Taurus mode so we're not in tourist mode we just return that which chat should I be in right now uh this chat the one you're typing in um okay I'm gonna get my teeth I think it's done hey I understand where's my pen there it is um all right um so now we need a few things so first off we'd need the current Center of the Taurus given the T value um and so that's going to be the point here um this point um so what do we what do we call this um we can't call this Center because that kind of sounds like this one um I don't know of a good name do you know of a good name do we call it C just to make it kind of Center but not really let's call it C that's our point let's call it P actually because that that sounds more like a point um P there we go we need to figure out P what is this point uh given our T value um and if our coil starts or the donut starts over here let's say uh then figuring that one out is going to be relatively straightforward we just do our our good old angle to Vector so we get the angle here um so we'll do T times Tau to get this angle and then we do angle to vector or angle to Direction then we get a normalized vector and then we multiply that by the major major radius um and then we get that point and this will also be useful because this is the x-axis so this happens to be the very same axis that we're going to need for this local coordinate space um so we're going to need this so maybe maybe we'll call this um the P direction or something okay so let's do that first um so we're going to use our angle to Direction and we're going to get a um 2D Direction in this case so math um what did I call it p-direction math FG angle to Direction and then we pass in t times Tau we could optimize this by caching this Jesus Christ okay the kittens are doing something weird hold on [Music] hey foreign I made it a few seconds ago or a few minutes ago on stream um it is a it is just the same functions that we put in the um I think we put it in the clock uh before uh I just moved these out to a separate thing so we could use the same functions elsewhere uh nerd snipe with the pigment mixing you know that's that's how it goes enjoy have fun in the rabbit hole of pigment mixing um okay um so the um we have the angle to Direction function now uh and so this will give us the uh direction to the the the point here so this gives us this direction P Direction but then we need the actual point here which is going to be the origin of the coiling that we want to do and so this origin is we can calculate that by um doing our P Direction multiplying that by the major radius of the Taurus so that gives us the center point um and then we need to Define um the two axes here so this kind of depends on how we've oriented our um how we've oriented our spring and which direction we want this to be in um so this is going to be a little bit confusing because we're kind of mixing different spaces but effectively if our Taurus is oriented like this which it is in this case the the way that I've defined it in code um then we are gonna have coordinates like this um coordinate spaces in general um takes a while to get used to uh you will very very often run into space transformation issues having things in the world in the wrong space and so forth and it almost it never really fully goes away you almost always mess something up with different coordinate spaces um and so in this case um the the the local y-axis here is pointing in the same direction as the the Taurus objects z-axis right um and so so that is our up Direction in the Taurus space uh so so maybe we'll just call that um the the local up and that's going to be a vector three um and so that is just going to be Vector three dot forward because that's the z-axis or we can just type it explicitly zero zero one um so that's our local up and then we have the um we have the P Direction here is actually the uh local uh rights axis um so we have all we need now to get this point based on our XZ Vector that we did before for the um for the local Direction in that space and so all we need to do now is we do a return the P plus so p is this point right here so P plus the um the XZ vectors x-axis times the P Direction so that will give us the we have our local Direction here and then we multiply it by these two vectors to effectively transform it from local to world or in this case from the local circle to the Taurus space um and so we just multiply the components by each of these two directions so it's going to be xevec dot y times the local up um oh p-direction could be a vector 3 in this case and then P should also be a vector 3. and there there we go I believe that should be it you could also do this using matrices if you want to but I believe it's going to be a little bit more expensive because matrices also take scale into account and whatnot and so this is a little bit cheaper there are a few optimizations you can do because like you you aren't actually using X and Y from this local up um yeah but anyway so so this this should do it I believe um could be wrong but I think that's it and and there we go oh we forgot the minor radius I think no radius minor is here okay so we do take that into account as well um so now we have our donut so we can change the the major radius and we can change the minor radius to make this little little tiny squiggle or we can do a very dense squiggle and and then then there we go so it's going to be it's going to be disconnected as soon as we have a turn count that's not an integer um and so for 6.5 turns it's not going to repeat the patterns so we have to have an integer to make sure that it's connected um but yeah that's the that's the tweet we did it all right any questions about this one seem to have done something wrong well it looks beautiful um here's the here's the cup um so so one little optimization we can do here is that the the local up since we just have one in the z-axis and zero on the other axis uh we can just um we can basically just replace this where we put the XZ of x dot Y and the z-axis here and so this is going to be a little bit faster so just a little tiny optimization there okay but here's the code so there you go we're gonna have some tea while you observe the code and while the kittens are trashing the bathroom boys I don't know what's going on over here I don't see it um [Music] I don't really see what's wrong either that looks like it should work is your is your input T value from zero to one yeah that looks like the same code works for the spring but not the Taurus then um well have you said you're have you set your major radius I think if statement is slightly cursed since else is grayed out uh the reason else is grayed out is because you don't actually need an else here um you can just do return immediately because the Elsa is kind of implicit I think that's why else is grayed out for both of us uh otherwise I'm not sure what's wrong um [Music] that one shouldn't matter the order of multiplication doesn't matter in that one um okay I don't know what's not working yeah I'm not sure but I should probably move on we can look at it later if you want um um okay okay I know I shouldn't be reading YouTube chat but YouTube chat is confusing me nothing is allocating here I don't know why we're talking about allocations we have no classes here it's all just structs and so so there's no there's no worries about allocations I don't know why we're talking about allocation um okay um cool then we did the donut um what what else should we do we how much time do we have left um so we have an hour and 15 minutes with a break that would be about an hour um so um let's see what should we do next we have the we talked about polygon triangulation and did someone mention surface area I forget which one which one do you wanna do you want to do uh bezier mesh or concave um okay which one uh we need to we need to vote uh busier okay um we won't have time for both of these so we have to pick one uh the concave polygon triangulation is probably going to take a while because it involves a lot of like dealing with lists and data in ways that requires a lot of structure uh bezier mesh is kind of the same it's also got a lot of a lot of stuff um how about inventory I think we just have one vote on the inventory uh concave concave um okay we need we need to um where did okay there you go vote reacts to that post just just react with either an ocean or a triangular ruler it's technically called triangulation okay goodness boys all right we're doing the best image um mod abuse to remove oats oh boy um all right let's do that let's let's move this someplace else we're doing the bezier mesh I might move a little bit fast for this one because there's quite a bit of code um okay this one there's a higher chance I'm gonna make some mistakes because we're gonna have to juggle a lot of indices now um all right so this is our Buzzy mesh okay okay cats are playing so violently in the in the bathroom right now all right um let's see how do we do this uh we need to have a mesh that we need to assign so just setting that up uh if mesh equals null uh then we're gonna do mesh equals new mesh and then mesh filter dot shared mesh equals mesh all right just to have that set up um then we need the uh bezier points um I think I'm gonna um I think we're gonna use the child objects to this so we can just create four child objects um we don't have a an object for this one yet all right so we need a mesh filter and we need a mesh renderer so we're going to give that the default material and then we need our busy image components it's already assigned a mesh for us how nice all right and then we need trial objects on this one so bezing occurs at least cubic bezier curves have four points uh so we're gonna make four of those what is even happening with YouTube chat I have no idea this cuckoo local person is absolutely chaotic and I'm considering Banning them for filling the chat with just nonsense um okay all right but I'll let YouTube do their thing um enjoy enjoy weirdness on YouTube I suppose um okay uh now we need to be able to get a point in a bezier curve based off of our child objects um so probably give these some labels um P0 B1 P2 P3 okay me hey I don't know why they're playing so violently these days um okay all right now we need to get a point in a bezier curve so we need a vector three uh get the point or get bezier point uh and then again we're gonna have a t value for where along the curve we want to get those points again from zero to one as usual uh we're also going to want to be able to Let's see we can probably just copy our old bezier function to save some time um there we go then we need some points um so um uh P0 is going to be transform dot get child zero dot local position and then we'll just do that for all four there we go we have our points um and then okay all right we got our points we have our get busier points and now we think we're ready to to start doing things um so so one of the the um one of the important things you have to figure out here is to um we have our our bezier curve here start we have our end and we have some control points there we go um so now we know how to get a point on the curve itself right but if we want to generate a mesh along this one then it's going to get a little bit more complicated than that because now uh we we need to have a 3D shape from this um right and then depending on what shape we want to use we might need um these directions as well right um and so so when we sample a point we actually also need to know what is the normal of this point because if we want to make this thick in other words at an offset like this um then we need to know what direction to offset this in because the normal is going to be different depending on where we are um and so we need to figure out a way to calculate the normal right um all right um and so if you um if you have a curve and we are animating a point over time remember our T value is sort of like a time value or rather we can interpret it as such and then if we then animate it over time then what this describes is really the position over time and then if you if you remember from when we we were talking about derivatives if you then get the derivative of this we get the velocity and the thing about the velocity is that the velocity is always going to be tangent to the curve itself and so no matter where we sample the Curve the velocity is actually always going to be tangents um and and then if we normalize the velocity we get the tangent Direction um and if we have the tangent direction we are almost there right because then we have this vector right this is this red one is now the tangent Direction and we can use that to calculate the um the normal Direction and because this is in 2D and we can actually take a bit of a shortcut to calculate this normal if we were to make a 3D path where the the bezier curve itself is moved out into three dimensions calculating the normal is actually very non-trivial but if we restrict ourselves to 2D just like flowstorm does the the game that I showed you earlier and then calculating this normal is Trivial um and then you get a consistent value um all right [Music] um yeah and so the first thing we need to do is how do we get the velocity or the derivative of a bezier curve um now there is a way to do that and I could walk you through all of that math or we could take a bit of a shortcut um because if you remember the the way the bezier curves work is that we have this lerp function right where we lurp based on a t value between these points so we have maybe 0.3 or something and so we get these points and so we can connect those with new lines and then for the next layer um we get another set of lines that connect these and then for the final Point uh we then get a point here the curve that this is going to draw is something like this right um and this red line is actually tangent to the Curve um and so the way that we've calculated the position in the bezier curve we can actually use this method but we get the direction from this point to this point um and then normalize it and then we actually get the tangent direction of the bezier curve without having to get the derivative and all of that stuff right which is kind of cool so we can just use this very same method that we used earlier but we just kind of ended early we don't calculate this point and instead we calculate the direction between these two um so I'm I'm not going to do any optimization now I'm just kind of going to skip a lot of that so we're going to do get busy attendant um and so we have our points D and E uh those are these two points here um so this is D and this is e so if we want the direction from D to e we do e minus D and then normalize that and so return e minus d Dot normalized um could also just called me these get points and get tangent because this is in the context of the bezier um busier situation um okay um are you wondering how I did the numbers thing um I just used copy and paste so I copied these three numbers and then I paste it also then you get the the same numbers um all right uh so now I know how to get the tangent we know how to get the point and then we also need to be able to get the normal um and here's where we can actually use a um we could actually use a a construct in unity that's very useful um or should we use that maybe we should or we could use a matrix um let's use the unity thing Okay so basically what we want um is we want to Matrix go to practice okay we can do matrices effectively what we're looking for is we want to Define this local space for every point right um it has an origin it has a an orientation because we have these three axes right uh and so maybe we can just make a function that returns um this orientation at any given point or this this local space at any given point on the bezier curve so we could just make a one function that does that whole thing right um instead of splitting it up into separate functions that's going to make it more optimized um so I'm just going to move the tangent in here um and so instead of posts we can use the Matrix can you remove our get tangent function um okay so we have our tangent and then we need the origin and that's going to be this um all right so where the origin and the tendon but we need the other axes as well um trying to figure out how I want to set up the Matrix so when we set up the Matrix we can do it in various different ways we could do either a new Matrix 4x4 where we specify each column individually we could do that um we could also do a matrix 4x4 um dot TRS where we give it a a position a rotation and a scale um but I think I think it's it's better to set the columns directly this time um so the the First Column is going to be the x-axis and that's the one we already have right that's the the tangent um although we might want to orient this differently but that's okay it doesn't really matter um all right so we we pass in the tangent here um although this is going to be a vector 4 because it's a matrix four by four right uh so this is going to be a little bit annoying if there's not a way to do I really have to do new Vector 4 for all of these that would kind of suck um just going to make a quick helper function to make this a little bit easier because otherwise the code would be really cluttered um okay let's just call it effect four we're gonna be we're gonna be a little spicy um and we're gonna default this one to zero okay so we pass in the tangent as our x-axis uh and then we need the y-axis and the z-axis and then we need the origin and the origin we already have um so we're gonna do uh Vector 4 the origin and then the W component of this one has to be one um just because of how the Matrix is set up here it is so this is effectively what we're constructing right now we're setting up these axes right here we assign the position and we assign the x-axis so we did that here that's the x-axis and we added a zero to the end and we've assigned the position and we've added a 1 to the end there right uh but only the y-axis and the z-axis why are we using Vector four instead of vector 3 because the 4x4 Matrix requires uh four components here the Constructor just that's just what it has um and so that's why we need the uh the zero at the very end because we're supplying this whole thing as a vector um and that's why um all right just split it up make it a little bit more readable okay uh the Z direction is is easy enough because we're doing this in in 2D so the z-axis is always pointing in the same direction it's just always pointing the weight um and so in this case it is simply um um new Vector for zero zero uh one zero um should be in the Z Direction here all right and then finally we need the uh y direction okay so here's where we can employ a a bit of a bit of a cheap trick um it's very that I didn't mention before that's but that's very useful to know um and that is that if you have a like in some sense we're trying to find this green Vector right and if we want to find a vector that is perpendicular to both uh the x-axis and the z-axis um then you probably know that well we can just use the cross product right the cross product gives us a vector that is perpendicular to our two input vectors um and so we could use the cross product here and that will work but we could actually take a little bit of a shortcut here um because this is in 2D and if you imagine a coordinate system um let's draw the unit circle because why not um and we have a coordinate here let's say we have um this point then we we have a an X offset here right so that's kind of the the X um if you imagine that this line drawing distance this would be X um and then we have y here um so there's actually a very cheap way to rotate a vector by 90 degrees um and the the way to do that is is something called uh swizzling so if we previously had the vector of x and Y then if we want to rotate that 90 degrees um then all we need to do is to Swizzle in other words swap components and negate one of them and so if we do um negative y and then we pass in X as the Y component then this will actually rotate it by 90 degrees um so if we consider this distance right here it will give us oops this point because now we swapped these um swapped these basically um so so this um yeah so this is a very cheap way to just rotate a vector 90 degrees um and you can also rotate the rotate the other way around um and that in that case you swap the components but you negate the other one um and depending on which one you negate it's either going to be a positive rotation or a negative rotation uh and so so this way you can actually get um all um all of the 90 degree offsets um obviously if you want to rotate by 180 degrees um then you just need to negate the vector in general so then it would just be negative X and um negative y okay um so this is um Plus 90 degrees minus 90 degrees and this is plus minus 180 degrees is there any big difference between positive and negative rotation uh the only difference is the direction that you rotate in um so you would get different results right positive rotation and negative rotation otherwise there's no difference the only difference is the direction um okay um all right so that's just a very cheap way to rotate these and so so you can see that in uh this doesn't work for 45 degrees does it no uh this does not work for 45 degrees um and so so this is a very useful tool whenever you have to get a vector perpendicular to another one and they just lie in the same plane and so if they align in the X Y plane which they do here um then you can just do one of these and you will simply get the the other one that you need um okay so um then all I need to do is to rotate it uh uh so let's see we have our tangent here then we need our normal um and so the normal we're gonna set that to um because I don't have all my helper functions now so I can't do this easily um so normal dot X um is now going to be uh let's see we want to do a positive rotation so normal dot X is going to be to be a negative tangent dot y and then the Y component of the normal is going to be positive tangent.x so we're swapping the components here so this is swizzling uh I guess I can wait what what okay writer is confused that's okay life is confusing wait now it allows me to just type it in immediately I didn't do that before maybe because I didn't like fully okay so this is probably just gonna cast it to a vector four uh with zero as the last component so in this case we can just do like a three dot forward here as well um okay so I believe this is all we need to do to get the the the coordinate space of a given point on our bezier curve um okay um so I believe I believe that's all we need to do to get that point uh all right so we might want to test this now usually I don't trust myself and so I want to I want to be able to test this so I'm going to create a range um from zero to one for for the the T value just for testing it's called a t-test um then um what do we call this M for the bezier Matrix I don't know BM m m basm I'm not sure um all right and then we pass our T value in here and [Music] let's see so this is the local position right so we should probably work in local coordinates um um transformed about local to World Matrix so used to using shapes God damn it we're gonna draw a sphere at the point uh so dot uh get position wait what is oh yeah I need the radius that's why it's sad um there we go hmm all right that is a pretty big sphere probably want to make it a little bit smaller all right let's see it's got our t-test and it is it seems to be following the curve right that's that's what we want isn't that neat all right um but now we also need to test the orientation like did we get the direction vectors right um so um I'm not sure if we can do this but let's see if we can think it should be possible I forget if you need the inverse or this Matrix but I think if we just multiply by our bezier Matrix then I think we can just draw this at zero because I think we should have moved into the space that we just defined uh yes that does work okay that means it's easy to draw the axis as well so we can do gizmos dot draw array um two Vector three dot right uh we should set the color um call her not red green and blue uh up and forward okay I guess we could have used a position handle as well but too late now all right we got got some some orientation going on here and this seems to be correct the the red one is the tangent the green one is the normal and then the blue one is the um well I guess this would be the the binormal in this case um and there we go we got our orientation set up um and so so now that we have this then we can basically do something similar as we did for the um for the Taurus right we defined this local space um and then if we want to generate points in that space we can use that space to get that point transformed into the parents space right um and so that's basically what we need to do here um yeah okay The Next Step here is a little bit like tricky it kind of depends on how we want to Define the profile of this uh because we we kind of need a shape to extrude right we're effectively extruding something along a bezier curve and so so now we need to figure out like how do we Define that data structure um I'm not sure if we should get into something very complicated or if we should just do a very simple example because I don't think we have a whole lot of time um so I think in our case we could maybe just generate a quad strip just this part right here like uh like this surface and then we generate that I think we it's easier to have time for that um okay so let's just do that for now um all right so we know that our Matrix works we have tried it out it seems to seems to work fine um so I think comment that out now um so I think what we really want is um or I guess we can no no that's fine okay sorry I'm thinking in real time and talking at the same time um okay now we need to Define all of our uh all of the data that we need so that this is going to get a little bit messy um so when we generate a mesh we need to keep track of everything we're doing and what index every every current situation has so when we when we generate a mesh we're going to have numbers attached to every vertex we're going to have um you know we're going to have zero we have one and then maybe two maybe three four depending on how we Define this order right um right and then we're gonna have to create triangles across all of these okay um so how do we parameterize this in terms of detail level maybe we specify the number of subdivisions like this um I don't know if we should specify the number of quads or the number of lines here I think quads is easier to wrap your head around this being one quad right um yeah let's call that sections um so this is kind of a classic error like I don't know if you've seen all the memes about off by one errors but it's very very very common um we often run into situations where we have something like this right um where we have to decide how do we how do we parameterize this how many is this is this three or is this four um this is a very classic problem um this is usually called like fence post problems where you kind of have the the indices of the points go from zero to three but the lines themselves themselves go from zero to two and this is a classic classic thing where it's very easy to mix these two up and mess up which which one your your um which one you're supposed to use wearing uh so that's the fence post issue happens a lot probably gonna happen now and I'm gonna mess it up at some point but but that's okay part of learning isn't it um okay so I think what I want to Define for the detail level is I think I want to define the number of fences not the number of posts so I think I want to set this number for how many of these we want um and that puts the minimum value at a nice one instead of two um so someone need a name for these um in the in our case we can call them quads but if we have a more complicated thing we should call them maybe segments uh so let's call them segments um Okay so we need the number of segments and also here's a here's a quick Unity tool development tip uh there is a function called on validate an onvalidate is kind of used to verify the input data it's called every time you change a variable um and so if I want segment count to never be less than one this is where I would ensure that that happens um yeah so I can I can just do a segment count equals um math dot Max of uh one and second counts um all right I need to drink some tea um must have done something wrong um hmm can't see anything wrong with that code right off the bat uh so I'm not sure what's wrong there I'm afraid so the error could be outside of that code um um okay all right so if we go to Unity just make sure that that works look at our segment count we can set it to 1 and we can't set it below 1. um that code also looks correct I'm not sure what's wrong I'm afraid and I feel like I should continue going through this so then we have time to walk it through but I could look at it after after class today um if you don't fix it until then all right so we have a number of segments and then we need to do two things uh for our meshes right uh we need to um one we need to define the vertices and two we need to define the triangles right those are the two steps um so we can just start with doing the vertices let's let's try to try to make it easy so when we iterate through this curve we want to get the coordinate of this and this and then we move to the next step in the curve get the coordinate of this coordinate of this and so forth um and then in the end we should have a specific number of vertices right um so so let's see maybe it's good to have the store the number of vertices that the total number of vertices and the total number of vertices is going to be a segments plus one so that we get the the last post here now times the number of vertices for your profile which is 2 in this case right um so it's going to be um segments plus one times two I believe so one two two points uh number of segments but we also need to include vertices for the last one so we do segments plus of one instead of seconds okay that's our vertex count um so let's just Define that if we can spell that's going to be a segment count uh plus one times two we could Define a constant for the number of like a number of points we had per profile if we have a more advanced profile we would have more points than just two but so that's where you would insert the um your the number of vertices in your profile um okay [Music] um yeah I think we're ready to define the the vertices um so let's make a I'm gonna ignore optimization now so I'm just going to allocate a list um all right yeah vertices uh and then we need to make a for Loop and let's see how many uh divisions do we need now well in this case we actually need the number of posts not the number of segments right um I feel like there should be a better name for this um other than posts um I don't know what to call the call these uh but in any case we need to um we need to iterate through that so that is going to be segment count plus one um and then we need to get the T value in order for us to to sample our bezier Matrix right um and so that is going to be I divided by us the the total number uh minus one which is going to be just segment count right um so we need to convert that to float and we need the minus one because we want this to end at a value of uh one um all right and so now we can get a point or our Matrix in the bezier Curve um so that's our our bezier Matrix let's just call it MTX and at T um and then here we need to add our two points um so Birds dot add and then we need to transform a point from the local space of the Matrix to um the the world space that we're using and so we're going to do a matrix dot multiply point three by four because we don't need the last column so three by four is going to be cheaper it's going to ignore the projective row which is this last row is for projective Transformations which we don't need we don't have that and so we can just ignore that completely and so that's why it's called three by four because we're we only care about this three by four region of The Matrix um and so we do multiply point three by four and then we pass in the local space points um and I guess we don't we don't really have those local space points we could actually make them public um so profile point a profile point B um right I'm going to default those to uh what are our axes again uh I guess they should be Vector twos actually um I guess they could be Vector threes it's a little cursed but you know what let's just do Vector three um so uh we want to place them along the z-axis in this case um so new Vector three zero zero negative one and then positive one so these are just the uh the local space coordinates of the the profile that we're extruding along the bezier curve so these could be anything I'm making them public so that we can change them um all right uh and then we just pass them in here so profile point a profile point B uh and now we should have gone through all of the vertices that we need uh all right and so then we need to do the uh triangles we're gonna make a new list here as well and remember triangles are indices uh they refer to the index of the vertex that we want to create a triangle around and so every triangle is three integers so if we want to create a triangle uh between 0 1 and 2. those are the three vertices we need to pass in to create this triangle and the order here matters it follows the left hand rule in other words if you make a thumbs up with your left hand then the phase of normal is going to be the direction of the thumb and the um if you're the order you define the vertices in follows the curl of your finger in other words the normal of the surface um is going to follow the left hand rule so you want to define the vertices in this order that this arrow is pointing in um so we want to Define it as 2 0 1. and then for this triangle here we want to do something similar so we're going to do 2 1 3. okay and so um here we need to kind of decide what we want to iterate over I think in my case I think it would be easier to iterate over every segment right because every segment has two triangles and so it's relatively easy to just iterate around the number of segments so that's going to be our iterator um all right and so now we need to figure out how do we go from the current segment to the indices that we want to Define the way that I usually do this is that because all of these things are relative um as in if we're looking at this quad right here the indices is going to be a zero and then plus some number to access these other points right when we do the next quad it's going to be 2 plus some number to access the other points um and so so usually I the first thing I do is to figure out what is the root of this this whole quad and so the root in this case um we can see that it's a segment count or the current segment uh times two right zero times two is zero one times two is two um yeah and then uh wait did I is that not hold on uh yeah two times two is four three times two is six yes that's correct um so the the root index is always going to be the current segment times two so I'm just going to call that s to kind of specify that this is the segment sometimes I rename my iterators just for that reason um so the the root index is going to be S times 2. um and now It's relatively easy to to get the next one um so the neighbor is going to be the roots plus one right um so um so the neighbor is going to be a root plus one um and then the next point is going to be root plus two because it's two plus two and then the neighbor of the next point uh it's going to be root plus three and so in this case uh it's a relatively simple simple offset that we're setting up here um okay and then we need to define the triangles so triangles dot add we're gonna have to add six numbers here right because it's two triangles each triangle has three indices um and so we just do the the same thing we did here so it's going to be root um root Neighbor Next right that's the first triangle um so root neighbor next okay first triangle second triangle all right so the second triangle um we could go from this one so this is neighbor to next neighbor to next I think that's correct um so neighbor to next neighbor to next okay I believe that's it for the triangles and then we need to assign this to the mesh so we're going to do mesh.clear just to remove any old data and then mesh dot set vertices I'm going to pass our words in we're going to do mesh dot set triangles I'm going to pass in our triangles to the default submesh index which is just zero and then we also haven't calculated the normals now um so we might want to do that we can either calculate them ourselves or we can can calculate them manually so so there's a function called recalculate normals so this one is just going to kind of do it for you it's going to approximate it based on the neighboring vertex structure uh or we're going to sign them manually um the um the I think the best way of doing it in this case is that we can just Define them manually um because we actually have the normal data from our Matrix so then why not just add that right so we're gonna Define our normal and so that is going to be the Matrix dot multiply vector um and then we pass in um I guess the normal is just the column right so the normal is the the First Column so we actually don't don't have to transform at all if we can just get the column directly um um wait why is this sad oh because we already have a thing called normal it's a normal there we go okay all right so we have the normal and then we just add that to our normal three and also add normal another twice because there are two vertices right and they have the same normal uh cool and then we do mesh dot set normals as in our normals and I believe that's it um another thing if you're doing this per frame you might also want to do mesh dot mark dynamic um it just it just optimizes it for frequent updates as the documentation says it's going to be a little bit slower if you don't do this um okay uh I think this is enough unless I've forgotten something [Music] um let's see if it explodes uh recompile okay beautiful I love this look at this this beautiful quad um all right increase the segment count and here we go we have now created a well technically a busier service right but that's that's our that's our little wavy wave isn't that cute we did it and we can look at the wireframe as well we want to see the structure that we ended up having so if we now increase the segment count you can see that it adds some more vertices um yeah okay we actually didn't hell yeah hold on word to draw a wavy quad I don't know yeah I mean it is it is a lot of work but blender inside Unity I am seriously considered writing a 3D editor in unity but I've never gotten to it it's a lot of work um um pro builders awful yeah yeah so there there are already like 3D um editors in unity and they probably spend more time on it than I will be able to um yes there's a git with all this stuff I haven't committed this code but I should um okay we never ended up using the vertex count usually um you use those when you use arrays instead of instead of lists but uh I guess we can do a quick optimization as well uh just to to make sure that this doesn't allocate just out the ass every frame um so we're just going to move these out into the outer scope um and then instead of defining new ones we're just going to clear them before we generate anything okay and so this is defining vertices this defining uh triangles uh uh right Gustav if your triangles are flipped so that they're upside down um then it is probably the the order that you define the triangles in um have been flipped or you flipped the vertices in the profile um or pass them in the in the opposite direction or whatever um um yeah that code looks correct so I presume you probably flipped these somewhere and where do we use the get tangent function um I actually merged it so that um the tangent is re is returned in the form of a matrix instead so we're kind of doing the position and the tangent um directly and the same function because that's cheaper and why not because that's kind of the thing we need anyway um yep and so our get tangent function is basically this part right here right um okay and I will push this code um let me just test to make sure the profile stuff works um yeah this seems to work [Music] um so I think should also be able to do stuff like oops like this yeah although now the normals are incorrect we kind of hard-coded the normals um so if you're wondering what a mesh looks like when you have incorrect normals uh this is this is what it looks like um because now the shading is confused but we can use it to generate this type of stuff um we would just have to to adapt the normals after this but now we basically generated a polyline right generated a thick curve okay I should revert the those changes all right um um not sure why I'm not getting a mesh uh check for errors in the console uh make sure you have a mesh filter and a mesh renderer with the material assigned to it um double check this um is your number of segments set to one or because that's what would happen if it's set to one hmm that is weird I don't know why that wouldn't work um I don't think I did a ride just seems like a wavy line to me uh so your points are now in 3D so keep in mind that we actually haven't added support for uh Z positions now um so the the orientation is is going to presume that your child objects have a z position of zero um so so make sure that your points have a z value of zero otherwise um you're going to get wonky results um so if you have a weird squiggle then it's it's not going to be super great um okay um Adam I think what it could be is that your points might be defined in the other direction like that that might be it might be as simple as that right like maybe your first point is on the right side and the last point is on the left side uh then it would be um upside down right Maybe although your mesh is not it says None there um wait I forget if you had an upside down mesh or like a flipped mesh or what your case was um but you have to make sure that you assign to the mesh filter if you don't if it's not rendering anything [Music] um okay you have that um it's possible maybe you added this code later and the mesh is no longer null um so I think I think you could you could move this outside just assign it every every on druggismus um because it's possible the mesh is no longer null but somehow the mesh filter never picked it up when it was created okay um all right um how much time do we have left we have seven minutes until lunch uh what do we want to do for the last few minutes any other assignments you have questions about um we have time to talk about some of these but we don't have time to implement them um um some of you talked about the polygon triangulation I think that's a that's an interesting exercise I think we should talk about that let's do that as our last last thing um so all right let's do polygon triangulation so this is kind of kind of a fun and challenging problem um got the mesh now but for some reason are the shark teeth uh that means your triangles are incorrect some order somewhere is not the way it should be but I mean if you want shark teeth then that looks great um okay so pulling on triangulation uh so this is a common problem in Tech art or in like 3D modeling you have some sort of uh polygon and then you have to fill it in with a surface um and so uh when we talk about something like convex triangulation if you have a a shape that is fully convex um then in this case it's a relatively straightforward process to to triangulate this because when you have a convex shape all you really have to do is to consider one point here and because it's convex you can actually just draw a line to every other point um because there's no chance that you will like accidentally um like intersect the mesh anywhere if it was concave like if we had a concave mesh like this then this would actually be an invalid triangle right like we don't want a triangle here uh but because it's convex every Point can see every other point right and so when you have a convex polygon all you have to do is um iterate through the um of the parenthesis was the issue for me oh so that one is doing an integer division um yes you have to convert one of those to float in order for the T value to be a floating point value yes um okay anyway um so when you want to triangulate a convex shape you just pick your point usually the first point so if this is zero one uh two and three and four then all you really have to do is to say Okay I want to create a triangle between 0 1 and 2. then we've got our first triangle and then the next triangle is 0 2 3 and we got our next triangle and the last one is going to be 0 3 4. and so it's basically a for Loop where you define the indices with a bit of an offset to generate these triangles um and so that's how you triangulate a convex shape now the way more harder way more hard problem is the um concave shapes and so now if we want to triangulate a polygon that can be concave that means we might have a situation like this right just a very very irregular jagged unpredict unpredictable thing right so now we have a a polygon that is that is concave so our usual strategy of just picking a point and triangulating um every other Edge is obviously not going to work here because if we consider the first point here we can just like okay if we employ the same strategy we would create a triangle here and then we would create an incredibly skinny triangle here and then it would create a triangle here and then a triangle here and then a triangle here um from here right and then it would overlap here and so I would create a triangle in this entire region and so this uh the strategy we used before it doesn't work anymore because now we might actually accidentally overlap some points um and so we can try to figure out okay so what are uh what are some of these um what are some of the properties of uh these vertices like what is special about the vertices in a concave polygon um and so you can actually look at the internal angles and that can actually inform us a little bit about the geometry we're dealing with um and so if we look here at the internal angles you can see that this one is less than 180 right and that one is two but this one has more than 180 degrees right um and then we can continue and this one is less less um and then again this one has more than 180 degrees this one is less this one is less this one is more um and this these types of points have a name so not only can we call the entire polygon convex or concave but when it comes to the points themselves this property is called convex if the internal angle is less than 180 degrees and it's called reflex for some reason um if the points have greater than 180 degrees on the inside and this is actually critically important when trying to figure out how to triangulate this because if you look at the vertices that are convex those are way more likely candidates for triangulation right like if we look at this one and we'll look at its neighbors we can actually create a triangle safely here right if we look at this one and its neighbors we can create a triangle um look at this point and it's two neighbors we can create a triangle there too and so the first step is kind of like find convex points and triangulate just triangulate the neighbors of the the convex points and this strategy kind of works um especially if your cat will stop eating your cables hey um so this is kind of kind of the first step to to doing this um but this will not always work um so this is going to work on some of them uh but not in every case um and so so what is the case where this strategy wouldn't work well consider this shape right here we have a vertex we have another vertex we have a cat and then we have a Vertex down here and then we have a Vertex here so now we consider the the internal angles well it's convex here it's a reflex here it's convex here and it's convex here and so now we might just use our algorithm of like okay well this one is convex and then we look at its neighbors and create a triangle with its neighbors and so now we've actually created an invalid triangle like this is not how we're supposed to fill this shape right um I need to eject this boy Jesus Christ you you you're getting you're getting rejected hello you're being a piece of you're being a piece of you're the cutest piece of yeah stop eating my cables it's dangerous and bad okay do you think he's got it this face he's so full of you you're full of okay all right um so this triangle is not valid right and so now our our strategy of of just picking a a convex point and creating a triangle around its neighbors no longer works um but it actually works pretty okay in most cases um um but so so the the final thing we have to do in this this strategy or this algorithm is that when we're considering a candidate for creating a triangle um so this would be considering this triangle right here right we have to check if it contains another point um so so we have to check does it contain another point if it does then don't create the triangle that's a really really important step to make sure that this this algorithm is robust um there are a few shortcuts you can take here um when you have a triangulation like this um it's actually there's an optimization where when you're checking if it contains a point um it's actually only possible or rather you only have to check for reflex points you don't have to check all of the convex points you only have to check if it contains reflex points which is actually kind of a nice little optimization so we don't have to check every other point every time right um and so if we do that strategy then if we're considering this point we check its triangle it contains the reflex points and then we discard that candidate and then we move on to the next one we consider this one and its two neighbors this triangle right here is valid this is a triangle we want to fill and our new parameter now is uh this triangle right here just one triangle left and then we fill that in um and so so that is usually the the strategy that you employ um and so if we were to do uh this one right here then we would start with some points maybe this one we pick this triangle right here and so that one is is convex and then we fill in a triangle uh now we have a bit of a scary situation because when you have collinear points in other words points that lie along the same line the algorithm gets ambiguous and messy so hopefully you didn't run into that or you don't have to deal with that go to the next convex Point uh we checked for um containing neighbors here it doesn't seem to contain any points right so we create a triangle and remember every time we add a triangle the perimeter of our polygon kind of shrinks right like the we're dealing with a smaller and smaller polygon every time so you need to take that into account that the the states of whether or not a point is a reflex or convex can actually change right in fact that actually happens here so the next triangle that we got is checking the neighbors of this one which is now this point and this point um and so the uh this one is still a convex but this one is actually convex now but it wasn't before um and then we create a triangle there um no no no not the cables not the cables not again we've been through this Mr Salad balls um okay and so uh the next triangle will be created here so we fill that in and now the new angle of this one is actually almost 180 degrees but it is actually a little bit smaller so this one is now convex right this one is also convex now um and so we kind of keep keep moving on here so the next triangle would be a very skinny triangle here which generally if you want a very good triangulation algorithm generally very thin triangles are to be avoided gpus don't like skinny triangles um so you generally need a better strategy than this one uh for like a like a very optimized algorithm or one that gives you a better sheet rather okay and the next one um we're checking this point uh and for this one uh this one actually it seems like it could probably contain this point um I think it does it's almost collinear with these three points um but it seems like this would be inside so we're skipping this one so we're not going to create a triangle around this one's neighbor because it contains those points so we're doing this one instead we're skipping to the next one and this one can actually Define a triangle just fine so we fill that in this is now convex instead of reflex because the angle is less than 180 degrees and we can create a triangle with that one so that's going to be this triangle right here and that because this is the neighbors these are the two neighbors of that point um and then finally we have this angle right here is convex convex convex and it's just one triangle left and that's when we fill in the last triangle um so this is kind of the strategy that you employ to triangulate um this triangulation algorithm actually has a name and it's called the ear clipping algorithm so that's a very useful relatively easy to implement a way to do uh polygon triangulation um some of the more like mathy stuff in this that's less about the algorithm itself um is that when you check for whether or not a point is a reflex or convex um remember that we have a situation kind of like this right uh where you either have a convex internal angle or you have a reflex internal angle um if you want to check if this is convex or reflex this is actually kind of just a straight up dot product or sorry um determinant right or the wedge product because we have a vector pointing in this direction and then we have another Vector pointing in this direction and we want to know is this Vector pointing to the left or to the right of this one and that's all we need to do right we don't actually need like the the actual angle here like we don't need to know if this is 135 or whatever all we need to know is is it to the left or to the right um and so we can actually just use the wedge product um so this is a and this is B um so so all we need is the wedge product between a and B and then we need the sine of that one like is it positive or negative um so um so we can use this to determine if it's convex or reflex without actually calculating the angle because we don't we don't need the exact angle we just need to know if it's to the left or to the right um okay um and so so this one would be either positive or negative depending on which which one of these two states um it has in relation to these vertices um the sign of this one would be different depending on the winding order if you're pulling on a stiff been defined um like clockwise or counterclockwise so that's also something you might have to take into account when you're doing this uh but yeah um all right could one solution be segmenting the shape of the convex points and then recursively divided like that uh what do you mean by segmenting the shape with the convex points um we've gone a little bit overtime but I hope that's that's okay uh we don't have time to implement this um but but I think I think this kind of explains the process at the very least um all right any any questions or thoughts about this or any of the other assignments uh before we go for lunch um or or yeah any any questions uh have you pushed to the git uh I can do that um uh the convex points on the points between them are separately triangulated uh I don't know what you mean by points between them like how would you check for that and what do you mean by that uh let's see uh okay everything's been pushed to the repository um okay um yeah I'm not sure what you mean you did I think you would have to draw draw a diagram of the process um okay uh any other questions we're gonna after lunch we're gonna we're gonna do the the special bonus topics um that are that were not planned from the beginning which means that I might fumble and I might make a lot of mistakes and I might not be qualified to talk about the topics but it should be should be nice regardless um we're going to talk a little bit about some esoteric math we're gonna we're gonna open the quaternion box the the rotate the mystery box um we're gonna open this a little bit and just peek inside and kind of kind of try to build a little bit of an intuition about how this mystery box works um and so so we're gonna do that we might also have time to get into a little bit of geometric algebra which is kind of fun um or at least I I think it's fun and interesting um okay [Music] um all right [Music] have an implementation problem like the shape I sent this morning I'll have to look at it more uh yes okay yeah I I can do that off stream we don't have to do that while I'm live uh okay I think uh I think that's I think that's it for now right questions thoughts does YouTube have any questions uh yes all of this will be on YouTube don't worry the the thing after lunch is also going to be on YouTube okay something like this [Music] um I divide the shape between the reflex points then the algorithm becomes about how do you divide between the reflex points and that is a non-trivial thing to do um it might be trivial in this case um but in the general case it is not trivial and it's also difficult to detect which case you're in um yeah yeah so so for example if you consider um so your idea let me see if I just got this right your idea is to take the all of the the points that were originally reflex um and basically uh triangulate based off of those uh which would be these three points right um so yes if you if you create a triangle between these reflex points than all of the other areas that are left are happen to be convex in this case um so that will work with this specific shape um but it will not work with the general shape um so so if you consider um well I guess you can just make a make a little shape like this um like now what does it even mean to make a triangle out of these and like how do we how do we how do we subdivide this and whatnot um and so if you want to look into that that is actually a separate problem and that is called convex decomposition um so if you want to if you want to look into that then this is the search term um and convex decomposition is generally as far as I know a harder problem uh than polygon triangulation um in terms of algorithmic complexity I believe convex decomposition is just much more expensive um whereas a polygon triangulation can actually be done really quickly um we haven't actually talked about like algorithmic complexity like the um like the O notation o of N squared and O of one this type of stuff um but uh there there are fast ways of triangulating uh there are ways that are faster than ear clipping as well um in terms of how much the algorithmic complexity grows with a number of points um but those are complicated um we have data structures and algorithms in December here right cool okay then you can you can maybe do that and then you're probably going to talk about it there um starting next week not December oh okay it doesn't dot product give me the same result as a wedge product no um because the dot products does not distinguish between these two cases the dot product Returns the same result for both of these um so the dot products will be able to tell you if this is behind or in front um so that's what the dot product can distinguish but the wedge product will distinguish if it's to the right or to the left so that's why we're using the wedge product and not the dot products okay all right I'm very hungry we have to we have to go for food uh we're gonna we went 20 minutes over time um I do we go for an hour of lunch or do we shorten the lunch uh long lunch or short lunge or I guess it's a normal lunch or short lunch what would vote with your with your lunch lunch money uh uh one vote for a long lunch okay not doing double lunch 50-minute lunch that's a weird compromise I guess it's valid that's like lurping between the two um all right let's do normal length lunch um okay all right going for lunch break uh okay hmm okay we're zooming in an hour then um lunch break there we go uh before I go and turn off the stream anyone on YouTube um do you have any have any questions wait double audio do you have double audio that's my audio doubling up for everyone or just that one person audio is all right fine there uh audio is fine okay cool then that problem probably has two tabs open or something all right uh thank you thank you for joining after lunch we're gonna do the special special topics of esoteric math um still interesting but maybe a little bit less relevant for games at least when it comes to the abstract algebra stuff we're also going to talk a little bit about splines and procedural animation which is much much more applicable to games um at least so far um all right well I will I will see you all after lunch hope you have a good good lunch break um all right bye everyone
Info
Channel: Freya Holmér
Views: 48,281
Rating: undefined out of 5
Keywords: Acegikmo, Freya Holmér, Freya, Holmér, Twitch, Unity, Unity3d, math, vectors, dot product, scalars, numbers, mathematics
Id: sZKfaio97bc
Channel Id: undefined
Length: 196min 1sec (11761 seconds)
Published: Fri Nov 04 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.