Coding Challenge #11: 3D Terrain Generation with Perlin Noise in Processing

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello welcome to another coding challenge with me Dan I don't know if you know my name maybe you don't I'm here to program this particular simulation from scratch so what this is is kind of like an infinite procedurally generated terrain it looks like you're flying over it so I'm going to use the processing programming environment so Java based environment you can get it at processing.org check the links for various things you might need in the description of this video but without further ado I gotta get right I'm gonna get started okay so I'm going to close this out so what do I need so first of all I have a sketch setup I've got set up and I've got draw a size and background that's the only thing so I've got this blank canvas right now and notice in setup i'm also using p 3d because i need a 3d environment so what I need before I can really do anything is I need to make the terrain itself as just like a flat grid so how does that work basically I could draw a giant rectangle and that would be my terrain but instead of drawing a giant rectangle what I want to draw is a lot of tiny rectangles next to each other and I'm saying rectangle and I guess I really means square like this because I want my terrain to be lots and lots of shapes all attached to each other and next to each other and in fact a good way to do this in 3d is to choose something called a triangle strip triangle strip you know what this means is I can say vertex vertex vertex vertex vertex vertex vertex vertex over and over again and what the computer is going to do is connect all these vertices with triangles triangular polygons and all connected together you'll see this appearance of a mesh and then what I'm going to do is once I have this mesh is I'm going to take each point as this where my screen right this flat white board is my screen I'm going to extrude some of them pull them out some of them are going to get pulled higher some learn get pulled lower so it has a mountainous light quality so before I can get that part though I just need this triangular mesh to appear in the window so let's first make that happen so the way to make that happen is I need to have a nested loop right for every single point on this grid so I'm going to start with X equals zero X X is less than and I'm going to need to have know how many columns and how many rows so I'm going to say X is less than columns and then I'm going to say y equals zero Y is less than rows okay so now columns and rows don't exist as variables so I'm going to add them columns rows and what I'm going to do is also need to figure out a good variable that I'm going to need is how big is each of these squares how many pixels wide how many pixels high and it'll be the same number let's make that 20 so I'm going to add another variable I've got this time ago I'm doing this for two months see how long this takes so hopefully not more than 30 minutes I'm going to make a variable called SEL kind of standing for scale and uh I'm going to set that equal to 20 I'm really keeping an eye on my audio to make sure the audio doesn't cut out okay uh okay so now what am i doing okay so first just to make sure things are working what I'm going to do is I'm going to have some sort of arbitrary width and height and I'm going to make those the same as the window just for now it's going to change later I'm just sort of being simple about things and then I'm going to the number of columns is the width of the width of my grid divided by that scale and the number of rows is the height of my grid divided by that scale and just to make sure things are working let's just draw a rectangle a rectangle at where x times scale Y times scale and at that size and I'm going to say stroke 255 and no fill so what I should have so far if things are working right is a perfect grid so this is a good sign I now have this grid but I can't draw it as rectangles - yeah I could but to manipulate it to make it a terrain to make it all bumpy I want these to be triangles a triangle strips so I'm going to change what I'm doing and I'm gonna say now let's think about this hmm my triangle so now I could have my triangles go down but mentally it's just easier for me me to think of everything as Rose so I want to do the top row next row next row next row next or a next row of triangles so I need the outer loop to be why because first start with why do all the X's go to the next why do all the X's so I realize I want to take this Y rose and put this as the outer loop and then what I need to do is for every each row will be its own triangle strip so by the way where is this coming from I'm going to go to processing org under reference and under begin shape I know I'm going to zoom in here see so what I'm doing is I'm using begin shape and end shape which allows you to set a bunch of vertices and you get a shape but if I scroll down this is really what I want I want this triangle strip so I want to send all set set a whole bunch of vertices and have it all connected magically with triangles okay so now I should be able to if I go back to the code say a for every single row begin shape and then n shape and of course I don't want to just say generic begin shape I want to say begin shape and what I'm intending to make is a triangle strip and then instead of making rectangles what I need what I what I what I want to do is just set and I'm going to set this up here the stroke and fill outside just to instead of drawing rectangles what I want to do is set vertices so the first verda vertex is going to be at x times scale y time scale and it's going across so if I were to just run this right now I should I'm just getting these lines across because I didn't actually make the triangles what I need to do is create the vertices like this what I just did was set vertices like this vertex vertex vertex vertex vertex vertex I need to do vert up down up down up down up down up down so I need to do y and y plus one for each loop so how do I do that I just all I need to do is add another vertex Y plus one time scale there we go this should work please work there we go so now you can see I have this beautiful mesh of triangles so this is the building block from which I can that I can manipulate now it doesn't look very 3d I've done everything in 2d right now so let's at least take a moment to rotate it on an axis so if I if I right now you're seeing where's a prop this is my Kleenex you're seeing this and it's just flat facing you I want to rotate it like this so it looks like you're flying over it so to do that we want to rotate along what axis this is the x axis I want to rotate along this x axis so I'm going to say right here rotate X and like pi divided by three which is like 180 60 degrees so if I run this where did it go so we've got some problems here the issue is I've drawn everything relative to the top left so if everything's drawn relative to the top left everything is rotating around the top left and I've just rotated it completely out of view so what I need to do is have everything drawn relative to the centre of the window so I should translate to the centre look there it is and I can see it now I can see this plane that I might be traveling over but it's shifted off in to the right it's because zero zero is in the center which is what I want but the triangles start at zero zero so remember I have this variable and this should I'm going to make these global variables W and H I want every single triangle to be like offset back by that width divided by two so if I go back to here I can I wonder if I could probably actually just do a whole nother translation let's just do another translation of negative width after I rotate with divided by two negative height divided by two I think that will do the trick and there we go so this is what I want I now have this almost infinite it's not infinite but I have this terrain of triangles that is on an angle map look at this I'm only at eight minutes this could possibly be be done in 12 I should never say how long that's going to take because it's only going to take longer but we're doing really well now what is what do I need to do here well I've really gotten super far the only thing I need to do is take one of those and like pull some of the vertices for vertices up so let's just do something goofy like let's make all of them random so how do I pull them up well each vertex only has an X and a Y right remember this is this is the mesh that I'm drawing it's exactly this but just turns on its side but if I want to take this point and pull it up a little bit so I want to turn on its side it looks like it's going up along the y axis it's really changing the Z the Z value the Z value for all of those vertices has been 0 all along so let's go now and say what if I were to do like random negative 100 100 for all the Z values what's going to happen here let's run this and see look at that ok well what I you see it's kind of going crazy let's 100 I guess was too much let's make it ran between negative 10 and 10 let's run it again there you can see that I now have this mesh and I know maybe I'll make the framerate rate 1 so you can kind of like just sort of catch it for a second is it running yet whoops that didn't happen hey is framerate broken in whoo look at that I wonder if framerate is broken in P 3d that's really weird I don't know why that's not working I'm gonna have to investigate that and maybe file a bug report so but anyway that's neither here to there the point of what you're seeing is this now has this quality of a terrain because each point is higher or lower now the issue is I need to have some consistent way of doing this so I think what would be useful is for me to have a data structure that stores all the Z values right the the x and y values the x and y values well let me just knock over a light the x and y values and I'm probably gonna have everything messed up now the X&Y about physical comedy or that's not really comedies just physical miss apps the X and y values are fixed they're never going to change the Z values however might change there's some sort of variable calculated procedural some algorithm has to generate those Z values so I need another data structure to keep track of all those Z values and what I think I would to do is use a two-dimensional array a two-dimensional array would allow me to store for every single spot here some Z value calculated according to some to some algorithm so let's go back and I'm going to come back to here and I'm going to say and I'm going to make these floating point values so this is a two dimension processing how I define a two dimensional array and I'm going to call it I don't know what to call it a landscape terrain I'll call it terrain is a new and you know what I need the two-dimensional array to have cut that have the number of spots as the number of column and rows so I want to actually initialize it after I calculate the columns and rows and so a two-dimensional array with this many columns and this many rows now what can I do but I can actually in setup right now I could just say I equals I'll so use the X again X and you know I just need this exact sorry same nested loop and instead of drawing anything what I'm doing here is I'm saying terrain index X index y equals some random value there we go so now I'm picking a random set of values in setup and then here instead of drawing them as random I'm going to say get those Z values I want the Z value at X Y and then what do I want here I want the Z value at X Y plus 1 remember I'm doing vertex vertex vertex vertex so I need those Z values at Y and y plus 1 so now if I run this we should see whoops I got an error array out of bounds exception oh ok so of course I got an array out of bounds exception because I'm doing every single row and the row below it and when I get to the bottom there's no row below it so I need to say rows minus 1 for this loop I can only go to the second-to-last row so now if I run this again we should have there we go so now you can see I've got the terrain and it doesn't it you can see that it's not like a terrain that's filling my view but that's sort of an easy problem to solve because you know I have that's why I have these variables here I can say well let's just make it much wider and much longer and now I have my terrain filling my view so how do I make it look though like I'm flying over it and have it appear infinite tricky question well here's a way to do it there's a bunch of different strategies and maybe I'll make another video that picks up right from here to do different ways but I'm going to use something you can see this random terrain is not so great like it doesn't really look very much like a mountainous like quality what I want is something that's more organic fractal like nature like so to speak and what I could do is use something called Perlin noise so let's I have a separate video which I think I'd go over probably noise that I'll link to but I'm gonna just briefly discuss what how Perlin noise would work in this context and I am I don't know what time I'm at but I'm gonna keep going okay so purling noise purling noise is a way of getting smooth random numbers meaning random numbers if I think of random numbers in one dimension random numbers that I might ask for over time that are similar to the one I picked before it so if I want to get kind of a hole if I wanted to move something around the screen kind of fluidly I could use Perlin noise to pick its location but what I want to do is actually use two-dimensional Perlin noise meaning think of a space of numbers in two dimensions so if I have a checkerboard and I were just to pick a random number between 0 and 10 or between negative and 10 for every spot in the checkerboard I would get exactly this every single spot on this board is a random terrain value but that's not what I want what I want is to pick a Z value for here and then I want all the values around it to be somewhat similar to it and then for this one I want all the values around it to be somewhat similar to it so as things move up and down they move up and down smoothly so I think this probably merits a longer discussion about Perlin noise I'll refer you to my other video and ask questions the comments and maybe I'll make one that demonstrates this more specifically maybe video just about this idea but I'm going to kind of move on from that that being the sort of conceptual idea now how does it work if I call the noise function in processing there is a noise function in processing noise the word noise really means randomness like audio noise but random in processing means randomness noise means Perlin noise named for Ken Perlin who invented this particular algorithm now noise if I give it two nodes whenever I call the note by behind the scenes when you start processing it's almost as if this infinite plane of numbers was created in two dimensions with noise values available to you and you can give it any particular X Y value and get a particular noise value and this function will always give you a value between 0 and 1 so actually something that I can just do right now it's going to look a little bit weird if I could just go in here and I can say here instead of using random what I want to do is use the noise function and just give me a noise value for every X and y and then I also want to map the noise value which goes between 0 and 1 to some value between like negative 100 100 so let's run this now and see what I get so this is starting to look a little bit better and you know I could I'm going to just make it a little less tall this is starting to look a little bit better maybe there is a slight more consistency to this but it's still pretty random and the reason why it's still pretty random is that the numbers that I picked right I'm asking for noise at 0-0 and then I'm asking for noise at 1 comma 0 then noise at 2 comma 0 you know down here I'm asking for noise at 2 comma 1 I'm making a big leap into the noise space with these whole integer numbers and actually the noise algorithm wants you to use small gradations so the actual pixel X Y values doesn't really work very well for to act to be the values that are passed into the noise function so the way I'm going to do that instead is by creating my own variable I'm going to say X offset a float starting at zero and that should actually go in here and I'm going to say Y offset as a float starting at zero X offset Y offset and then I'm going to use those values for the noise function as the things are going to pass through and then I don't have to live with the X is zero plus one plus one plus one I can increment those separately so here I can say something like X offset splut equals zero point zero point zero one and that's what I want to do inside this loop and then after that loop for every Y I want to increase that by zero point zero one so we can see now that my values whoa so what Cameron went off you can see now that my noise is much too smooth I move I'm moving so slowly my gradations within the noise noise space are so small that the actual terrain is very very flat so let's change that to like point one and point one and see how that does much better you can start to see I have this sort of smooth smooth mountainous region now we're really getting something this is much better and maybe I could increase this now to sort of make some of the mountains a little bit higher you can see wow that's pretty good too and I could also even go through it faster and maybe shrink this down to one hundred you know III have a problem where I tend to play with like values forever but you can start it you can see now that we're getting something much more like actual terrain because I have these smooth random values so now I've got this terrain that appears somewhat infinite like I'm flying over it but I'm not moving over it well here's the kind of amazing thing so I could start going down the road of like camera work and translation and then like adding to the end of it as I'm flying over it but with Perlin noise there's a really really quick trick that I can do let's think about how this might work all right remember this is my flat terrain and I have the noise values so the noise values are getting picked based on based on X off which are the values along the x axis and y off which are the values along the x axis what if my x offset values never change what I want to fly this way right I want to fly over it I want to fly along the y-axis why off always starts at zero what if where why starts just changed a little bit each time so that the top the what I'm seeing far off in the distance starts to appear as if it's moving close so nothing's actually moving I'm just adjusting the noise I'm moving the noise space along where I'm starting and though that that two-dimensional plane of noise so if I come back here now I've got to recalculate this in draw so I've got to take this whole loop in draw I'll just put it at the beginning and I'm going to run it so it looks the same now all I need to do is say okay this value needs to change not start at zero every single time so I need another I'm going to create a variable called flying and it's going to be zero and I'm going to have Y offset start at flying and in every cycle through draw flying is going to increase a little bit but I'm flying backwards so let's have flying decrease a little bit and now I'm flying forwards although it almost looks like I'm flying it looks just like it's undulating but I would pretty sure if I make this a lot faster it's going to appear much more like I'm flying so you can see there's some goofiness happening in the background a kind of a nice effect I probably if I extend it how much I'm drawing further out for example if I made this like 1,600 and you know I could also think about translating a little bit down so that it's a little bit lower I think plus 50 would do that you know now I need to make it wider if I'm extending it further I gotta stop tinkering with this I'll let you tinker this would tinker tinker tinker with this yourself but changing the you can sort of see now that it's almost as if I there's a curved world and the mountains are like pump appearing over so I think if you play with the values to play play with the positioning play with the rotation you can and also of course play with the color you don't have to draw this as a mesh you can do a variety of things with this so I'm hoping this helps you understand a little bit a about how 3d works and 3d shapes works a little bit more about Perlin noise and also just sort of some creative exploration for what you might be able to do with this and what types of projects you might be able to make so thanks for I'm just checking to see if the audio is still working and I had a panic moment where it was it but thank you for watching this was about 22 minutes and I think I made this example 22 minutes which I'm very pleased about okay and I'll see you soon talk to you later bye bye
Info
Channel: The Coding Train
Views: 796,635
Rating: 4.9636617 out of 5
Keywords: processing perlin noise, perlin noise, perlin, terrain generation, coding challenge, processing, noise, challenge, procedural, random, game, tutorial, terrain, procedural terrain, procedural generation, programming, coding, daniel shiffman, nature of code, processing 3, generation, creative coding, programming challenge, learning processing, processing (programming language), p3d processing, p3d, 2d perlin noise, 3d, processing tutorial, perlin noise processing, terrain perlin noise
Id: IKB1hWWedMk
Channel Id: undefined
Length: 22min 43sec (1363 seconds)
Published: Wed May 04 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.