boolean rendererd = false; int renderY = 0; int LineBuf[];
float clamp(float val, float min, float max) { if (val < min) { return min; } else if (val > max) { return max; } else { return val; } }
vec reflection(vec v, vec normal) { return v.add(normal.scale(-2 * v.dot(normal))); }
int fcolor(float r, float g, float b) { int ir = (int)(clamp(r, 0, 1) * 255.99); int ig = (int)(clamp(g, 0, 1) * 255.99); int ib = (int)(clamp(b, 0, 1) * 255.99); return color(ir, ig, ib); }
class Scene { ArrayList objs; ArrayList lights;
Scene() { objs = new ArrayList(); lights = new ArrayList(); }
void add_obj(Object obj) { objs.add(obj); }
void add_light(PointLight light) { lights.add(light); }
void find_nearest_intersect_with_ray(Intersect isect, vec orig, vec dir) { isect.t = -1; vec normal = new vec(0, 0, 0); for (int i=objs.size(); --i>=0; ) { Object obj = (Object)objs.get(i); float t = obj.intersect_line(normal, orig, dir); if (t >= 0 && (isect.t < 0 || t < isect.t)) { isect.t = t; isect.normal.set(normal); isect.obj = obj; } } }
boolean intersect_anything(vec orig, vec target) { vec diff = target.sub(orig); float len = diff.length(); vec dir = diff.scale(1.0 / len); vec normal = new vec(0, 0, 0); for (int i=objs.size(); --i>=0; ) { Object obj = (Object)objs.get(i); float t = obj.intersect_line(normal, orig, dir); if (t >= 0 && t < len) { return true; } } return false; }
vec shading(vec pos, vec normal, Material material, vec raydir) { vec col = new vec(0, 0, 0); float a = material.reflection; if (a < 1) { col = col.add(calc_diffuse(pos, normal, material).scale(1 - a)); } if (a > 0) { col = col.add(calc_reflection(pos, normal, raydir).scale(a)); } return col; } vec calc_diffuse(vec pos, vec normal, Material material) { vec col = new vec(0, 0, 0); for (int i=lights.size(); --i>=0; ) { PointLight light = (PointLight)lights.get(i); if (visible(pos, light.pos)) { col = col.add(light.shading(pos, normal, material)); } } return col; } vec calc_reflection(vec pos, vec normal, vec raydir) { vec refvec = reflection(raydir, normal); return raytrace(pos, refvec); }
vec raytrace(vec orig, vec raydir) { Intersect isect = new Intersect(); find_nearest_intersect_with_ray(isect, orig, raydir); if (isect.is_enable()) { vec pos = orig.add(raydir.scale(isect.t)); return shading(pos, isect.normal, isect.obj.material, raydir); } else { return new vec(0, 0, 0); } }
boolean visible(vec pos, vec target) { return !intersect_anything(pos, target); } }
vec eyepos = new vec(0, 0, -1); Scene scene;
void setup() { size(256, 256); LineBuf = new int[width];
scene = new Scene(); { Material material = new Material(1, 0, 0); material.reflection = 0.5; scene.add_obj(new Sphere(new vec(0, 0, 0), 0.5, material)); } { Material material = new Material(0, 1, 0); material.grid = 0.25001; material.diffuse2.set(0, 0, 1); scene.add_obj(new Plane(0, 1, 0, 0.5, material)); } scene.add_light(new PointLight(new vec(1000, 1000, -1000), new vec(2, 2, 2))); }
void draw() { if (rendererd) { return; }
render_line(LineBuf, width, height, renderY); copy_line(LineBuf, renderY); if (++renderY >= height) { rendererd = true; } }
void copy_line(int[] img, int y) { loadPixels(); for (int i = 0; i < width; ++i) { pixels[y * width + i] = img[i]; } updatePixels(); }
void render_line(int[] img, int width, int height, int iy) { float w2 = width / 2; float h2 = height / 2; float xofs = w2 - 0.5; float yofs = h2 - 0.5; float py = -((iy - yofs) / h2);
vec normal = new vec(0, 0, 0); for (int j=0; j<width; ++j) { float px = (j - xofs) / w2; vec raydir = (new vec(px, py, 1)).normal(); vec col = scene.raytrace(eyepos, raydir); img[j] = fcolor(col.x, col.y, col.z); } }
|