Coding Challenge #24: Perlin Noise Flow Field

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello and welcome to another coding challenge in this coding challenge I'm going to program a visualization it looks just like this now for the thumbnail and I'm going to do it in p5.js using javascript in the browser what's running over here is an example that I made previously in processing which will give you a higher performance so at the end of this video perhaps we'll take a look at that very briefly so where I'm not going to start from scratch this video is really going to be built on top of this idea of two-dimensional Perlin noise if two demential Perlin noise is not familiar to you stop now go to the video description and go and find my series about Perlin noise and then come back okay hi you're back great ok let's get started so I'm going to start from this particular piece of code which generates this particular output so this is already an example with two-dimensional Perlin noise and each pick each each pixel gets a grayscale value according to two-dimensional Perlin noise but I want to do something different what I want to do is in the kind of grid of pixels right this is my very very low resolution grid of pixels instead of having a grayscale value for each pixel so to speak what I want to have is a vector I want to have an arrow pointing in some direction and I want that direction to to be a direction set according to Perlin noise because ultimately what I'm going to do is I'm just going to like pour a whole lot of particles into this area which known as a flow field this is known as a flow field and pour the particles in and they're going to follow the arrows and we'll see what happens ok so the first thing that I need to do is start revising the code to make vectors instead of pixels so let's take a look about how let's take a look at how that might work so I'm going to work with a very low resolution canvas just 200 by 200 just to kind of get things kind of started here and one thing that I also need to think about is a core variable here is I need to think about what is the ratio of kind of cell to width so I don't want to have an arrow for every pixel it's not going to be it's going to be unreasonable for me to have 200 instead of maybe a wanted vector every ten pixels or every 20 pixels so let's make that a variable called like scale I'm going to call it SC l short for scale I'm going to say that's 20 and then what I but I also need to have is columns and rows so I'm going to have the columns is going to be the width divided by scale and I better floor that floor something that gets rid of the decimal place and I'm going to say Rose is a height divided by scale so now what I want to do is I'm not dealing with pixels anymore so I can get rid of load pixels I can get rid of update pixels and in fact I can get rid of all this pixel array stuff but let's just see that things are working for a second so what I want to do is have Y now go through all of the rows and have X go through all the columns and what I want to do is draw I'm going to draw a rectangle I'm going to draw a rectangle at x times scale I got to scale up Y times scale and the size of that rectangle is scale and I'm just going to give it a random fill for right now and I want to see that I'm at least getting a grid of rectangles so if I run this okay so this is working so this is now going to be my grid now what I've done is I put a grayscale value a random grayscale value in every cell hey why don't we make that a random note a noise value just so just to get started here so let me now change this look I already have this year already have this noise function why not let's just make that fill based on that noise function and you can see okay so you can see right now that I'm not really because I'm so low resolution that these cells aren't these cells are kind of like very vent that almost the color is almost identical so one thing I'll do let's just try making the scale 10 you can see let's make the increment a little bit bigger there we go so now we're starting to see something that looks a little bit more like Perlin noise because and and what do thing I want to do also just while I'm working on this okay I think it would be useful to just keep an eye on the frame rate so I'm gonna do something a little bit goofy I'm going to make a variable called F our let's say fr equals create P so I'm making a paragraph element on the page and I'm going to say F our HTML frame rate and I'm going to floor that so this is a p5 function that just gives me back the frame rate I want to just see it as a paragraph element on the page so you can see the frame rate I'm right now everything's fine I'm running really fast like 60 frames per second so okay so this is my grid and I essentially have a grayscale value for every spot on the grid but that's not what I want what I want is a vector for every spot on the grid okay so one thing I could do is instead of saying fill let's at least right here create that a create a vector so what I'm going to do is I will say VAR v equals create vector now actually there's actually a function in p5 where you can create a vector from an angle p5 vector from angle and I'm going to create a vector from the angle 0 I now I now have a vector I've created a vector from an angle and what I want to do actually is instead of drawing a rectangle I'm going to say a stroke zero I'm going to draw that vector as a line so I'm going to say a push pop there's a bunch of different ways I could do this but I'm going to rotate by that vectors heading and then I'm going to draw a line from so I'm also I'm going to translate to x times x scale Y times scale and then I'm going to draw a line at that spot but that's a line oh I of that is sorry from 0 0 to scale 0 so what am I doing here what I'm doing is I'm saying for every single one of those vectors translate to this spot then draw a line but that's just a line like this and then rotate it according to rotate a according to the heading of that random vector the angle so to speak so now if I run this you can see look I have a whole lie whole bunch of lines pointing directly across now what if I were to say from angle pi divided by two now I have a whole lot of lines pointing down what if I were to say PI divided by six now I have a whole bunch of lines pointing that way we're getting somewhere right you see where I'm getting at because what I can do now is I could say what if I have a random angle between 0 and 2pi oh ok first of all I should probably clear the background so you can see now this is just a random vector for every spot in that grid every frame so one way I could stop it from like changing all the time as I could say a random seed 10 so if I reset the random seed you can see this is a whole bunch of random vectors now ultimately what I want to do is show you how to make this field of vectors this flow filled with noise values but I could I could come up with other ideas I could use sine waves I could I could get it data input I could get like wind data from various geo locations through some kind of like weather API and there's a great project which I've shown in other videos which does that but I'm going to just use Perlin noise so let's go back and say the angle is the noise value times 2 pi right so when I wanted to get a grayscale value between 0 and 255 I took the noise value times 255 now I want a random angle I want the noise value times 2 pi I don't need the random seed anymore from angle that particular angle and now you can see there we go so now I have this nice flow field essentially of all of these vectors kind of pointing similarly at each time i refresh I'm going to get a slightly different one now one thing you might notice is that I don't actually need to calculate this every time through draw because ultimately I don't need to calculate this every time through draw because ultimately it's staying the same I could calculate it once and set up and then refer back to it later however I think this might be a good time you and me okay we need to talk meet me over here at this other camera we need to talk actually never mind let's talk over here there is Pearlie noise I've shown you one dimensional Perla noise though I've shown you two dimensional Perlin noise I have yet to show you three dimensional noise Perla noise and in fact Perla noise can exist in any n dimensions but here is an opportunity where we might decide let's do something with three-dimensional Perla noise so the what one dimension is the x-axis another dimension is the y-axis imagine a Z dimension as slices these angles change as slices that I'm just like coming out of the screen well what if instead of actually building something visually in 3d that we thought of that third dimension is time every frame of animation what if I were to add as a global variable Z off and set that equal to 0 and then I were to say noise X off comma Y off comma Z off I've now said give me noise values in three-dimensional space so there's a noise value right here in three-dimensional space it's similar to all the values that surround it and so I'm looking at a slice of noise values then I want to present another slice of noise values they don't want to present another slice of noise values so those Z offset change every time through draw can you hear people laughing and talking in the background I don't know if you can and now whoa it's changing like crazy so I'm moving through time a little bit too quickly so let me move like quite a bit slower and that's when we move even slower so you can see now I have a flow field that's actually changing over time and you can imagine lots that I could do just with this much but ultimately what I want to do if you recall and we can sort of see this crazy sketch now is like really just like filled over itself a zillion times but what I'm trying to do is recreate this particular visual so what's happening in this particular visual is that particles are being dropped on top of this flow field and following those arrows so this is the first thing that we need to do now I just realized we have a bit of a problem small crisis of conscience here which is that if I want to drop a particle on there I need like a whole like physics engine and to move the particle around and all that and I kind of want to just go and grab now let's make it we can do this really fast this is a coding challenge I'm going to to add the particle object from scratch here so what I'm going to do is I'm going to make a new file I'm going to call it ooh particle J s and I'm going to use a JavaScript constructor function and my particle needs to have a position which I'm just just make it 0 0 it needs to have a velocity which is going to be an 0 0 vector and it needs to have an acceleration I'm going to write an update function where the position gets added the velocity and the velocity the acceleration gets added to the position if you're confused about how these physics engine works go and walk all of my nature of code videos on physics engines and then I'm also going to reset the acceleration to zero by multiplying the vector by zero then I'm going to write an apply force function which is a function it receives a force and what do I want to do with that force I just want to add it to the acceleration so this is actually all I need well this is so easy and then I just needed just a show function whoops that's I wrote that incorrectly equals function then I want to show function which what does it Drew do it draws the particle so what should I draw it us let's just draw it as a point for right now we're going to say stroke zero point this stop position dot X this stop position dot Y so this is nice I have this really simple particle object it has position velocity acceleration and has a little update method to update its velocity based on acceleration to update its position based on the velocity and then as an apply force function to accumulate any forces into the acceleration so now I just need to make sure that my index.html file references that new particle J s file and let's just very very quickly make a particle array and in the particle array I'm going to say particle index 0 equals a new particle just but I've lost my train of thought here a new particle oh yeah new particle and then I want to say a here particle index 0 dot a show sorry and dot a update and let's just see ok what's missing couldn't find particle J s because I typed that in wrong I said particles j s whereas the file is called particle J s and now particle is not defined what's a particles and this is also very confusing here the array is called particles there we go so you can see there's that particle up there in the corner so I have one single particle that's good now what I want to do is add a whole bunch of particles so let me make this a for loop is less than 100 let's add 100 particles and just say particles index I and then let's write another for loop iterating over the entire length of the array and having each particle okay so now particle pipes something wrong particles okay there should be a hundred particles there let's make sure all the particles are everywhere let's let's give the particles random positions to start so you can see there's 100 particles around randomly and then just to make sure they're like doing something let's say P vector R ep5 vector dot random so this gives them all a random velocity okay so the particles are moving around with a random velocity they're doing something okay one thing I need to do I just realize is that I need to have the particles wrap around when they get to an edge they should come back on the screen so I need to let me add that really quickly so I'm just going to add a function called edges and I'm going to say if this dot pause X is greater than with this dot Paz dot dot dot x equals zero and I'm going to do this in a kind of short handy way and I'm going to say less than zero should equal width and then I want this again but I want to do it with Y and I want this to be height and I want to do this then needs to be Y and this should also be height so I now have a new edges function and I can quickly also say you know wrap them around the edges here so now we should see I have a whole lot of particles moving around forever and ever and ever and let's not render the vectors for a second okay so now I have a window with a lot of particles moving around but I want those particles now to be affected by the actual vectors in the flow field itself so how do I do that okay this is that this is the crux of this project so first thing I want to do is I want to actually say I'm gonna give these like quite a bit of alpha so let's see if so you can see that I can see it's slowing down quite a bit but I'm drawing the vectors but you can see the particles are not moving anywhere according to the vectors I also just while we get started I'm going to take off Z offset to see now this oh whoa do I not hit save yep so now I want to make sure this works with a fixed flow field and with the particles I also just so we see them a little bit better I'm going to say stroke wait for to make them a little bit thicker okay oh boy but I don't want my vectors to have that stroke wait so I'm going to say stroke wait one okay so now we can see the particles moving and the flow field kind of behind it so what I want to do is say for every particles location look up the vector that's nearest to it and then apply that as a force so here's the thing the of all of the vectors are calculated up here so what I want to do is actually store all of those in an array so I'm going to make a variable called flow field which is an array and that that array should have as many spots as there are columns and rows so now what I want to do is say flow field equals a new array yeah this is a weird thing to do in JavaScript but I'll do it anyway you know you can actually preset the size of an array by saying new array and maybe that was a bit unnecessary but I'm going to do that anyway and then and then what I'm going to do here is I actually already have perfectly the calculation this was left over from my pixel example this should be columns and this should be not be x for anymore because I don't have RGB values I have a single single value I can now say flow field index index equals that particular vector so now all of these vectors that I'm calculating are now stored in that particular array so now what I need to do down here is say I'm going to say particles index I and I'm going to write a function called follow and I'm going to pass in that flow field so what I'm doing is I'm saying hey you particles here's an array of vectors each particle is responsible for finding the appropriate vector in that array to look up so for example just to come back to this diagram I'm a particle right let me get by actually it's fine to use I'm a particle right here my position might be like 300 by 200 and maybe these are 100 by 200 I need to first divide by scale to look up the appropriate index into that array find the vector and then apply it as a force let's see how that works so if I go to the particle function I'm going to write a new particle object the constructor function I'm going to write a function called follow equals a function I'm going to just call this vectors and now what I'm going to do is I'm going to say x equals floor this top position dot X divided by scale so I need to take remember its exposition is this actual place on the screen and but it's corresponding position in the grid I have to scale down by that scale variable its y-value is do that with y then the index is X is X plus y times columns this is that formula for how you take a two-dimensional value into a one dimensional array and I cover that in some other videos which I'll try to link to in this one and then now I should say the force is that array of vectors at that index and I should be able say this dot apply force that force so now essentially what I'm doing is I'm saying based on my me I'm a particle based on my X Y position scale myself to a grid of column in rows then look up the corresponding vector in that one dimensional array and then take that vector and apply it as a force so let's now actually have the velocity start at zero and let's see if this works and I'm sure I miss something but let's give it a try oh okay that's kind of working but you can see excuse me that they're spiraling out of control in terms of speed so one thing I should think about is okay you know I should think about one thing I should really think about sorry is what is what is the magnitude of these vectors so maybe these vectors I need to set their magnitude to something much smaller like 0.1 they shouldn't really be that strong like a full a full a unit full and you can see that now but you can see there's still like really speeding up over time that's because this acceleration is just building up and pushing and pushing there's no limits to how fast these particular vet these particular particles can go so I think something I could do here which would make sense would be to have a like a maximum speed variable and set that equal to like four and then in the update function I could just say this dot velocity dot limit this maximum speed so now I'm just saying the particles actually you know no matter how much you start pushing them they do have a altima maximum speed and now we should see that the particles are following this flow field and you know maybe they're not following it you know you know and I could kind of control what that now I could go back and I could say well actually maybe I want the magnitude to be five and you can see when the magnitude is five they're going to be lockstep exactly with the flow field so you can see what the magnitude of that force is really controls how exactly are in terms of following this path and by the way let's add the Z offset back in so those vectors change over time and you can see now what we're kind of getting we've got these particles following a flow field but that flow field is changing over time reasonably I've still got 30 frames per second I'm going to do a couple more things one is let's add some more particles let's have Z change a little bit more slowly something like this and let's see how we're doing so now I have a lot more particles but it is running rather slow so one thing I could do here hopefully to get it to run quite a bit faster is I can actually just not bother to draw the vectors the data for the vectors is still calculated and exists but I could still I could skip drawing them and you can see now I'm getting a nice 60 frames per second it's really getting stuck at the top and the bottom that vector force is really quite strong so I'm trying to I set the magnitude to 5 let's set it to like 1 and actually I'm going to set it to 0.05 anyway you could play with this year and I could also one thing that I could really think about is well do I want the full maybe I want the vectors actually to be to have more variety to them they're all is generally always pointing to the left because remember I'm picking random values between 0 and PI and they cluster around the middle so I'm not picking random so like I could say times 2 pi times 4 and now I'm going to get a lot more sort of like noisiness but there's a lot of different ways and it's all moving like kind of too fast and I I should create some sliders and I could kind of like really control this stuff a little bit more strongly so you can think this is kind of this is more when I was trying to get so I have a sort of stronger flow field but there's a lot more variety in terms of where the particles go now I could add some separation so they don't get on top of each other as much but you get the idea here now what this I basically have all the way done I now have this flow field where I can drop particles in it and I could you know I could sort of push the performance here and say like well what if I try to drop you know 500 particles in you can see it's running a little bit slower but I've got more stuff happening but what if instead of drawing the particles as dots what if I drew that what if I allowed them to blend their alpha to be sort of like alpha blended across the screen for a while so let me to kind of create that visualization so really now one thing if I were you I would stop this video and just go to this show function and play make rainbow colors to add alpha values but let me do a couple things to try to get that effect so one thing I'm going to return the stroke weight back to one and I'm going to give it quite a bit of alpha and in the sketch I'm also going to draw the background now only once in setup so let's see what we get here with this so now you can start to see what I'm getting here I'm getting this kind of nice alpha blending pattern now if I were to zoom into this you can see there's actually like the particles move faster than one pixel per frame so they're actually skipping pixels so something that could actually be quite useful here would be to have each particle store at the very least a previous position which I'm going to say is a to start with is a copy of its original position so it when it starts it has its current position in its previous position and then every time it moves right after update it's actually let's do this every time after we so what I want to do is actually not draw a point but I'd want to draw a line from its current position and I know that camera just went off because that means a half an hour has passed to its previous position this previous position dot why now if I whoops ah I'm in the wrong place if I run this again okay there's a couple issues number one is oh my goodness what is going on there's some crazy extra lines so we have a problem right if I'm always taking a particle and drawing the line between its fruit not its position its previous position when it leaves its previous position is here its new position is here suddenly this line goes all the way across so I want to add an extra check in here just to correct that there might be like a better way of doing this and actually what I could do is I could just update it in this edges function which actually let me do that this is different than how I did in my other example but what I'm going to do in this edge is function is I have to add write if any of these are true what I need to do is say what I want to say this stop previous previous position dot x equals this stop position dot X so I'm going to I'm going to write a function this dot update previous is a function which just does this algorithm in it whoops X so so any time it hits the edge I'm going to just update the previous so this is like an extra time and I need to make sure I do this then right before I draw it so I actually want to have edges right before show so it gets updated and then what I so this should correct that problem so now you can see oh look at that okay so it's actually kind of doing something interesting I never update the previous position so it's actually drawing a line from where it started to its current position so let me actually add the most crucial part here which is that I also want to every time after I draw it to say this dot update previous so after I draw it the previous position comes the current position and now you can see what this is doing I'm getting nice continuous lines actually see those continuous lines what did I miss here uh hold on i time out I get a debug okay i back i didn't actually need to debug anything it is working so you can see I've basically gotten the gist by programming from scratch of this particular example now there's a bunch of few things that are different number one is in this larger version one size I've got kind of higher resolution going on one thing that I think you probably would notice is this is running reasonably at 30 frames per second but if I were to go back and try to add you know to make this run over like a much larger canvas and have something like 2500 particles you're going to see that right currently it's running at like 4 or 5 frames per second whereas this processing version which I will pull up right now this processing has 10,000 particles and it's for whatever reason it's 1200 by 800 now let's look at let's and actually I'm going to render this with in the P 2d renderer which uses OpenGL hardware acceleration I'm going to print the frame rate just to the console and take a look at that come alive come alive processing so we can see that this is actually running over 50 frames per second and once again again I may point out there are 10,000 particles and I'm that kind of high resolution whereas here I have you know only 1500 and then not as high resolution it's running really really slow so what I would need to do to like pull the most performance out of the web browser would be to probably render this somehow with WebGL and a kind of hardware accelerated way which maybe I'll continue and look at at some point but hopefully this video gives you the basic idea and what I would love to see and I'm just going to let you know what I'd love to see you do is first I'll make this like rainbow-colored try playing with the various parameters try rendering in a different way see what kind of quality you can get can you make you know large scale prints out of it go and look at the processing version there's a variety of things that you can look at and try to expand upon this maybe you can make a bunch of sliders to change different parameters and that sort of thing so I hope you enjoyed this particular coding challenge it was a little bit long a little bit scattered if you liked it like the video say it in the comments let me know on Twitter at Schiffman and I look forward to seeing you in another coding challenge soon enough thanks for watching bye
Info
Channel: The Coding Train
Views: 281,186
Rating: undefined out of 5
Keywords: noise, perlin, series, perlin noise, terrain, tutorial, terrain generation, procedural generation, 2d perlin noise, perlin noise processing, nature of code, processing perlin noise, p5.js, p5js, p5.js tutorial, p5js noise, p5js perlin noise, flow fields, perlin noise flow field, noise(), random(), randomness, coding, flow, creative coding, coding challenge, javascript, javascript (programming language)
Id: BjoM9oKOAKY
Channel Id: undefined
Length: 33min 34sec (2014 seconds)
Published: Mon Jun 27 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.