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\$
  • 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 '15 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 '15 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 '15 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 '15 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 '15 at 12:18
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\$
  • \$\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 '15 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 '15 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\$ – Lars Viklund Jul 22 '15 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 '15 at 14:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.