Skip to content

Instantly share code, notes, and snippets.

@FlorianCassayre
Created June 4, 2019 09:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FlorianCassayre/91dd3165adfdc3707f7d861cab4db57c to your computer and use it in GitHub Desktop.
Save FlorianCassayre/91dd3165adfdc3707f7d861cab4db57c to your computer and use it in GitHub Desktop.
final int margin = 200;
int sampled = 0;
float[][] acc;
final PVector light = new PVector(2, 1, 1).normalize();
void setup() {
size(800, 800);
acc = new float[height][width];
noiseSeed(0);
}
void draw() {
background(255);
for(int y = 0; y < height; y++) {
for(int x = 0; x < width; x++) {
final float h = heightAt(x, y);
final float dh = 0.1;
final PVector point = new PVector(x, y, h + dh), n = normalAt(x, y);
final float ambient = trace(point, randomHemisphere(n).mult(1), 100);
final float r = 0.2;
float direct = floor(trace(point, light.copy().add(new PVector(random(-r, r), random(-r, r), random(-r, r))).mult(1), 150));
final float ratio = 0.5;
final float total = 1.0;
acc[y][x] = (acc[y][x] * sampled + (1 - total) + total * (ambient * (1 - ratio) + direct * ratio)) / (sampled + 1);
set(x, y, color(acc[y][x] * 255));
}
}
sampled++;
}
void keyPressed() {
if(key == 's')
saveFrame();
}
float trace(PVector pos, PVector dir, int iterations) {
final PVector point = pos.copy();
for(int i = 0; i < iterations; i++, point.add(dir))
if(heightAt(point.x, point.y) >= point.z)
return (float) i / iterations;
return 1.0;
}
float heightAt(float x, float y) {
final float scale = 0.03, minHeight = 0, maxHeight = 50;
return isInside(x, y) ? (maxHeight - minHeight) * noise(x * scale, y * scale) + minHeight : 0;
}
PVector normalAt(float x, float y) {
final float d = 3;
if(isInside(x, y)) {
final float dxmin = max(x - d, x + margin), dxmax = min(x + d, width - margin), dymin = max(y - d, y + margin), dymax = min(y + d, height - margin);
final float dx = (heightAt(dxmax, y) - heightAt(dxmin, y)) / (dxmax - dxmin), dy = (heightAt(x, dymax) - heightAt(x, dymin)) / (dymax - dymin);
return new PVector(-dx, -dy, 1).normalize();
} else {
return new PVector(0, 0, 1);
}
}
boolean isInside(float x, float y) {
return x >= margin && x < width - margin && y >= margin && y < height - margin;
}
PVector randomHemisphere(PVector n) {
while(true) {
final PVector v = new PVector(random(-1, 1), random(-1, 1), random(-1, 1));
final float lenSq = v.magSq();
if(lenSq > 1 || n.dot(v) < 0)
continue;
return v.div(sqrt(lenSq));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment