Help with noise map (terrain map)

Hi there,

I’m trying to find a way to make an animated graphic similar in appearance to a poster I found online. Is there a way to programmatically make this noise map have more clustered areas and less noisy like here? Thanks.

My code:

// noise map

color black = color(0, 0, 0);
color green = color(64, 128, 64);
color blue = color(0, 126, 192);
color mustard = color(187, 162, 24);
color white = color(255, 255, 255);

int numImages = 8;
PImage[] images = new PImage[numImages];

int seed = int(random(1000000));
int[] sizes = { 20 }; // { 20, 40 }
int lstep = sizes[sizes.length - 1];
int step;

float d0, d1, dz, dv;

void setup() {
  size(600, 800);
  frameRate(25);
  noStroke();

  randomSeed(seed);

  step = sizes[int(random(sizes.length))];
  d0 = random(100, 200);
  d1 = random(25, 75);
  dz = random(0, 100);
  dv = random(0, 0.1);

  textFont(createFont("IBMPlexMono-Medium.ttf", 50));
  textAlign(LEFT, TOP);

  for (int i = 0; i < numImages; i++) {
    String imageName = "data/F" + nf(i, 2) + ".png";
    images[i] = loadImage(imageName);
  }

}

void draw() {
  
  //background(blue);

  // noise map

    for (int j = 0; j < height; j += step) {
      for (int i = 0; i < width; i += step) {
        
        float n0 = noise(i / d0, j / d0, dz);
        float n1 = noise(i / d1, j / d1, dz + 10);
        float n = 1 - (n0 * 0.75 + n1 * 0.25);

        int k = int(n * images.length);

        fill(lerpColor(blue, white, n));
        rect(i, j, step, step);
        image(images[k], i, j, step, step);
        
      }
    }

  // typography

  fill(255);
  rect(0, lstep * 2, lstep * 6, lstep);
  fill(0);
  textSize(lstep * 0.7);
  text("noise map", lstep / 2, lstep * 2);

  fill(255);
  rect(0, height - lstep, width, lstep);
  fill(0);
  text("#" + seed, lstep / 2, height - lstep + lstep / 8);

  dz += dv;
  
}

void keyPressed() {
  
  seed = int(random(1000000));
  step = sizes[int(random(sizes.length))];
  d0 = random(100, 200);
  d1 = random(25, 75);
  dz = random(0, 100);
  dv = random(0, 0.1);
  
}

Here are the files on GitHub.

Hi figle, are you able to explain in a bit more detail the effect you want to achieve? What do you mean by noisy? The animation, or the scale of the noise in terms of contrast? Looking at your code, I’m not entirely sure why you are randomising the d0, d1, dz and dv params. Noise itself takes care of all of the randomness? Lowering the step sizes for noise in general makes things smoother.

1 Like

Hi @rapatski,

I want to achieve a similar effect to the linked poster – a kind of abstract terrain map, with random areas or “countries” which would then have a specific pattern applied.

For my code I have adapted an example with Perlin noise but it doesn’t really do the trick (randomising the params is just for me to see how it changes appearance). However, I see here that Perlin noise has been used to a kind of satisfying effect.

Ahh OK so what’s going on in both these references is that the noise is used as a kind of ‘map’ to sample from, and display different assets or graphics depending on the brightness of the pixel/cell. It’s similar to how ASCII art is done (there is an example in the Topics > Library > Video I believe).

So first, load a bunch of different images into an array in setup(). Say about 5 of them. (or alternatively, colours for rects)

Then, use your noise to draw into a separate PGraphics object (think of an PGraphics object as another sketch window, but then stored in a variable), also called an offscreen buffer. Do it exactly the same as you normally do, but this time into the PGraphics object. See here: PGraphics \ Language (API).

When that is done, call loadPixels() on that object, and cycle through all pixels and get their brightness. Depending on that brightness, you display a different image asset (or render a different colour rect), like so:

// this snippet assumes you've created a PGraphics object named pg
// and that you've defined a grid by means of numCols and numRows vars

pg.loadPixels();
for (int i = 0; i < numCols; i++)
{
  for (int j = 0; j < numRows; j++)
  {
    // this is to find the right pixel in the sampling pgraphics
    int sampleX = i * pg.width / numCols;
    int sampleY = j * pg.height / numRows;
    int pixelIndex = j * pg.width + i;
    float br = brightness(pg.pixels[pixelIndex]);

    // and here you draw the cell with the right asset
    int cellX = i * width / numCols;
    int cellY = j * height / numRows;
    int cellW = width / numCols;
    int cellH = height / numRows;

    if (br < 50)
      image(images[0], cellX, cellY, cellW, cellH);
    else if (br < 100)
      image(images[1], cellX, cellY, cellW, cellH);
    else if (br < 150)
      image(images[2], cellX, cellY, cellW, cellH);
    // etc.
  }
}

I’ve not tested the above, but it should point you in the right direction.