Created
August 15, 2017 03:23
-
-
Save PatrickMurphy/e1edb6577b7759421cf7d8aef3531008 to your computer and use it in GitHub Desktop.
Brownian Terrain
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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