The always up-to-date definitive guide to terrain generation: Part 5 - 3d noise

Discussion in 'Resources' started by jtjj222, Aug 18, 2012.

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

    jtjj222

    Part one
    Part Two
    Part Three
    Part Four

    This is starting to get interesting. Thus far, we have covered the basics. Now let's get into some advanced stuff. 3d noise. Trust me, it's a lot cooler than it sounds. By the end of this tutorial, we will have build something similar to this, but with better grass:

    We will also cover making terrain similar to this:

    I have already written on the subject, but the tutorial I wrote was, frankly, half assed and half hearted. With that out of the way, let's begin.

    For this tutorial, we will cover using the 3d version of bukkit's SimplexOctaveGenerator. In a later tutorial, we will cover using other forms of noise, but for now, we will only concern our self with bukkit's implementation.
    Last chapter, I talked about how you should think of 3d noise. Notch also talked about it, but never delivered on his promise of a series on the subject. Think of it as returning the "density" of the location you give it. The extreme values are the centers of the blobs. If you allow only blocks with a density above a certain threshold to be solid, you get usable terrain. The smaller the threshold, the more blocks are solid, and the more "connected" everything looks.
    [​IMG]
    The scale of the generator (among other things) can be used to manipulate the terrain. The picture above has a pretty low scale compared to:
    [​IMG]
    Remember: scale is how "stretched" everything is.

    At this point, the examples look a little boring, but they will get better, trust me. Here is the code for the above examples. The only difference between them is the scale.

    If you have made it this far in the tutorial series, you probably understand that code. If not, post below, or pm me. We loop through all of the blocks in the chunk, find their density, and make them solid if their density is above a certain threshold. Note that 3d noise is very slow, and this is a very inefficient (and boring) way of using it. Now onto some uses.

    Using 3d noise with 2d noise:
    This part explains how to use 3d noise to add overhangs to a 2d noise generator. To do this, we calculate the 2d noise for the top of the overhangs, and calculate the 2d noise for the bottom terrain. We then fill the bottom terrain solid, and loop through the blocks in between the bottom and top terrain, check their density, and make them solid if their density is above a certain threshold. Example. The terrain that that generates looks alright, but the overhangs are a bit off.
    Now, I still haven't played with all of the values for everything, so if you can figure out how to make the terrain look better, let me know, and it will be included in this tutorial along with your name, and how awesome you are.
    That code above, with threshold at 0.3:
    [​IMG]

    You can combine more than one base generator to give the hills below more character, and in a later chapter, when we cover biomes, this code could make an interesting mountain biome. It only needs one more thing: grass. Adding grass is pretty simple, but It would be better explained in code. We loop through all the blocks once again, check if there is air above them, and stone beneath them, and if so, set them to grass.
    Here is the world with grass:
    [​IMG]
    There you go!

    Making that glass catacomb:
    The way I made the glass catacomb was by checking if the density of the block was between 0.3 and 0.4. If so, I set it to glass. With a little extra work, that could be turned into a hollow world used for a survival game, among other things.

    Project files:
    Glass catacomb.
    Grassy overhanging mountains.

    At this point, we have barely scratched the surface of what we can do with terrain generation. I thought this part was going to be a lot longer. codename_B has managed to make some epic looking skylands with 3d noise, so I would highly recommend you go check that out here. I am also working on Vast tracks 'o mountain . Minecraft itself also used 3d perlin noise to make some of it's terrain features.
    There is a lot more to come in this series, so stay tuned, and please leave a suggestion as to what topic I should write about next. If there is anything that you think I should add to the series, PLEASE let me know :D. Happy terrain, uhh, generating?

    Part 6
    Part 7 - The long awaited biomes tutorial (Written!)

    Updating all the posts when I add a new tutorial is getting too cumbersome, so I am just going to daisy chain them :D

    As a reply to my earlier tutorial on 3d simplex noise, codename_b showed us this:
    [​IMG]
    I think it is so relevant to this post, that I am including it here. This is in no way my work; All credit goes to codename_b. Thank him.
    Code:java
    1.  
    2. package de.bananaco.gen;
    3.  
    4. import java.util.ArrayList;
    5. import java.util.List;
    6. import java.util.Random;
    7.  
    8. import org.bukkit.Material;
    9. import org.bukkit.World;
    10. import org.bukkit.generator.BlockPopulator;
    11. import org.bukkit.util.noise.PerlinOctaveGenerator;
    12. import org.bukkit.util.noise.SimplexOctaveGenerator;
    13.  
    14.  
    15.  
    16. public class ChunkGenerator extends org.bukkit.generator.ChunkGenerator {
    17. double scale = 32.0; //how far apart the tops of the hills are
    18. double threshold = 0.0; // the cutoff point for terrain
    19. int middle = 70; // the "middle" of the road
    20.  
    21. public List<BlockPopulator> getDefaultPopulators(World world) {
    22. return new ArrayList();
    23.  
    24. }
    25.  
    26.  
    27. /*
    28.   * Sets a block in the chunk. If the Block section doesn't exist, it allocates it.
    29.   * [y>>4] the section id (y/16)
    30.   * the math for the second offset confuses me
    31.   */
    32. void setBlock(int x, int y, int z, byte[][] chunk, Material material) {
    33. if (chunk[y>>4] == null)
    34. chunk[y>>4] = new byte[16*16*16];
    35. if (!(y<=256 && y >= 0 && x <= 16 && x >= 0 && z <= 16 && z >= 0))
    36. return; //Out of bounds
    37. try {
    38. chunk[y>>4][((y & 0xF) << 8) | (z << 4) | x] = (byte)material.getId();
    39. } catch (Exception e) {
    40. e.printStackTrace();
    41. }
    42. }
    43.  
    44. @Override
    45. //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)
    46. //returns a byte[world height / 16][], formatted [section id][Blocks]. If there are no blocks in a section, it need not be allocated.
    47. public byte[][] generateBlockSections(World world, Random rand,
    48. int ChunkX, int ChunkZ, BiomeGrid biomes) {
    49. Random random = new Random(world.getSeed());
    50. SimplexOctaveGenerator gen = new SimplexOctaveGenerator(random, 8);
    51. PerlinOctaveGenerator gen2 = new PerlinOctaveGenerator(world.getSeed(), 8);
    52.  
    53. byte[][] chunk = new byte[world.getMaxHeight() / 16][];
    54.  
    55. gen2.setScale(1/scale);
    56. gen.setScale(1/scale); //The distance between peaks of the terrain. Scroll down more to see what happens when you play with this
    57. double threshold = this.threshold; //scroll down to see what happens when you play with this.
    58.  
    59. for (int x=0;x<16;x++) {
    60. for (int z=0;z<16;z++) {
    61. int real_x = x+ChunkX * 16;
    62. int real_z = z+ChunkZ*16;
    63.  
    64. double height = middle+gen2.noise(real_x, real_z, 0.5, 0.5)*middle/3; // generate some smoother terrain
    65.  
    66. for (int y=1; y<height && y<256; y++) {
    67. if(y > middle-middle/3) {
    68. double noise = gen.noise(real_x, y, real_z, 0.5, 0.5);
    69. if(noise > threshold) //explained above
    70. setBlock(x,y,z,chunk,Material.STONE); //set the block solid
    71. } else {
    72. setBlock(x,y,z,chunk,Material.STONE);
    73. }
    74. }
    75. }
    76. }
    77. return chunk;
    78. }
    79. }


    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 27, 2016
  2. Offline

    Icyene

    Is it just me or does the first video terrain look like a strangled snake, and the second video like that Rainbow Road thing in Mario Kart? And is that a satellite - dish like terrain in the first picture? Anyways, thanks for all these great tutorials! They helped alot :)
     
    jtjj222 likes this.
  3. Offline

    hypothete

    Hey jtjj222 and codename_b, thanks for the examples. I was wondering whether you could help me understand the output of the noise function better, and its relation to the threshold. Here's what I'm trying to accomplish: a Skylands-type environment with islands varying in "density" from y=96 - 192. My initial thought would be to vary the threshold by height (so like sin(y/255*2Pi)) but that didn't seem to work. I also tried adjusting the amplitude and frequency of the noise by height, but the results were not noticeable. Any ideas on how I could make density vary by height? Thanks!

    Here's my code for reference. If I leave in the threshold varying with height (commented), MV2 tells me it fails. link

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 27, 2016
  4. Offline

    jtjj222

    I don't really understand what you are trying to do. Can you explain that a bit better? Also, can you get a stack trace for the error that you are describing?
     
  5. Offline

    hypothete

    I'm just trying to make it so from Y 1-96 there are almost no islands, Y 96 - 224 there are a lot of islands, and then 225-256 almost none again. I ended up just generating the islands in that middle bit, but that slices through some of the lower and higher blobs, which IMO looks bad.
     
  6. Offline

    jtjj222

    Add a displacement to the noise based on the y value.
     
  7. Offline

    Hoolean

    Next, could you show us how to add trees and biomes, as it would be very much appreciated! Thank you!
     
  8. Offline

    Armadillo

    Very good tutorials!!!!
     
  9. Offline

    Corgano

    Please continue making tut's! These are probably the most epic things I've seen bukkit do!
     
  10. Offline

    Limeth

    I agree!
     
    slowbuild and MrBluebear3 like this.
  11. Offline

    ignirtoq

    Any chance the part detailing biomes will be out any time soon?
     
  12. Offline

    jtjj222

    Haha, I know it's been a while. School has been keeping me busy :(
     
  13. Offline

    Corgano

    Don't make me beg!
     
  14. Offline

    El_Minadero

    What would I have to do to retain Mc's default terrain generation but alter the distribution and look of ore veins?
     
  15. Offline

    jtjj222

    Well, you could copy the source code directly form a decompled version of minecraft. If that's too much, you could just add a new block populator to the existing world to add ores (create an event handler for the onWorldInit event, then add the populator using world.getBlockPopulators().add() or something like that).
     
  16. Offline

    jtjj222

    Biomes are out!
     
Thread Status:
Not open for further replies.

Share This Page