Procedural Landmass Generation (E02: Noise Map)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Transcribed by tymewiz] Hi everyone welcome to episode 02. So today we are going to begin programming our noise map generation we are going to be using perlin noise for this series since unity provides a built-in implementation in their maths class one thing to take note of with perlin noise however is that at integral coordinates we are always going to get the same value this isn't going to pose a problem, but it is good just to be aware of it alright, so in this new unity project, let's head over to the scripts folder and let's create a new c# script called Noise so if we just open this up we're not going to need to apply this to any object in our scene so we have no reason to inherit from monobehavior also we are not going to want to make multiple instances of this script so we can just go ahead and make it static alright, so we want this to have a method for generating a noise map and we want that to return essentially a grid of values between 0 and 1 so let's create a public static method returning a 2-D array of float values and we can call this method GenerateNoiseMap so ultimately its going to have a whole bunch of arguments including the lacunarity and persistence values we talked about last episode but for now let's just define the map dimensions as an int for the mapwidth and another int for the mapheight so we can now create our 2-D float array called our noisemap set that equal to a new 2-D float array with a size of mapwidth by mapheight and well want to loop through that noisemap so we'll say for int y = 0, y less than mapheight, y ++ and similarly for the x value for int x = 0, x less than mapwidth, x++ so now we want to figure out at which point we'll be sampling our height values from so let's say float sampleX let's just set this equal to x for now and then float sampleY we can set to y of course we don't want to just use these integer values since as I mentioned earlier that will give us the same value every time so let's introduce a new argument, a float for the scale of the noise and we can just divide x by scale and also y by scale so we can get some nice non-integer values now of course we have to be careful that if scale is 0 we are going to get a division by 0 error so let's just handle that case by saying if the scale is less than or equal to 0 then we can just clamp it to a minimum value of, say, 0.001 alright so now that we have our sample coordinates we can say float perlinvalue is equal to mathf.perlin and we'll pass in sampleX and sampleY we just need to now apply that to our noisemap so we can say noisemap, with coordinates x and y is equal to that perlin value finally of course we just need to return the noisemap that we just created now obviously there is a lot more work we need to do on our GenerateNoiseMap method but i'd first like to get it drawn onto the screen so that we can sort of visualize what we are working with so let's head back to unity and we are gonna create another c# script this one called mapgenerator and I want to apply that to an object in the scene so let's create a new empty and just call this mapgenerator as well just reset that so it's in the center of the scene and apply the mapgenerator script to it so in here we want to have a bunch of values defining our map such as later on lacunarity and persistence but for now just public int mapwidth public int mapheight and also that float for the noise scale alright then we want to have a public void, call this generatemap and what it'll start out by doing is just fetching the 2-D noisemap from the noise class so we can say 2-D float array call this noisemap, is equal to noise.GenerateNoiseMap and we can pass in all these parameters mapwidth, mapheight, and noise scale so later on of course we'll have a bunch of stuff over here to process this noisemap and turn it into our terrain map but for now we just want to pass it along to our mapdisplay class so that it can draw this noisemap to the screen so let's go back to unity and create this mapdisplay class that i've been talking about so let's call this mapdisplay and we can apply that to the mapgenerator object in our scene as well so this is just going to take the noisemap and turn it into a texture and then its going to apply that texture to a plane in our scene so let's create a new plane gameobject and I'm just going to reset that so it's in the center we can just remove the collider and let's now go to our mapdisplay so we're going to want a reference to the renderer of that plane so we can just set its texture so let's say public renderer, call that our texture renderer and then we are going to want to have a public method called something like drawnoisemap which takes in that 2-D float array for the noise map and what we'll first want to do is figure out the width and height of the noisemap that we've been given so we can do this by saying int width equals noisemap.getlength 0 for the first dimension and then int height = noisemap.getlength 1 for the second dimension now we can create our 2-D texture by saying texture2D, just call this texture is equal to a new 2-d texture with a width of width and, you guessed it, a height of height so we now want to go ahead and set the color of each of the pixels in this texture so one way to do that is to say texture.setpixel and then we can pass in a x and y coordinate as well as a color but it turns out it's faster to first generate an array of all of the colors for all of the pixels and then to set them all at once like so so we'll chose that method instead so let's create a color array, call this our colormap, set that equal to a new color array with a size of width multiplied by height and then we'll want to loop through all of the values in our noisemap so we can just say for in y = 0, y less than height, y++ once again same thing for x for in x = 0, x less than width, x incrementing by 1 each time we now want to set colormap we need to of course figure out the index for the colormap remember that the colormap is a 1-dimensional array whereas our noisemap is a 2-dimensional array so we can get the index by first multiplying y by the width of the map so that will give us the index of the sort of row that we are currently on and to get the column we of course just add the x value so we want to set this equal to a color somewhere between black and white, depending on the value of the noisemap at that point so we can say color.lerp, from color a equals color.black to color b equals color.white and then we give it a percentage between 0 and 1, which is the same range as our noisemap, which is convenient so we just say noisemap, with an index of x and y ok so we want to apply those colors to our texture so we say texture.setpixels. pass in the colormap and then just apply everything we've done by saying texture.apply ok so now we'll want to apply the texture to the texture renderer one thing to note is that we dont want to always have to enter game mode in order to preview our maps it would be much nicer if we could generate them inside of the editor so that means we can use texturerenderer.material since that is only instantiated at runtime so instead we use sharedmaterial so we can set the sharedmaterials maintexture equal to the texture we've just generated it'd also be nice to set the size of the plane to the same size as the map so we can just say texturerenderer.transform.localscale is equal to a new vector3 with an x size of width, a y size of 1, and a z size of height alright, let's save that and let's go into the mapgenerator class so we can call the mapdisplay with our noisemap so we need to get a reference to the mapdisplay of course so let's just say mapdisplay, call that display, is equal to find objectoftype mapdisplay and then we can say mapdisplay.drawnoisemap and just pass in the noisemap alright, let's go back into unity, and let's apply the plane to here and let's also create a material for this plane im gonna create a new folder, to store materials in and ill just create a new one over here, just call this, something like, map material and im gonna set this equal to a unlit texture shader, since we dont have a light in our scene currently and im just gonna apply that over here so at the moment there is no way for the mapgenerators' generate map method to be called so what we're going to do is create a editor script that will have a little button over here to generate the map within the editor so let's create an editor folder and inside of that we'll create a new c# script and we can call this something like mapgeneratoreditor alright, let's open that up and we'll start off by saying using unityeditor and then we'll extend from editor instead of monobehavior and we can delete all of this stuff and instead just override the oninspectorgui method ok, so let's start off by getting a reference to our mapgenerator so we can do that by saying mapgenerator, just call that mapgen is equal to target, which is the object that this custom editor is inspecting and we just want to cast that object to a mapgenerator so we can just add in brackets before it map generator like so alright, so let's draw the default inspector so we can just say draw default inspector and then we want to add in a button and we'll say if that button is pressed so the button is guilayout.button with some text, say just generate if that button is pressed we'll say mapgen.generatemap() ok, so let's go into unity and we want to make sure that our map has a width and a height otherwise the texture is going to break and potentially crash unity, that's happened to me once or twice so let's give this a width of 10 and a height of 10 and a noisescale of, say .3 the button isnt actually showing up at the moment, which is just a little something I forgot, we need say over here that this is a custom editor and we have to say that the type of class that it is a custom editor of is the mapgenerator class ok so now we should see that generate button popping up so if we press generate we now get this nice perlin map let's increase the size to 100 by 100 let's perhaps add in an option for the map generator to autoupdate whenever we change one of these values so let's create a public bool in the mapgenerator class public bool autoupdate and what the map generator editor will do is it'll say if draw defaultinspector, which just means if any value was changed then.. if mapgen.autoupdate, then we'll also generate the map if we turn on autoupdate and increase the scale we should see that automatically updating I'm going to end here for this episode, I hope you've enjoyed, and until next time... Cheers!
Info
Channel: Sebastian Lague
Views: 444,989
Rating: undefined out of 5
Keywords: procedural generation, proc gen, perlin noise, world, procedural, terrain, random, Unity (Software), Unity 5
Id: WP-Bm65Q-1Y
Channel Id: undefined
Length: 15min 14sec (914 seconds)
Published: Sat Feb 06 2016
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.