top of page

Procedural 3D Terrain Generation

5
6
1

 

Project Name: Procedural 3D Terrain Generation using Perlin Noise

 

Technology: Unity Engine, C# Scripting

 

Type: Solo Project

 

Description:

 

In this Unity app, I procedurally generated a 3D low-poly world with two distinct Biomes. The terrain is fully generated at compile time.

 

  1. A landscape - with a mountain range including moving water, sand, greenery, and ice tops.

  2. An island - which is covered by water on all sides and has moving water, sand, greenery, and ice tops.

 

Sequence of the procedural generation events that happens at compile time:

  1. 2D Noise map is generated using the Perlin Noise function

  2. Octaves are generated on the same 2D noise map

  3. The 2D Data is mapped to 3D coordinates of a new empty mesh

  4. The vertices are corrected according to some of the variables like “Mesh Height Curve”

  5. The mesh is divided into smaller triangles for LOD and optimization

  6. Depending on the biome selected, the mesh is regenerated again

  7. Colors as textures are applied to the mesh depending on the color map

  8. Dynamic water is rendered around the mesh

 

Two main algorithms used:
 

  • Algorithm 1 for generating octaves:

For each octave we want to generate, we collect a random number between the range -100000 to 100000 and then generate noise from that seed. This random number is generated based on the system clock, making it unpredictable. Additionally, for each octave, a new seed is generated by offsetting the same seed from the previously generated octave. This whole random generation is applied to both X-axis and Y-axis of the current octave. The following is the main logic where octave calculation happens:

 

 

 

        System.Random Rng_No = new System.Random(seed);

        Vector2[] octaveOffsets = new Vector2[Total_Octaves];

 

                     for(int i=0;i<Total_Octaves;i++)

                     {

                              float offset_X = Rng_No.Next(-100000,100000)+ offset.x;

                              float offset_Y = Rng_No.Next(-100000,100000)+ offset.y;

                              octaveOffsets[i] = new Vector2(offset_X, offset_Y);

                     }

 

                     for (int i = 0; i < Total_Octaves; i++)

                     {

                              float sampleX = (x-halfWidth) / scale * frequency + octaveOffsets[i].x;

                              float sampleY = (y-halfHeight) / scale * frequency + octaveOffsets[i].y;

 

                     }

 

 

​​

  • Algorithm 2 for generating island biome:

 

Creating this Biome was an interesting challenge. I had a 2D noise map filled with octaves and random noise. I was thinking of making a separate noise function to make the noise look like an islandic style noise (sort of a heatmap). However, I found out that masking a 2D gradient map with the current noise map can do the trick too. So I wrote a mathematical function to generate a 2D gradient map where all the pixels in the middle were dark(have full opacity), and the rest of the pixels had no opacity. The following is the mathematical formula:

Above function gives curve like this:

After implementing the above function in code:

​

​

                                                 Mathf.Pow(value, a) / (Mathf.Pow(value, a) + Mathf.Pow(b - b * value, a));

​

​

Above line of code generated this 2D noise map:

The Black color value in the pixel denotes its opacity. Totally dark pixels are opaque, and pixels shifts towards becoming transparent the more white color they have. In the end, I masked this noise map with the original biome barren terrain, which gave off the feel of an island. The white pixels(fully transparent ones) are overlapped by water.

​

© 2026 Shreevallabh Sunil Kulkarni. All rights reserved.

bottom of page