Although you can always use the OnChunkBeforeCreate and OnChunkAfterCreate events to supply or modify the chunk voxels (check Events section), Voxel Play also allows you to create and plug-in your own terrain generator class. This feature is useful if you want complete control over how the altitude and moisture are generated.


To create your own terrain generator follow these steps:


1.- Create a new C# script, name it "MyTerrainGenerato".


2.- Your terrain generator class must inherit from VoxelPlayTerrainGenerator class and needs to have this skeleton (highlighted parts must be provided):


namespace VoxelPlay {

    [CreateAssetMenu (menuName="Voxel Play/Terrain Generators/Your Generator Name",fileName = "MyTerrainGeneratorAsset", order = 101)]
    public class MyTerrainGenerator : VoxelPlayTerrainGenerator {

/// <summary>
/// Used to initialize any data structure or noise textures from your own script
/// </summary>
        protected override void Init() {

              ...
        }

/// <summary>
/// Gets the altitude and moisture
/// </summary>
/// <param name="x">The x coordinate.</param>
/// <param name="z">The z coordinate.</param>
/// <param name="altitude">Altitude.</param>
/// <param name="moisture">Moisture.</param>
        public override void GetHeightAndMoisture (float x, float z, out float altitude, out float moisture) {
              ...

        }

/// <summary>
/// Paints the terrain inside the chunk defined by its central "position"
/// </summary>
/// <returns><c>true</c>, if terrain was painted, <c>false</c> otherwise.</returns>
/// <param name="position">Central position of the chunk.</param>
        public override bool PaintChunk (VoxelChunk chunk) {
              ...

        }

}
}

The Init() method is called by Voxel Play to initialize your terrain generator. Place here any code you may need to initialize your terrain generator like reading files, textures or precompute some data. This method is only called once when the world is loaded and the associated terrain generator is loaded as well.


The GetHeightAndMoisture() method is called whenever Voxel Play needs to know the elevation and moisture amount for any position in the world. Note that only X/Z positions are passed to this function. You need to return two values: altitude and moisture. If you don't use moisture in your terrain generator (the PaintChunk method) you can simply return 0 as moisture.


The PaintChunk() method is called every time a chunk needs to be created. The goal of this function is to fill the chunk.voxels array with VoxelDefinitions. The chunk.voxels array is a linearized 16x16x16 array following (read Chunk structure for details). The chunk array is passed as an empty array so you just need to write the positions occupied by voxels. Voxel Play includes some terrain generators located in Voxel Play/Scripts/Private/ScriptableObjects folder:

  • FastFlatTerrainGenerator.cs: a simple terrain generator which only uses a voxel definition (no biomes).
  • TerrainDefaultGenerator.cs: this is the terrain generator used in the world demo scene. It uses a multi-step noise generator plus an optimized PaintChunk() method which calls GetHeightAndMoisture to get heightmap data including altitude and biome at each position. The biome contains the voxel definitions used at the surface and underground for each position of the chunk.
  • UnityTerrainGenerator.cs: a more advanced terrain generator which takes the TerrainData object of an existing Unity terrain and fills chunks according to the splatmaps, vegetation and tree data.


Please take some time to examine the above scripts and learn from the given code.


The VoxelPlayTerrainGenerator base class already provides the maxHeight and seaLevel public fields which are necessary.

You can also use the NoiseTools static class to load noise or heightmap textures in your Init, GetHeightAndMoisture or PaintChunk methods:


NoiseTools.LoadNoiseTexture(tex, out textureSize): loads noise values from a texture and returns an array of float values.


2D noise texture methods:

NoiseTools.GetNoiseValue(array, textureSize, x, z): reads noise value from array mapped to world position x, z + offset based on world seed.

NoiseTools.GetNoiseValueBilinear(array, textureSize, x, z): same but applies bilinear filtering which returns an averaged value based on neighbours.


3D noise texture methods:

NoiseTools.GetNoiseValue(array, textureSize, x, y, z): reads noise value from array mapped to world position x, y, z + offset based on world seed.