How to connect perlin noise seamlessly?

I’m making procedural terrain generation with perlin noise
My problem here is that when I put a few chunks generated by perlin noise next together, they dont connect, how do I make them connect seamlessly?

I do not think it is meant to tile unfortunately.

Maybe @Evgeni_Popov has a trick ?

1 Like

Well other games do it so I assume there must be a way
Maybe I should be using another type of noise? Idk

A trick I used was to generate 3d perlin noise and sample a tube. as the tube would loop, so is the 2D perlin.

2 Likes

Sorry i don’t understand that
Can u explain it more?

let me do it with pseudo code:

for(let y = 0;y < 256;y++)
{
for(let x = 0;x < 256;x++)
{
const rotationAngle = (x / 256) * 2 * Math.PI; // full circle from x
coordinate.x = Math.cos(rotationAngle);
coordinate.y = y / 256;
coordinate.z = Math.sin(rotationAngle);
const perlinValue = perlin3D(coordinate);
}
}

This will sample a tube in a perlin 3D. produced values will tile on 1 dimension.
Sample a torus to have tile in 2 dimensions.

3 Likes

Sorry but I dont know how to implement this in my code

This is what I currently have:

function chunkPosition({ x, y }) {
  const resultX = Math.floor(x / 32);
  const resultY = Math.floor(y / 32);

  return { x: resultX, y: resultY };
};

function chunk({ px, py }, seed) {
  let n = new perlinNoise3d();
  n.noiseSeed(seed);

  let size = 16;
  let output = [];
  for (let x = 0; x < size; x++) {
    for (let y = 0; y < size; y++) {
      output.push({ x: x+px, y: y+py, value: n.get(x / 12, y / 12) });
    };
  };
  return output;
};

let chunks = [];
  
  async function loadChunk({ posX, posY }) {
    let b1;
    let first = false;
    let chunkData = [];
    
    for (const block of chunk({ px: posX*16, py: posY*16 }, (Math.random() * 6000))) {
      if (first == false) {
        b1 = block;
        first = true;
      };

      createBlock('grass', { x: block.x-8, y: Math.round((block.value*10)/2)-2, z: block.y-8 });
      chunkData.push({ type: 'grass', position: { x: block.x-8, y: Math.round((block.value*10)/2)-2, z: block.y-8 }});
      
      for (let i = 1; i < 6; i++) {
        //createBlock('dirt', { x: block.x-8, y: Math.round((block.value*10)/2)-2-i, z: block.y-8 });
        //chunkData.push({ type: 'grass', position: { x: block.x-8, y: Math.round((block.value*10)/2)-2-i, z: block.y-8 }});
      };
    }; scene.blockMaterialDirtyMechanism = false;
    
    let chunkPos = chunkPosition({ x: b1.x , y: b1.y });
    chunks.push({ position: chunkPos, data: chunkData });
  };

  loadChunk({ posX: 0, posY: 0 });
  loadChunk({ posX: 1, posY: 0 });
  loadChunk({ posX: 0, posY: 1 });
  loadChunk({ posX: 1, posY: 1 });

And i’m using this module to generate noise (thats why I couldnt create a playground)

Could you try to ask them if you rely on their package ? Maybe they have a trick for it ?

but you are providing a new random seed for each of your chucks , this wont tile.

you need to use the same seed and “scroll” the noise function in a manner that makes sense for the position of the chuck

looking at the module sample code , you would use this

noise.get(x,y,z)

you do not need to create a new instance of the perline noise or apply the seed more than once , so do that outside the code that generates the chucks , then just use this function to get the tile from the function you need

4 Likes

I tried using the same seed but it just loaded the same copy 4 times

Do you have a playground?

I didn’t only say use the same seed, read my response properly and do your research into how to use the offsets of the noise function :grinning:

1 Like