Solved World Generation Biome Noise Map sharp edges

Discussion in 'Spigot Plugin Development' started by Streampy, Feb 8, 2020.

  1. Hey guys,

    I am working / experimenting with custom worldgeneration and I got a problem with the edges of my 'biomes'.

    Here is my code
    Code (Java):
    @Override
            public ChunkData generateChunkData(World world, Random random, int chunkX, int chunkZ, BiomeGrid biome) {
                SimplexOctaveGenerator generator = new SimplexOctaveGenerator(new Random(world.getSeed()), 8);
                ChunkData chunk = createChunkData(world);
             
                PerlinOctaveGenerator temperatureGen = new PerlinOctaveGenerator(world.getSeed(), 16);
                temperatureGen.setScale(1.0/300.0);
             
                PerlinOctaveGenerator rainfallGen = new PerlinOctaveGenerator(world.getSeed() + 1, 15);
                rainfallGen.setScale(1.0/300.0);

             
                for (int X = 0; X < 16; X++)
                    for (int Z = 0; Z < 16; Z++) {
                    //    Biome b = biome.getBiome(X, Z);
                    //    double frequency = 0.1D;
                    //    double amplitude = 0.9D;
                    //    double multitude = 32D;
                        double seaLevel = 64D;
                     
                 //    int noise = 50;
                     
                        int realX = chunkX*16+X;
                        int realZ = chunkZ*16+Z;
                     
                        generator.setScale(1/64.0D);
                     
                     
                        int rain = (int) Math.abs(rainfallGen.noise(realX, realZ, 0.9, 0.9) * 50);
                        int temp = (int) Math.abs(temperatureGen.noise(realX, realZ, 0.9, 0.9) * 50);                
                     
                        int flat = (int) (generator.noise(realX, realZ, 0.1, 0.1)*2+seaLevel);
                        int high = (int) (generator.noise(realX, realZ, 0.5, 0.5)*24+seaLevel);

                         
                        if(rain > 5 && temp < 15) {
                           biome.setBiome(X, Z, Biome.PLAINS);
                           int maxY = flat;
                           for (int y = 0; y < maxY; y++) {
                               chunk.setBlock(X, (int) y, Z, Material.GRASS_BLOCK);
                           
                           }
                       
                        }else if(rain <= 5 || temp >= 15) {
                            biome.setBiome(X, Z, Biome.DESERT);
                            int maxY = (flat + high) / 2;
                              for (int targetY = 0; targetY < maxY; targetY++) {
                                  chunk.setBlock(X, (int) targetY, Z, Material.SANDSTONE);
                              }
                        }
                    }  
                return chunk;
            }
    I looked at the following links:
    https://www.spigotmc.org/threads/problem-with-smooth-biome-transition-worldgenerating.350536/
    https://www.spigotmc.org/threads/trouble-making-smooth-biome-transitions.369868/
    https://www.reddit.com/r/proceduralgeneration/comments/6nyjil/terrain_how_do_you_combine_noise_maps/
    http://www.java-gaming.org/topics/perlin-noise-infinite-biomes/31568/view.html
    https://en.wikipedia.org/wiki/Linear_interpolation

    I copied paste some of the spigot code to figure it out how to fix it but still, some of the spigot post solved the issue but without saying how they fixt it or without a example. One of them said the lerp method worked for them but I research on the internet but couldn't find a real explanation how it works.

    If someone has maybe a example how to fix it or want to share some code it would be help full.
    I am stuck for the last 2 weeks on this object.
     

    Attached Files:

  2. Linear interpolation:
    Suppose you have two points in 3D-Space p1 = (x1, y1, z1) and p2= (x2, y2, z2)
    The simplest way of connecting these two points is by a simple line through these points. A line is an affine, 1-Dimensional subspace of any finite, n-dimensional vector space. A line can be constructed using two vectors, one that determines the direction and one that determines the "offset" of the line. Thus an equation can be given in the form of
    x = p + v*t
    p is an arbitrary vector on the line, v is the vector that yields the direction of the line. x is the resulting Vector and t is a variable.
    If you now have two biome-edges, linear interpolation simply means that you set all the blocks along two edge-points p1 and p2 not by how they are defined using the noise-generator, but instead using the line-function given.
     
  3. Any how should I implement that in the worldgeneration, its not there is a line in between? and I can't be sure that both values are already set?
     
  4. I can't provide any actual code because I'm afraid that might be quite lengthy.
    Whenever you are at the edge of two biomes (you'll have to find a way to detect that, maybe using a biome-map?) you would then go, say, 4-5 steps in the direction of each biome and then interpolate between the edges of the biome.
     
  5. I am still stuck on it, I know what you mean with try to find the edge, but I really need a example because else I will be stuck on it for another 2 weeks
     
  6. I found something like: here he has the same issue so I am going to try
     
  7. Kind of saw a version with multiple biomes: https://github.com/StreampyYT/WorldGeneration
    So far I am going to look into changes these values and terrain generation (NOT MY CODE) I only updated
    EDIT: Its just junk it works but get the same problems when changing bigger things in the noise maps
     
    #7 Streampy, Feb 8, 2020
    Last edited: Feb 8, 2020
  8. After some time researching and asking other world generation plugin authors I got a kind of fix using lerp its not pretty but it works:

    How I solved it (ugly code incomming, was only for testing):
    First you have to find the edge between the 2 biomes can be done by checking around the block
    getBiome is my own functions to find in the temperature noise & rain noise the correct biome
    getHeightAt is my function that checks the biome at that x & z and based on that it makes a noise with that and returns the Y value.

    Code (Java):
    int high = getHeightAt(realX, realZ, generator, biome, rainfallGen, temperatureGen);
                       Biome b = getBiome(realX, realZ, rainfallGen, temperatureGen);
                        if (getBiome(realX + 1, realZ, rainfallGen, temperatureGen) != b) {
                            int high2 = getHeightAt(realX + 1 , realZ, generator, biome, rainfallGen, temperatureGen);
                            high = (int) lerp(high, high2, 0.25f);
                        }else if (getBiome(realX - 1, realZ, rainfallGen, temperatureGen) != b) {
                            int high2 = getHeightAt(realX - 1 , realZ, generator, biome, rainfallGen, temperatureGen);
                            high = (int) lerp(high, high2, 0.25f);
                        }else if (getBiome(realX, realZ + 1, rainfallGen, temperatureGen) != b ) {
                            int high2 = getHeightAt(realX, realZ + 1, generator, biome, rainfallGen, temperatureGen);
                            high = (int) lerp(high, high2, 0.25f);
                        }else if ( getBiome(realX, realZ - 1, rainfallGen, temperatureGen) != b) {
                            int high2 = getHeightAt(realX, realZ - 1, generator, biome, rainfallGen, temperatureGen);
                            high = (int) lerp(high, high2, 0.25f);
                        }
    After this you got the correct high for the high between the 2 biomes

    Lerp function that I used:

    Code (Java):
    float lerp(float point1, float point2, float alpha)
        {
            return point1 + alpha * (point2 - point1);
        }

    Screenshots from before the lerp and this code:
    The one with red wool was to check the my edge system for checking around the block (tip extend the check to fix still ugly edges probably from 1 block check to maybe 5 or 10)
    edge.jpg


    After the lerp was added (before it should be a straight wall)
    kindoffix.jpg
     
  9. After some tweaking I put 'for (int i = 1; i < 5; i++)' in front of the if statment and change the 1 to i in every if statement and I change the 0.25f to 0.125f because I have to do it now 4 blocks instead of 1 and this work for now.
    This what I got from changing it:
    better.jpg