10 minute code: 3D Perlin noise Terrain in Processing

Perlin noise is a powerful way to generate cloud-like texture. Here I use it to generate height values and then connect them into a mesh of triangles, resulting in a random 3D terrain. Read on for all the code!

// how big is the terrain
int mapSizeX = 256;  // # of dots
int mapSizeY = 256;  // # of dots
int mapHeight = 300;  // scale

// perlin noise values
// larger scale makes the terrain more bumpy
float xScale = 0.01;
float yScale = 0.01;
// adj moves the terrain
float xAdj = 0;
float yAdj = 0.002;
float speedX = 0.01;
float speedY = 0.001;

// where to store the terrain data
PVector [] points;


void setup() {
  size(800,800,P3D);
  createMap();
  generateMap();
}

void createMap() {
  points = new PVector[mapSizeX*mapSizeY];
  int i=0;
  
  for(int y=0;y<mapSizeY;++y) {
    for(int x=0;x<mapSizeX;++x) {
      points[i++] = new PVector();
    }
  }
}

void generateMap() {
  int i=0;
  
  for(int y=0;y<mapSizeY;++y) {
    for(int x=0;x<mapSizeX;++x) {
      float z = noise(x*xScale + xAdj,
                      y*yScale + yAdj);
      points[i++].set(x-mapSizeX/2,
                      y-mapSizeY/2,
                      z);
    }
  }
}

void draw() {
  background(0);
  translate(width/2,height/2);
  rotateX(mouseX*0.01);
  rotateY(mouseY*0.01);
  
  xAdj+=speedX;
  yAdj+=speedY;
  generateMap();
  
  //drawMap1();
  drawMap2();
}

void drawMap1() {
  int i=0;
  beginShape(POINTS);
  for(int y=0;y<mapSizeY;++y) {
    for(int x=0;x<mapSizeX;++x) {
      mapPoint(points[i++]);
    }
  }
  endShape();
}

void drawMap2() {
  for(int y=0;y<mapSizeY-1;++y) {
    beginShape(TRIANGLE_STRIP);
    for(int x=0;x<mapSizeX;++x) {
      PVector p0 = points[mapAddr(x,y)];
      PVector p3 = points[mapAddr(x,y+1)];
      mapPoint(p0);
      mapPoint(p3);
    }
    endShape();
  }
}

void mapPoint(PVector p) {
  wheel(p.z*255f);
  vertex(p.x*3,  // bigger for show
         p.y*3,  // bigger for show
         p.z*mapHeight-mapHeight/2);
}

int mapAddr(int x,int y) {
  return y * mapSizeX + x;
}

// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
// thanks, adafruit!
void wheel(float WheelPos) {
  float r,g,b;
  if(WheelPos < 85) {
    r=255 - WheelPos * 3;
    g=0;
    b=WheelPos * 3;
  } else if(WheelPos < 170) {
    WheelPos -= 85;
    r=0;
    g=WheelPos * 3;
    b=255 - WheelPos * 3;
  } else {
    WheelPos -= 170;
    r=WheelPos * 3;
    g=255 - WheelPos * 3;
    b=0;
  }

  fill(r,g,b);
  stroke(r,g,b);
}