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);
}