Perlin noise function not working as intended

40 Views Asked by At

I have a simple perlin noise function that has the parameters x, y, z, and seed. When I draw the perlin noise to the canvas using the function, the pattern which the perlin noise generates repeats over and over (kinda in a grid pattern) instead of being pseudo-random.

Here is my code:

function perlinNoise(x, y, z, seed) {
  function fade(t) {
    return t * t * t * (t * (t * 6 - 15) + 10);
  }

  function lerp(t, a, b) {
    return a + t * (b - a);
  }

  function grad(hash, x, y, z) {
    var h = hash & 15;
    var u = h < 8 ? x : y,
      v = h < 4 ? y : h == 12 || h == 14 ? x : z;
    return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
  }

  function scale(n) {
    return ((1 + n) / 2);
  }

  // Generate the permutation array based on the seed
  var p = new Array(512);
  var permutation = [];
  for (var i = 0; i < 256; i++) {
    permutation.push(seed ? (seed + i) % 256 : i);
  }
  for (var i = 0; i < 256; i++) {
    p[256 + i] = p[i] = permutation[i];
  }


  var X = Math.floor(x) & 255,
    Y = Math.floor(y) & 255,
    Z = Math.floor(z) & 255;
  x -= Math.floor(x);
  y -= Math.floor(y);
  z -= Math.floor(z);
  var u = fade(x),
    v = fade(y),
    w = fade(z);
  var A = p[X] + Y,
    AA = p[A] + Z,
    AB = p[A + 1] + Z,
    B = p[X + 1] + Y,
    BA = p[B] + Z,
    BB = p[B + 1] + Z;

  return scale(lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z),
        grad(p[BA], x - 1, y, z)),
      lerp(u, grad(p[AB], x, y - 1, z),
        grad(p[BB], x - 1, y - 1, z))),
    lerp(v, lerp(u, grad(p[AA + 1], x, y, z - 1),
        grad(p[BA + 1], x - 1, y, z - 1)),
      lerp(u, grad(p[AB + 1], x, y - 1, z - 1),
        grad(p[BB + 1], x - 1, y - 1, z - 1)))));
}



// Helper function for 2d perlin noise
function perlin2D(x, y, seed) {
  return perlinNoise(x, y, 0, seed);
}

var scene = document.getElementById("scene");
var ctx = scene.getContext("2d");

scene.width = window.innerWidth;
scene.height = window.innerHeight;

for (var x = 0; x < scene.height / 3; x++) {
  for (var y = 0; y < scene.height / 3; y++) {
    var perlinValue = perlin2D(x / 10, y / 10, 384);
    ctx.fillStyle = `rgb(${perlinValue * 255}, ${perlinValue * 255}, ${perlinValue * 255})`;
    ctx.fillRect(x, y, 1, 1);
  }
}
*,
*:before,
*:after {
  font-family: roboto, Arial, Helvetica, sans-serif, system-ui;
  padding: 0px 0px;
  margin: 0px 0px;
  box-sizing: border-box;
}

canvas {
  display: block;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <canvas id="scene"></canvas>
</body>

</html>

(Note: The way I am drawing the perlin noise is very inefficient and take awhile to load).

Strangely, The 1D perlin noise does work using this function.

0

There are 0 best solutions below