Thursday, February 6, 2020

java - Tiling perlin noise seamlessly, but without repeating to generate an infinite 3D world


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.



Answer



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.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...