mods, can you please delete this? I have written a better tutorial on the subject

Discussion in 'Resources' started by jtjj222, Apr 21, 2012.

Thread Status:
Not open for further replies.
  1. Offline

    jtjj222

    Hello, I still haven't tinkered with all the values, but I just figured how to use 3-d simplex noise to create interesting terrain features. It could be used to make mountains and overhangs, although I'm still tinkering around to figure out how to do that. I would have personally liked to know about this sooner, and so I would like to share what I know with you. I'm not very experienced with this stuff, but If in any way this post helps you, please let me know :D

    This tutorial assumes that you have used two dimensional simplex noise (or as many know it, a simplexoctavegenerator). codename_B has a nice tutorial on it: http://forums.bukkit.org/threads/in...errain-generation-using-simplexoctaves.28855/

    First things first, when using 3d noise, think of the noise as density. If the noise is above a certain threshold, make it solid. Notch explains this: http://notch.tumblr.com/post/3746989361/terrain-generation-part-1
    Code:java
    1. public class ChunkGenerator extends org.bukkit.generator.ChunkGenerator {
    2. double scale = 32.0; //how far apart the tops of the hills are
    3.  
    4. public List<BlockPopulator> getDefaultPopulators(World world) {
    5. //Block populators go here
    6. return null;
    7. }
    8.  
    9.  
    10. /*
    11. * Sets a block in the chunk. If the Block section doesn't exist, it allocates it.
    12. * [y>>4] the section id (y/16)
    13. * the math for the second offset confuses me
    14. */
    15. void setBlock(int x, int y, int z, byte[][] chunk, Material material) {
    16. if (chunk[y>>4] == null)
    17. chunk[y>>4] = new byte[16*16*16];
    18. if (!(y<=256 && y >= 0 && x <= 16 && x >= 0 && z <= 16 && z >= 0))
    19. return; //Out of bounds
    20. try {
    21. chunk[y>>4][((y & 0xF) << 8) | (z << 4) | x] = (byte)material.getId();
    22. } catch (Exception e) {
    23. //do nothing
    24. }
    25. }
    26.  
    27. @Override
    28. //Generates block sections. Each block section is 16*16*16 blocks, stacked above each other. //There are world height / 16 sections. section number is world height / 16 (>>4)
    29. //returns a byte[world height / 16][], formatted [section id][Blocks]. If there are no blocks in a section, it need not be allocated.
    30. public byte[][] generateBlockSections(World world, Random rand,
    31. int ChunkX, int ChunkZ, BiomeGrid biomes) {
    32.  
    33. Random random = new Random(world.getSeed());
    34. SimplexOctaveGenerator gen = new SimplexOctaveGenerator(random, 8);
    35. byte[][] chunk = new byte[world.getMaxHeight() / 16][];
    36.  
    37. gen.setScale(1/scale); //The distance between peaks of the terrain. Scroll down more to see what happens when you play with this
    38. double threshold = 0.0; //scroll down to see what happens when you play with this.
    39.  
    40. for (int x=0;x<16;x++) {
    41. for (int z=0;z<16;z++) {
    42. int real_x = x+ChunkX * 16;
    43. int real_z = z+ChunkZ*16;
    44.  
    45. for (int y=1;y<256;y++) {
    46. if(gen.noise(real_x, y, real_z, 0.5, 0.5) > threshold) //explained above
    47. setBlock(x,y,z,chunk,Material.GLOWSTONE); //set the block solid
    48. }
    49. }
    50. }
    51. return chunk;
    52. }
    53. }

    Sorry for the indenting, the code tag screwed it up.
    If anything above isn't clear to you, pm me.
    If you use it as-is, with scale at 32 and threshold at 0.0, it creates nether-like terrain:
    http://dl.dropbox.com/u/12637402/tutorial1/scale32.png
    http://dl.dropbox.com/u/12637402/tutorial1/scale32pic2.png
    http://dl.dropbox.com/u/12637402/tutorial1/scale32pic3.png
    Scale 64, threshold 0:
    http://dl.dropbox.com/u/12637402/tutorial1/scale64.png
    http://dl.dropbox.com/u/12637402/tutorial1/scale64pic2.png
    http://dl.dropbox.com/u/12637402/tutorial1/scale64pic3.png
    Scale 256, threshold 0:
    http://dl.dropbox.com/u/12637402/tutorial1/scale256.png
    Now, we can play with the threshold a bit. The larger the threshold, the less solid blocks, and the less "connected" everything looks:
    Scale 256, threshold 0.7:
    http://dl.dropbox.com/u/12637402/tutorial1/thresholdPOINT7.png
    If I get a good response from this tutorial, I'll make another one that explains how to use multiple 2d simplexoctavegenerators together to make more interesting terrain, and also how you can use 2d noise along with 3d noise to make cool floating islands. I may also do one on biomes.
    Enjoy, and please let me know if this was helpful!

    EDIT2: Updated for the new method generateBlockSections
    edit3: xpansive showed me how to use voronoi noise in terrain generation, so if I can figure that out, expect a tutorial on it.
    EDIT3: Fixed formatting
     
    ferrybig and hypothete like this.
  2. Offline

    xpansive

    The generate method is deprecated. You should update the tutorial to use the new methods. Check the javadocs for details.
     
  3. Offline

    jtjj222

    **updated, thanks
     
  4. Offline

    codename_B

    This is very very awesome :D

    I never quite got my head around the 3d simplex as I could never really picture it in my head (2d I just picture the height as shades of gray, so basically a heightmap) so explaining it as density is excellent.

    When I've got the inclination I might make a few more WGENs based off of this - I've got a decent bank of populators put together that I can just fire into generated terrain now too lol.
     
  5. Offline

    codename_B

    [​IMG]
     
    jtjj222 likes this.
  6. Offline

    jtjj222

    ...how? That's epic. that looks like a high scale and low threshold, but there is something different I just can't put my finger on...
     
  7. Offline

    codename_B

    I'm also layering it with 2d perlin as a max noise level (and generating set 2d perlin below x coordinates) want to see the code?
     
  8. Offline

    p000ison

    Yessss, please! :p
     
  9. Offline

    codename_B

    Code:
    package de.bananaco.gen;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    
    import org.bukkit.Material;
    import org.bukkit.World;
    import org.bukkit.generator.BlockPopulator;
    import org.bukkit.util.noise.PerlinOctaveGenerator;
    import org.bukkit.util.noise.SimplexOctaveGenerator;
    
    
    
    public class ChunkGenerator extends org.bukkit.generator.ChunkGenerator {
        double scale = 32.0; //how far apart the tops of the hills are
        double threshold = 0.0; // the cutoff point for terrain
        int middle = 70; // the "middle" of the road
    
        public List<BlockPopulator> getDefaultPopulators(World world) {
            return new ArrayList();
    
        }
    
    
        /*
         * Sets a block in the chunk. If the Block section doesn't exist, it allocates it.
         * [y>>4] the section id (y/16)
         * the math for the second offset confuses me
         */
        void setBlock(int x, int y, int z, byte[][] chunk, Material material) {
            if (chunk[y>>4] == null)
                chunk[y>>4] = new byte[16*16*16];
            if (!(y<=256 && y >= 0 && x <= 16 && x >= 0 && z <= 16 && z >= 0))
                return; //Out of bounds
            try {
                chunk[y>>4][((y & 0xF) << 8) | (z << 4) | x] = (byte)material.getId();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @Override
        //Generates block sections. Each block section is 16*16*16 blocks, stacked above each other. //There are world height / 16 sections. section number is world height / 16 (>>4)
        //returns a byte[world height / 16][], formatted [section id][Blocks]. If there are no blocks in a section, it need not be allocated.
        public byte[][] generateBlockSections(World world, Random rand,
                int ChunkX, int ChunkZ, BiomeGrid biomes) {
            Random random = new Random(world.getSeed());
            SimplexOctaveGenerator gen = new SimplexOctaveGenerator(random, 8);
            PerlinOctaveGenerator gen2 = new PerlinOctaveGenerator(world.getSeed(), 8);
    
            byte[][] chunk = new byte[world.getMaxHeight() / 16][];
    
            gen2.setScale(1/scale);
            gen.setScale(1/scale); //The distance between peaks of the terrain. Scroll down more to see what happens when you play with this
            double threshold = this.threshold; //scroll down to see what happens when you play with this.
    
            for (int x=0;x<16;x++) {
                for (int z=0;z<16;z++) {
                    int real_x = x+ChunkX * 16;
                    int real_z = z+ChunkZ*16;
    
                    double height = middle+gen2.noise(real_x, real_z, 0.5, 0.5)*middle/3; // generate some smoother terrain
                    
                    for (int y=1; y<height && y<256; y++) {
                        if(y > middle-middle/3) {
                            double noise = gen.noise(real_x, y, real_z, 0.5, 0.5);
                            if(noise > threshold) //explained above
                                setBlock(x,y,z,chunk,Material.STONE); //set the block solid
                        } else {
                            setBlock(x,y,z,chunk,Material.STONE);
                        }
                    }
                }
            }
            return chunk;
        }
    }
    
     
    jtjj222 likes this.
  10. Offline

    jtjj222

    That's awesome, thanks :D
     
Thread Status:
Not open for further replies.

Share This Page