Skip to content

Instantly share code, notes, and snippets.

@reuk
Created July 12, 2013 20:53
Show Gist options
  • Save reuk/5987760 to your computer and use it in GitHub Desktop.
Save reuk/5987760 to your computer and use it in GitHub Desktop.
Megasimple raytracing sketch for processing. If I keep it 2D, I want to add support for beziers or splines or curves of some kind. Otherwise, I wanna add support for 3D triangles and have some kind of object loader. The idea is to take the focus of raytracing away from the final product (an image of an object) and instead focus on the rays thems…
class Ray {
private PVector origin = new PVector();
private PVector direction = new PVector();
private float length = MAX_FLOAT;
Ray(PVector o, PVector d) {
setorigin(o);
setdirection(d);
}
Ray() {this(new PVector(0, 0, 0), new PVector(0, 0, 0));}
void setorigin(PVector o) {origin = o;}
PVector getorigin() {return origin;}
void setdirection(PVector d) {direction = d; direction.normalize();}
PVector getdirection() {return direction;}
void setlength(float l) {length = 0 <= l ? l : length;}
float getlength() {return length;}
};
class ColorRay extends Ray {
private float intensity = 0;
ColorRay(PVector o, PVector d, float i) {
super(o, d);
setintensity(i);
}
void setintensity(float i) {intensity = 0 <= i && i <= 1 ? i : intensity;}
float getintensity() {return intensity;}
};
class Material {
private float reflective, transmissive;
Material(float r, float t) {
setreflective(r);
settransmissive(t);
}
Material() {this(0, 0);}
void setreflective(float r) {reflective = 0 <= r && r <= 1.0 ? r : reflective;}
float getreflective() {return reflective;}
void settransmissive(float t) {transmissive = 0 <= t && t <= 1.0 ? t : transmissive;}
float gettransmissive() {return transmissive;}
};
abstract class Primitive {
private Material material = new Material();
abstract boolean intersects(Ray r);
// only call if intersects(r) == true
abstract float distanceToIntersection(Ray r);
abstract PVector normalAt(Ray r);
abstract void display();
void setmaterial(Material m) {material = m;}
Material getmaterial() {return material;}
};
class InfinitePlane extends Primitive {
private PVector normal;
private float distance;
InfinitePlane(PVector n, float d) {
setnormal(n);
setdistance(d);
}
boolean intersects(Ray r) {
float dot = PVector.dot(normal, r.getdirection());
if (dot == 0) return false;
float d = distanceToIntersection(r);
return 0 < d;
}
float distanceToIntersection(Ray r) {
float dot = PVector.dot(normal, r.getdirection());
return (distance - PVector.dot(normal, r.getorigin())) / dot;
}
void display() {
stroke(0, 0, 255);
PVector grad = new PVector(-normal.y, normal.x);
float len = PVector.dist(new PVector(width, height), new PVector());
PVector pointOnLine = PVector.mult(normal, distance);
PVector point2 = PVector.mult(grad, len);
line(pointOnLine, PVector.add(pointOnLine, point2));
line(pointOnLine, PVector.sub(pointOnLine, point2));
}
void setnormal(PVector n) {normal = n; normal.normalize();}
PVector getnormal() {return normal;}
void setdistance(float d) {distance = d;}
float getdistance() {return distance;}
PVector normalAt(Ray r) {
float dot = PVector.dot(r.getdirection(), normal);
return dot > 0 ? normal : PVector.sub(new PVector(0, 0, 0), normal);
}
};
class MultiTree<T> {
T data;
ArrayList branch = new ArrayList();
MultiTree(T t) {
data = t;
}
void addBranch(MultiTree m) {
branch.add(m);
}
};
PVector rayOrigin = new PVector(0, 0);
PVector rayDirection = new PVector(random(-1, 1), random(-1, 1));
ArrayList primitive = new ArrayList();
MultiTree[] rayTree = new MultiTree[50];
float currentLength = 0;
void setup() {
size(400, 400);
colorMode(RGB, 1.0);
stroke(0);
for (int i = 0; i != 3; ++i) {
InfinitePlane plane = new InfinitePlane(new PVector(random(-1, 1), random(-1, 1)), random(width * 0.15, width * 0.25));
plane.setmaterial(new Material(0.5, 0.5));
primitive.add(plane);
}
generateNewTree();
// noLoop();
}
void draw() {
background(0);
translate(width / 2, height / 2);
float destLength = width;
currentLength += (destLength - currentLength) * 0.04;
for (int i = 0; i != rayTree.length; ++i) displayRayTree(rayTree[i], currentLength);
// saveFrame("####-ray.png");
}
void generateNewTree() {
for (int i = 0; i != rayTree.length; ++i) {
rayTree[i] = buildRayTree(new ColorRay(new PVector(0, 0), new PVector(random(-1, 1), random(-1, 1)), 1), primitive, 0, 20);
}
}
MultiTree buildRayTree(ColorRay r, ArrayList geometry, int currentDepth, int maxDepth) {
MultiTree ret = new MultiTree(r);
if (currentDepth == maxDepth) return ret;
if (r.getintensity() == 0.0) return ret;
Primitive intersected = new InfinitePlane(new PVector(1, 0, 0), 0);
boolean isIntersection = false;
for (int i = 0; i != geometry.size(); ++i) {
Primitive p = (Primitive)geometry.get(i);
if (p.intersects(r)) {
isIntersection = true;
float dist = p.distanceToIntersection(r);
if (dist <= r.getlength()) {
r.setlength(dist);
intersected = p;
}
}
}
if (!isIntersection) return ret;
PVector intersection = PVector.add(r.getorigin(), PVector.mult(r.getdirection(), r.getlength()));
float transmittedRayIntensity = r.getintensity() * intersected.getmaterial().gettransmissive();
ret.addBranch(buildRayTree(new ColorRay(intersection, r.getdirection(), transmittedRayIntensity), geometry, currentDepth + 1, maxDepth));
PVector objNormal = intersected.normalAt(r);
PVector newDirection = PVector.sub(r.getdirection(), PVector.mult(objNormal, 2.0 * PVector.dot(r.getdirection(), objNormal)));
float reflectedRayIntensity = r.getintensity() * intersected.getmaterial().getreflective();
ret.addBranch(buildRayTree(new ColorRay(intersection, newDirection, reflectedRayIntensity), geometry, currentDepth + 1, maxDepth));
return ret;
}
void displayRayTree(MultiTree r) {
ColorRay nextRay = (ColorRay)r.data;
stroke(1, nextRay.getintensity());
display(nextRay);
for (int i = 0; i != r.branch.size(); ++i) {displayRayTree((MultiTree)r.branch.get(i));}
}
void displayRayTree(MultiTree r, float maxLength) {
ColorRay nextRay = (ColorRay)r.data;
stroke(1, nextRay.getintensity());
float thisLength = maxLength - nextRay.getlength();
if (thisLength >= 0) {
display(nextRay);
for (int i = 0; i != r.branch.size(); ++i) {displayRayTree((MultiTree)r.branch.get(i), thisLength);}
} else {
display(nextRay, maxLength);
}
}
void display(Ray r, float distance) {
line(r.getorigin(), PVector.add(r.getorigin(), PVector.mult(r.getdirection(), distance)));
}
void display(Ray r) {
final float max = sqrt(width * width + height * height);
display(r, r.getlength() == MAX_FLOAT ? max : r.getlength());
}
void line(PVector a, PVector b) {
line(a.x, a.y, b.x, b.y);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment