[Unity] Voxel terrain generation - 5 - Noise (Part 1) - Grass LayersteemCreated with Sketch.

in indiedev •  6 years ago  (edited)

 

Now, we have chunks, inter chunk detection, UVs and a Database. We are ready to add noise to the Chunk and give a real shape to the terrain.

To do that, we will use Perlin Noise.

It looks like this :

Each pixel has a value which is more or less black (or white).

This value is the height of a block and the Perlin Noise is like a map of the world.

Let's take a random position in the noise. Around this position, values are getting more and more white, the height of the blocks goes down like a mountain.

And it's value is given between 0 and 1. 


 - So, this is what it looks like sideways : 

It is composed of :

- Octaves : The number of waves. Adding waves together gives a more realistic terrain.

- Frequency : Or increment, is the distance between each peak. It gives a sharp or flat terrain.

- Amplitude : The height of the waves.


 - Now, the same in a 3D environment : 

 Let's talk about Brownian motion!

Brownian motion is the random movement of particles in a fluid.

If we look at one particle, this is how it will look like :

 But why do we need it?

Adding the Brownian motion to our terrain will give this "shaking" effect to our world.So we won't have a smooth and ugly unrealistic terrain.
To do that, we add Octaves together which are calculated by a Fractal Brownian Motion algorithm.We use a persistence value to the FBM algorithm to set how much influence it has on the terrain. 


Let's code!

- First, go to your World script, we will change a few things : We are going to generate columns of chunks from bottom to top. 

 We add a new variable called "columnHeight" which is how many chunks we have on top of each other. 


 - Let's add a method called "GenerateColumn" to create our columns : 

It will create a chunk and loop to go on top of each other as much as requested by the columnHeight variable.


- You can change the Start method now :

 Now, it won't create chunks side by side but it will create columns of chunks side by side.

Now, maybe you'll notice that nothing happens if you test your game. That's because we create chunks before the blocks database is generated. We have to call it manually before our chunks. I fixed it in the last post.

We will initialize our Database before generating chunks. The Database script is on the same object, we will access the script and call the new method. 


 - Now you can test your game : 

We generated columns of chunks side by side. But every chunk is the same and we want something better to look at. That's why we need noise.


 - Go to your project folder and create a script called "Noise". It will contain everything we need to generate our height values. 

First, we need common values which will be used for every chunk : 

- The smooth value is the increment, giving a sharper/flatter terrain.

- Octaves is the number of waves added together.

- Persistence is how much the effect of FBM will be used.

 Max height is the height in blocks of our terrain.  Remember that i said the value of perlin noise is between 0 and 1 and here we replace 1 by 150. It will be remapped.

 - To map our value in the terrain we will create a method called "Map" :

It takes the minimum value and the maximum value and replaces 0 and 1 to min and max. We give the original values (0 and 1) and it will calculate and map those values.

Here we give min, max, 0, 1 and the value we want to map which is the perlin noise value between 0 and 150. 


 - To generate the height of a block, we need a method called "GenerateHeight" :

It maps the value of the perlin noise (While adding the FBM value) and returns the final height as an int.

- The FBM method :

This is where we will  calculate the final value. Remember that we will be on the x and z axis and get the height (y) of each position. That's why we give Z to the perlin noise instead of Y.

We loop as much as we have octaves and for each one we calculate the perlin noise value while adding persistence and frequency to each wave.

Then we return the total value divided by the maxValue.

/!\ The best way to fully understand this part is to test with different values /!\


- Let's calculate our block heights in the Chunk script :

Go to the GenerateVirtualMap method. 

We will need to get the position of the actual block in the world. (X local position in map + Chunk world position)

It will be given to the perlin noise to find the position inside the noise.

- Now we will create the first layer, the grass layer :

Here, we calculate the height of the block at the position X/Z we have.

If Y is at the position of the height we create a Grass block like before.

And to every other position, we add air blocks to make sure a block exists.

Now if you test the game, you won't see anything. That's because the block is too high and doesn't exist in our world.

There are two solutions to fix that : 

- Change your variables in the World script to have enough chunks in a column to get to the layer height.

- Add an offset value to the Chunk script :

 A positive value will bring them down.
This will lower the chunks to render the layers of our world. But remember that the other ones above our layer in the columns will still exist.

- Now you can test your game :

Our grass Layer is now generated!

In the next part we will add more layers, caves and ores.

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!