Skip to content

Instantly share code, notes, and snippets.

@PatrickMurphy
Created August 15, 2017 03:23
Show Gist options
  • Save PatrickMurphy/e1edb6577b7759421cf7d8aef3531008 to your computer and use it in GitHub Desktop.
Save PatrickMurphy/e1edb6577b7759421cf7d8aef3531008 to your computer and use it in GitHub Desktop.
Brownian Terrain
class BrownianPoint extends PVector {
int mode;
PVector last;
float firstLoad;
BrownianPoint(float x, float y, float load, int mode) {
this.x = x;
this.y = y;
this.z = load;
this.mode = mode;
this.last = PVector.random2D();
this.firstLoad = load;
}
void update() {
if (mode == 0)
randomBehavior();
else if (mode == 1)
randomThresholdBehavior();
else if (mode == 2)
randomThresholdScaleBehavior();
if (z>0)
if (terrain.deposit(floor(x), floor(y), 5)) {
z--;
}
}
void display() {
if (terrain.onMap(floor(x), floor(y)))
ellipse(x, y, 4, 4);
}
void randomBehavior() {
PVector offset = PVector.random2D();
this.add(offset);
}
void randomThresholdBehavior() {
PVector offset = last;
if (random(100)>90) {
offset = PVector.random2D();
last = offset;
}
this.add(offset);
}
void randomThresholdScaleBehavior() {
PVector offset = last;
if (random(100)>z/firstLoad) {
offset = PVector.random2D();
last = offset;
}
this.add(offset);
}
}
import peasy.*;
import peasy.org.apache.commons.math.*;
import peasy.org.apache.commons.math.geometry.*;
ArrayList<BrownianPoint> points;
HeightMap terrain;
TerrainMap terrainMap;
PeasyCam cam;
int map_size;
void setup() {
size(800, 600, P3D);
points = new ArrayList<BrownianPoint>();
map_size = 200;
terrain = new HeightMap(map_size, map_size);
terrainMap = new TerrainMap(600, new PVector(map_size, 0));
cam = new PeasyCam(this, (map_size/2)*terrainMap.cellScale, (map_size/2)*terrainMap.cellScale, terrainMap.getHeight(map_size/2, map_size/2, terrainMap.cellScale), 125);
for (int i = 0; i < 55; i++) {
points.add(new BrownianPoint(random(map_size), random(map_size), random(1000, 5000), 2));
}
}
void draw() {
background(0);
// 3D
//hint(ENABLE_DEPTH_TEST);
lights();
terrainMap.update();
terrainMap.display();
// 2D
// hint(DISABLE_DEPTH_MASK);
cam.beginHUD();
noLights();
textMode(MODEL);
fill(color(55));
rect(0, 0, map_size, height);
fill(255);
image(terrain.img, 0, 0);
image(terrain.img, 0, map_size);
for (BrownianPoint bp : points) {
bp.update();
bp.display();
}
cam.endHUD();
}
void keyPressed() {
if (key == 'b')
terrain.blur();
}
class HeightMap {
PImage img;
int wd, ht;
float[][] blur_matrix = { {1/9, 1/9, 1/9 },
{ 1/9, 1/9, 1/9 },
{ 1/9, 1/9, 1/9 } };
HeightMap(int wd, int ht) {
img = createImage(wd, ht, RGB);
img.loadPixels();
for (int i = 0; i < wd; i++)
for (int j = 0; j < ht; j++)
img.set(i, j, color(0));
this.wd = wd;
this.ht = ht;
}
Boolean onMap(int x, int y) {
return x>=0 && y>=0 && x<wd && y <= ht;
}
Boolean deposit(int x, int y, int val) {
if (this.onMap(x, y)) {
img.set(x, y, color(red(img.get(x, y))+val, 0, 0));
img.updatePixels();
return true;
} else {
return false;
}
}
void blur() {
println("blur");
img.loadPixels();
// Begin our loop for every pixel
for (int x = 0; x < img.width; x++) {
for (int y = 0; y < img.height; y++ ) {
// Each pixel location (x,y) gets passed into a function called convolution()
// which returns a new color value to be displayed.
color c = convolution(x, y, blur_matrix, 3);
img.set(x,y,c);
}
}
img.updatePixels();
}
color convolution(int x, int y, float[][] matrix, int matrixsize) {
float rtotal = 0.0;
float gtotal = 0.0;
float btotal = 0.0;
int offset = matrixsize / 2;
// Loop through convolution matrix
for (int i = 0; i < matrixsize; i++) {
for (int j= 0; j < matrixsize; j++) {
// What pixel are we testing
int xloc = x+i-offset;
int yloc = y+j-offset;
int loc = xloc + img.width*yloc;
// Make sure we have not walked off the edge of the pixel array
loc = constrain(loc, 0, img.pixels.length-1);
// Calculate the convolution
// We sum all the neighboring pixels multiplied by the values in the convolution matrix.
rtotal += (red(img.pixels[loc]));
//gtotal += (green(img.pixels[loc]) * matrix[i][j]);
//btotal += (blue(img.pixels[loc]) * matrix[i][j]);
}
}
// Make sure RGB is within range
//rtotal = constrain(rtotal, 0, 255);
//gtotal = constrain(gtotal, 0, 255);
// btotal = constrain(btotal, 0, 255);
// Return the resulting color
return color(rtotal/9, 0, 0);
}
}
class TerrainMap {
int size;
float cellScale;
PVector position;
float maxHeight;
float minHeight;
color[] levels;
TerrainMap(int size, PVector position) {
this.size = size;
this.position = position.copy();
this.cellScale = 5;
this.maxHeight = 0;
this.minHeight = -1;
levels = new color[]{color(30, 144, 255),color(222, 184, 135),color(75, 147, 65),color(85, 165, 94),color(6, 109, 51),color(155, 105, 12),color(124, 83, 7),color(235,235,235)};
}
void update() {
}
void display() {
pushMatrix();
translate(position.x, position.y);
// rotateY(frameCount/5000.0);
// rotateX(frameCount/300.0);
terrain.img.loadPixels();
maxHeight = -100000;
minHeight = 10000000;
for (int y = 0; y<terrain.img.height-1; y++) {
beginShape(TRIANGLE_STRIP);
for (int x = 0; x<terrain.img.width; x++) {
float h1 = getHeight(x, y, 5);
float h2 = getHeight(x, y+1, 5);
maxHeight = max(maxHeight, h1,h2);
minHeight = min(minHeight,h1,h2);
fill(levels[floor(map((h1+h2)/2,minHeight,maxHeight,0,7))]);
noStroke();
vertex(x*cellScale, y*cellScale, h1);
vertex(x*cellScale, (y+1)*cellScale, h2);
}
endShape();
}
popMatrix();
}
float getHeight(int x, int y) {
return getHeight(x, y, 1);
}
float getHeight(int x, int y, float scale) {
return red(terrain.img.get(x, y))*scale;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment