8
\$\begingroup\$

I have been working on a 3D game in java using LWJGL for a while now. I am trying to make procedurally generated infinite 3D terrain that is generated around the player.

So far I have:

  • 3D terrain chunks that are loaded and unloaded when the player moves. These chunks are made up of triangles not quads, and are 128x128 vertices.
  • A Perlin noise class that can successfully generate Perlin noise. (I think it is actually something called value noise, but it works)
  • A world class that handles loading and unloading of chunks, and applying the height maps to the chunks.

All of this works as it is coded to do, but not how I want it to. I don't know how to tile the noise seamlessly.

How would I make the noise tile, and furthermore, how would I generate large structures such as mountains that occupy probably up to hundreds of chunks.

Here is what is currently happening with the chunks and noise not tiling:

This

Here is my Perlin noise code:

private float[][] perlinNoise(int width, int height, int octave, float[][] whiteNoise)
{
    float[][] result = new float[width][height];

    int samplePeriod = 1 << octave;
    float sampleFrequency = 1.0f / samplePeriod;

    for (int i = 0; i < width; i++)
    {
        int x1 = (i / samplePeriod) * samplePeriod;
        int x2 = (x1 + samplePeriod) % width;
        float xBlend = (i - x1) * sampleFrequency;

        for (int j = 0; j < height; j++)
        {
            int y1 = (j / samplePeriod) * samplePeriod;
            int y2 = (y1 + samplePeriod) % height;
            float yBlend = (j - y1) * sampleFrequency;

            float top = (float) MathHelper.interpolateLinear(whiteNoise[x1][y1], whiteNoise[x2][y1], xBlend);

            float bottom = (float) MathHelper.interpolateLinear(whiteNoise[x1][y2], whiteNoise[x2][y2], xBlend);

            result[i][j] = (float) MathHelper.interpolateLinear(top, bottom, yBlend);
        }
    }
    return result;
}

public float[][] generatePerlinNoise(int width, int height, Random random, int octaveCount)
{
    float[][] whiteNoise = new float[width][height];
    float[][][] totalNoise = new float[octaveCount][][];
    float[][] perlinNoise = new float[width][height];
    float amplitude = 1.0f;
    float totalAmplitude = 0.0f;
    float persistance = 0.5f;

    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            whiteNoise[i][j] = random.nextFloat() % 1;
        }
    }
    for (int i = 0; i < octaveCount; i++)
    {
        totalNoise[i] = perlinNoise(width, height, i, whiteNoise);
    }
    for (int o = octaveCount - 1; o >= 0; o--)
    {
        amplitude *= persistance;
        totalAmplitude += amplitude;

        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                perlinNoise[i][j] += totalNoise[o][i][j] * amplitude;
            }
        }
    }
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            perlinNoise[i][j] /= totalAmplitude;
        }
    }
    return perlinNoise;
}

I think it would also be worth mentioning that I have asked about this on StackOverflow as well.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Just so you know, it will never INFINITELY tile, but you could make it pretty large (like, the range of a 32 or 64 bit floating point number) \$\endgroup\$
    – Alan Wolfe
    Jul 22, 2015 at 1:35
  • \$\begingroup\$ You might want to check out amortized noise instead of perlin, it looks like it has some nice benefits for a procedural world - like random access reads. jcgt.org/published/0003/02/02 \$\endgroup\$
    – Alan Wolfe
    Jul 22, 2015 at 1:49
  • 1
    \$\begingroup\$ I don't have a comprehensive answer for you but here's a link to a webgl pixel shader that generates a seamless mountain range. You will likely find useful info in it! shadertoy.com/view/MdX3Rr \$\endgroup\$
    – Alan Wolfe
    Jul 22, 2015 at 1:51
  • 1
    \$\begingroup\$ Lastly, here's a link to an explanation of "Wang tiling" which is a really great technique for making things out of tiles where the end result doesn't look tiled at all. blog.demofox.org/2014/08/13/wang-tiling \$\endgroup\$
    – Alan Wolfe
    Jul 22, 2015 at 1:53
  • \$\begingroup\$ @Alan Wolfe I eventually plan on having a spherical world, so technically it doesnt need to be infinite, because you would eventually end up where you started if you went in a straight line for a long time. But I shouldn't run before I can walk, I need to get perlin noise working first. Also FYI, I plan on doing this by mapping the vertices of a cube to a sphere, where each face of the cube is a large grid of chunks. \$\endgroup\$
    – Kelan
    Jul 22, 2015 at 12:18

1 Answer 1

4
\$\begingroup\$

Given credit to Alan Wolfe for what he said on "INFINITELY tile". A 2d perlin noise (or a 2d simple noise) will have no seam problem as far as you stay away from noise borders (defined by floatin point dimenision) Referencing the image: enter image description here

and said that you have chunks with 128X128 vertex, in chunk i,j you compute each vertex as :

for x : 0 .. 128-1
 for y : 0 .. 128-1
  PerlinNoise2d.getValue(i*128 + x, j*128 + y)

this , will grant seamless between chunks.

If you want to simulate a infinite world regardless of noise borders , you may use a 3d noise and consider the values on the surface of a sphere.. but this is another story.

\$\endgroup\$
4
  • \$\begingroup\$ Hmm... well, this is very useful, but the fact that my noise is value noise rather than perlin noise is an issue. I used this to implement it, and the article is unfortunately named perlin noise but I later found out it is actually value noise. I cant find any useful tutorial on a perlin noise implementation in java at all. \$\endgroup\$
    – Kelan
    Jul 22, 2015 at 11:57
  • \$\begingroup\$ Another thing that has just occured to me is would this work for chunks at negative grid-coords? your diagram starts at 0,0 but could it start at Float.MIN_VALUE or Double.MIN_VALUE ? Would this have an effect on the noise generated with negative coords? This question is probably stupid, but comes from my lack of understanding of perlin noise. \$\endgroup\$
    – Kelan
    Jul 22, 2015 at 12:28
  • \$\begingroup\$ @NervezXx Note that in Java, MIN_VALUE is the smallest possible positive non-zero value, not the largest negative value. \$\endgroup\$ Jul 22, 2015 at 14:03
  • \$\begingroup\$ Oh, I never knew this. I know that Integer.MIN_VALUE is a really large negative number, so I thought it was the same for Double and Float.MIN_VALUE \$\endgroup\$
    – Kelan
    Jul 22, 2015 at 14:18

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .