richardbiely / Voxelmetric

An efficient voxel framework for Unity3d

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Creating Proper Caves

aesliva opened this issue · comments

commented

Was wondering if there were any plans for 3D noise for the generation of caves, cliffs, overhangs, etc.. Also, if you were to implement it how would you go about doing it?

Adding another axis to iterate on will really slow things down, especially since we are already iterating over 3 loops in terrain gen (x, z, terrainlayer). I'm sure the set blocks method would have to change, and how we determine terrain height as well.

Just curious!

commented

So, I attempted to create some caves. Naturally, I'd assume iterating over the y-axis and using 3D interpolation would be enough to do this.

Added a 'y' variable:

        int xOffset = chunk.Pos.x;
        int yOffset = chunk.Pos.y;
        int zOffset = chunk.Pos.z;

        int i = 0;
        for (int z = 0; z < ni.noiseGen.Size; z++)
        {
            float zf = (z << ni.noiseGen.Step) + zOffset;
            for (int y = 0; y < ni.noiseGen.Size; y++)
            {
                float yf = (y << ni.noiseGen.Step) + yOffset;
                for (int x = 0; x < ni.noiseGen.Size; x++)
                {
                    float xf = (x << ni.noiseGen.Step) + xOffset;
                    ni.lookupTable[i++] = NoiseUtils.GetNoise(noise.Noise, xf, yf, zf, 1f, amplitude, noise.Gain);
                }
            }
        }

Acts like the absolute layer:

    public override float GetCaveNoise(Chunk chunk, int layerIndex, int x, int y, int z, float caveNoiseSoFar, float strength)
    {
        var pools = Globals.WorkPool.GetPool(chunk.ThreadID);
        var ni = pools.noiseItems[layerIndex];

        float caveNoiseToAdd = ni.noiseGen.Interpolate(x, y, z, ni.lookupTable);
        caveNoiseToAdd += minHeight;
        caveNoiseToAdd = caveNoiseToAdd * strength;

        if (caveNoiseToAdd > caveNoiseSoFar)
        {
            return caveNoiseToAdd;
        }

        return caveNoiseSoFar;
    }

    public override float GenerateLayer(Chunk chunk, int layerIndex, int x, int y, int z, float heightSoFar, float caveNoiseSoFar, float strength)
    {
        if (caveNoiseSoFar > 50f)
        {
            SetBlocks(chunk, x, z, chunk.Pos.y + y, chunk.Pos.y + y + 1, blockToPlace);
        }
        return heightSoFar;
    }

And in TerrainGen the y-axis is used:

public void GenerateTerrainForChunk(Chunk chunk)
    {
        int maxY = chunk.Pos.y + Env.ChunkSize;
        for (int z = 0; z<Env.ChunkSize; z++)
        {
            for (int y = 0; y < Env.ChunkSize; y++)
            {
                for (int x = 0; x<Env.ChunkSize; x++)
                {
                    float height = 0f;
                    float caveNoise = 0f;
                    for (int i = 0; i < TerrainLayers.Length; i++)
                    {
                        caveNoise = TerrainLayers[i].GetCaveNoise(chunk, i, x, y, z, caveNoise, 1f);

                        height = TerrainLayers[i].GenerateLayer(chunk, i, x, y, z, height, caveNoise, 1f);

                        if (height > maxY)
                            break;
                    }
                }
            }
        }
    }

Below is the result that I got. I'm not sure what can be causing this, any insight would be greatly appreciated!

image

In my opinion, the way you decided to do this is hacky and design breaking in the very least.

You can implement caves (just like any other layer) this way:
public class YourCavesLayer: TerrainLayer
{
protected override void SetUp(LayerConfig config)
{
}

public override float GetHeight(Chunk chunk, int layerIndex, int x, int z, float heightSoFar, float strength)
{
    return heightSoFar;
}

public override float GenerateLayer(Chunk chunk, int layerIndex, int x, int z, float heightSoFar, float strength)
{
    // you have access to your Y-axis
    for (int y = 0; y < Env.ChunkSize; y++)
    {
        // you can access 3D noise
        int someNoise = (int)NoiseUtils.GetNoise(noise.Noise, x + chunk.Pos.x, y + chunk.Pos.y, z + chunk.Pos.z, some_scale, some_max, some_power);
        int index = Helpers.GetChunkIndex1DFrom3D(x, y, z);
        // you can set your blocks individualy
        chunk.Blocks.SetRaw(index, BlockProvider.AirBlock);
    }

    return heightSoFar;
}

}

And don't forget to set your layer's config "index" properly. The bigger the number the later the layer is evaluated (not exactly a good choice for layer system but it is what it is right now).

commented

I appreciate your insight! (Newbie programmer, still learning and always open to feedback) :)

I do have another question though, there is a height limit to how far down terrain generation goes. Camera is following on y axis.

image

This height limit can be changed via the height variable in GenerateTerrainForChunk. Is this limit intentional? If so, how would 'infinite' terrain generation on the y axis happen?

commented

Got some decent results after tweaking with the noise.

image

Using fractal billow noise at a low octave. Generating air at lowest values i.e: (caveNoise < caveThreshold).

To make a world infinite on the Y-axis, modify you world's config so it contains:
"maxY": 0,
"minY": 0,