Terrain

The terrain is generated using the Marching Cubes method. Marching Cubes is a terrain generation method that uses 3D noise. It works by dividing the 3D space into an 3D array of cubes and then calculating the triangular sections of terrain that are contained within each cube and creating a mesh from them.

There are numerous in-depth tutorials and explanations to be found on the Internet, one of the best in my opinion can be found here:
https://www.youtube.com/watch?v=M3iI2l0ltbE 

The settings for the terrain are held in the TerrainManager script which is attached to the TerrainManager GameObject. It follows a singleton pattern so can be accessed from anywhere by creating a reference to TerrainManager.Instance in your code.

Terrain Settings

It holds the 3D noise settings for the terrain, and in this video I look at the various settings in detail and show how the look and feel of the terrain can be altered just by using the 3D noise settings. I also discuss the options for including caves in the terrain.

Its Update() method is responsible for keeping track of which chunks are currently visible and which new chunks need to be created.

Start Position

Start Position

The world map is contained in a 512 x 512 texture with each pixel representing a chunk. As each chunk is 16m x 16m this gives a world size of 8.192km x 8.192km = 67.1Km² before any wrapping occurs. As the texture is wrapped in both directions a potentially endless world is possible.

The start position indicates which chunk the player will start on, and this position is displayed as a red dot on the map displayed on the BiomeManager/BiomeTexture game object in the Scene View. 

Basic Settings

Basic Settings

The Seed value is used throughout the project for all random numbers generated to create the procedural terrain and the positioning of the scenery objects.

The Max View Distance is the distance in meters from the player in every direction that is to be filled with chunks. Obviously the larger the number the more chunks that need to be created on start so this value can directly affect the game start-up time. 

The Water Level is the height in meters that is used for positioning the Water Plane if water is included. Any height below the Water Level is considered underwater and any height above is considered as above water.

The Chunk Class

This class holds all of the information and methods for creating and modifying a chunk game object. It also holds information about each of its neighbouring chunks, taken from the biome map height and biome type textures.

Each chunk has a base terrain height value, taken from the biome height map. This means that the terrain gradually raises and lowers to match the biome map, and any 3D noise is added to this base height.

The 3D noise for the chunk is generated and stored in the float array _densityMap using OpenSimplex2F noise generation script. This is then added to the base terrain height for the chunk, and any cave data modifications made, and the result is then stored in float array _terrainMap.

To ensure chunks of different base terrain heights make a continuous terrain, the edges are ‘seamed’ together. This is done by finding the base terrain height of the neighbouring chunk and modifying the edge value to match the neighbouring chunk’s edge value before storing it in the _terrainMap array.

This ‘seaming’ is also done when modifying the terrain to ensure that the terrain doesn’t rip when altering it at the edge of a chunk. 

Terrain Water

Terrain Water

Adding Water

If your map includes Shallow Water and Deep Water biomes, and you want to use a Water Plane to show the water, then Include Water should be checked. If Include Water is checked then a Water Plane GameObject must be included to represent the water visually.

Adding a Water Plane

The Water Plane should be a GameObject that is 16m x 16m on the X and Z axis to match the size of a Chunk, and should have a material applied with a water shader on it.

In this video I create a suitable Water Plane object using a free water shader found on the Unity Asset Store and add it to MC Terrain.

Note that there is no provision for a player prefab to avoid starting in water so this would need to be accounted for if the game player is allowed to choose their own Seed value at the start of the game. 

  Modifying the Terrain

Modifying the Terrain

The Modify Terrain script is also attached to the TerrainManager game object and handles the lowering and raising of the terrain by the mouse. This is done by identifying the mesh triangle on the terrain that has been clicked on and finding the cube that the triangle belongs to. Once the cube is identified the corner values for the cube are set to 1f (corners all above ground) if terrain is to be removed, and 0f (corners all below ground) if terrain is to be added. Then the chunk performs the Marching Cubes function again to generate the updated mesh.

To identify the mesh triangle clicked on a raycast is performed. To prevent the player prefab from blocking the raycast from reaching the terrain the player prefab is automatically added to the ‘Ignore Raycast’ layer when it is instantiated. 

If a cube is modified that is at the edge or corner of a chunk, then each of the affected neighbouring chunks' edge values are updated to match the new edge values of the modified chunk. This is to prevent tearing occurring in the terrain when it has been raised or lowered. Once all of the edges and corners have been updated each of the modified chunks has the Marching Cubes function run on it to generate new meshes to ensure that the terrain is correctly updated.

When terrain cubes are modified, all scenery items are automatically deleted within the modified area. This is to prevent, for example, scenery items being left in mid-air when terrain is removed from below them. For this to work their prefabs must have a collider attached. To avoid the player prefab from colliding with the small objects eg, bushes and stones, their colliders should be set as triggers so the player can pass through them but they can also be identified by the ModifyTerrain script as being in the modified area. As grass is instanced in the GPU the removal of grass is handled by the GrassController script rather than the ModifyTerrain script.

© Copyright 2023 MC Terrain. All Rights Reserved.