Perlin Noise in GameMaker Studio 2

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
these sheep are wandering around in a nice normal possibly sheep-like manner these sheep are not both groups of sheep are wandering around in random unpredictable ways but this group is using purlin noise and this group is using gamemaker's built-in random function randomness or unpredictability is really useful in making games but often pure randomness as you can see gives you something you don't want because many things especially living things are somewhat predictable if this sheep is walking this way it should probably continue to walk this way and if it changes directions it would do so gradually it would not try to go in every direction at once like these sheep over here to use a less pretty but perhaps more clear example here are two graphs in each case the graph is made by drawing a line between a series of points in this case the points are generated using gamemaker's built-in random function and in this case the points are generated using purlin noise the graph made using the random function is erratic and unpredictable where each point is unrelated to the one that came before it the graph made using perlin noise is still random in a way but the change is so gradual the graph forms a smooth curve you can see the same thing in two dimensions here every pixel is being generated with a random value here every pixel is being generated using purlin noise the purlin noise version forms a smooth gradient while the random version is just white noise purlin noise was created by ken perlin he created it for the movie tron the original one and he won an academy award for it because while perlin noise is random it is random in a very different and useful way in tron it was used to create textures it is still used for this purpose but it's also used for many other things like randomly generating terrain or movement i'll be using it in my vectors and steering behavior series to create a nice smooth wandering behavior but it can also be used in shaders it can be used to create a shaky cam that reacts to slow motion and really so much more so how does perlin noise work well i'm not going to explain the math behind it because honestly i don't know it well enough and a lot of other people have done it much better than i could i'll include a link to at least one of those explanations below but i will explain the general concepts behind the math and more importantly for us how to use the perlin noise function to make things in perla noise works in multiple dimensions but i'm going to explain it in two so let's say we have a two dimensional grid pretend that at each vertex in the grid there is a value for any point in the grid that is not on the vertices the perlin noise function looks at the four vertices surrounding that point and does some math on those four numbers where the closer the point is to a vertex the more that vertex's value matters so if you pick any position the value return for that position will always be the same in basically the same way that the value returned by a random function will always be the same if you set the seed in fact you can think of the position as being the seed for the pearl noise function however the closer to positions are the more similar their values will be because the algorithm is looking at the same or mostly the same vertices only the weight given to each vertex is changing now this is a slight dumbing down of what is actually going on but it is correct enough that we can now talk about how to use the function in game maker the only thing i want to add here is that while i explained it in two dimensions it can work in any dimension and the perlin noise code we will be using is based off of three dimensions so let's look at the code [Music] let's start with the perlinos function itself as you can see it's moderately complex i didn't come up with any of this myself of course it's a pretty direct translation of ken perlin's improved noise which i translated from some c code online which you can find here if you're interested and again i'm not going to explain the math or the code in depth what's important is that we pass in three arguments and down here we're returning one value so three arguments in one value out those three arguments specify a point in 3d space and all of this code figures out what value to attach to that point in 3d space and again given the same position it's always going to return the same value the other important thing to note is that i've set up some default values for the y and z arguments so that when we use this function we can pass in just one or two arguments instead of all three but it is important to remember that even if we only pass in one argument the function is still always going to be looking at a point in 3d space the other arguments are simply being passed in by default i chose these numbers at random you could use other numbers you just don't want them to be integers for reasons i'll discuss at the end now let's look at its use so here's the code that creates this smooth curve in the create event we create a variable and call it n and give it a value somewhere between 0 and 1000. note that we're using the random function not the i random function because again we don't really want integers we create an increment variable and set it to a low number you'll see why in a moment we then create an array half the length of the room's width plus one and we loop through that array and we pass in n as the argument to our purlin noise and we get one value out of this function remember that i've specified two default arguments so even though i'm only passing in one argument here there is still an x y and z value and we have our point in 3d space and after we use in we then increment it so the next time we pass a value a position into the perlino's function that position is going to be in a slightly different place but still very close to the position that came before and that's important because as we mentioned before the closer the positions are the more similar the values are so if you want the purlin noise function to return a gradual change of values over time the amount that you change the position you're looking at also needs to be very gradual so this gets us our random number but in order to draw it to the screen we do need to do a little bit more to it the first thing that i do is map the value between zero and room height and put it into the array side note map value is one of my favorite custom functions it takes a number and maps it from one range to another which is incredibly useful in many different circumstances i include it in almost every project in this case it maps the value from a range of negative one and one to zero in room height so if the perlin noise function returned negative one that would be set to zero and if it returned one it would be set to room height if it returned zero it would be set to half room height and so on that allows us to scale the return value from perlin noise to something more useful something that we can actually see on the screen now purlin noise doesn't actually return a value between negative 1 and 1 but i'll talk about that more at the end as well and for now this is close enough in the step event we basically repeat this process once every step so we get a new value for n we increment in we map that value and then we push it on to the end of the array and delete it from the start of the array so that the array stays the same length in our draw event we're just looping through the array and drawing a line and now that i've explained this code i want to demonstrate what happens if you have a high value for n i have a slider here which i can toggle on and off and its position is tied to the increment value and you can see that if i increase the increment value the amount our position in purl and space is changing every step we quickly get something that approaches true randomness and if we decrease the increment value we get smoother and smoother lines with less and less change over time i am going to show the 2d example but before i do i want to point out something very important in the recent tutorial on how computers create randomness we talked about how random functions aren't truly random and if you give them the same input you get the same output that is true with perlin noise as well as i said before if you give the function the same position you will always get the same value and you can consider that position a seat of sorts give the function the same seed you get the same value just like with a random function however with a normal random function the seed is being changed and then used again changed and then used again because the goal is to be as close to true random as you can get but with purely noise we don't actually want that we want controlled randomness we want that similarity so the purlin noise function doesn't automatically update the seed when you call the function like the random function does it just does the math you have to update the seed manually by changing it in some way over time which is why i'm incrementing the value after each use and is something you have to remember to do when using perlin noise now let's look at our second example this code is only used for drawing the results to a surface so i'm going to skip it and only cover the code that deals with purlin noise i'm now declaring both an x and a y position and a single increment value we only need one increment value because we will increment the x and the y position by the same amount although you could do it by different amounts if you wanted to and you'll see why this is called why start in just a moment then we have the draw event and again i'm going to ignore all of this code which is just used to draw everything to a surface and focus on this code which actually creates the 2d pearl and noise and it is a little bit tricky at the heart of this code i'm doing a double for loop and for every pixel in the window drawing a 1 pixel wide square that is colored a shade of gray based upon the value returned by purlin noise again scaled using the map value function so we get the value from the purlinoids function with our x and y position scale it set the draw color based on that scaled value and then draw the rectangle what's tricky is how we have to increment the position that we passed into the prolinois function we are incrementing the y value inside the internal for loop and then resetting it every loop which is why we have the variable y start and then we are only incrementing the x value as part of the outer for loop to understand why we are incrementing the x and y values this way we have to visualize how this is actually being drawn we start in the corner at some random position for x and y and then for each column so the x value across the screen we go down that column to draw our first column of squares we don't actually want our x value to increase while we are in this column because remember that the value we pass into the perlinos function is essentially a location and that how similar the return value is is directly tied to how close two positions are so if we increase the x value then by the time we get back to the top here to start drawing the next column of squares the value we are looking at in our purlin noise space is no longer close to the value we looked at right here so we only want to increase the x position as we move along the columns and we need to reset the y position as well for the same reason for any given position in our room here we want the position next to it to have the same x and y value offset only by the increment but if we do that we get this cool result so i know this example is a little bit more complex but hopefully it helps show you how to control the values that you're passing into the purlin noise function and also why you need to do so [Music] the last thing to cover is a couple of traps with purlin noise the first trap is speed the purlin noise function is relatively speaking slow this room is 480 by 270. that is a total of 129 600 pixels and it has to run this algorithm for every pixel because we're drawing squares that are only one pixel wide now doing something 129 600 times isn't really that much for a computer but this algorithm itself is fairly complicated it's not just adding a number that many times it's running all of this code that many times and game maker studio 2 is single threaded so if i regenerate the room this is the actual amount of time that it takes to run through the double for loop for a room this size again very slow so if you're going to be using purlin noise for textures or large world generation it might be better to use a shader version which runs on the gpu rather than your cpu or use a pre-generated texture but if you're only going to be running it a couple hundred or even a couple of thousand times a frame it'll be fine the second trap is using integers the value returned by the perlino's function if all numbers passed into it are integers is always zero so if you pass in all integers you will always get zero regardless of what value those integers are and this by the way is why i don't have the default values as integers the final trap is that purlin noise is not a random distribution this may or may not be obvious but the values tend to be a bell curve around zero and the extremes are dependent upon how many dimensions you are checking again i don't fully understand the math and there's also some pretty conflicting answers online but the consensus seems to be that the range is negative square root of n over 4 to positive square root of n over 4 where n is the number of dimensions i haven't found this to be particularly relevant in my uses of perlin noise but it could matter for some things so i thought i would mention it here last but most importantly how do you actually get the perlin noise function that i'm using a link to the full project is down below so you can download and experiment with all of this code and a little bit more i didn't even cover how the sheep work but if you just want the function you can go to the github repo go to scripts and then purlin noise and then the gml file and then just copy this into your own script asset and there we go i'll be using perlin noise for a few different things down the road but for now if you have any questions feel free to ask them down below [Music] [Applause]
Info
Channel: SamSpadeGameDev
Views: 1,526
Rating: undefined out of 5
Keywords: gml, gms 2, coding, game maker, game maker studio, gms, 2.3, GameMaker Studio, yoyo games, tutorial, perlin noise, gradient noise, white noise, gamemaker studio, gamemaker
Id: ms1wczeXAT0
Channel Id: undefined
Length: 14min 1sec (841 seconds)
Published: Sat Sep 11 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.