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; } }
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); }
float intersect_line_sphere(vec orig, vec dir, vec sphere_center, float sphere_radius) { vec c = sphere_center; vec s = orig; vec d = dir; float r = sphere_radius; vec v = s.sub(c);
float dd = sq(v.dot(d)) - (v.dot(v) - sq(r)); if (dd < 0) { return -1; } else { float sqdd = sqrt(dd); float t1 = -v.dot(d) - sqdd; return t1; } }
float intersect_line_plane(vec orig, vec dir, float a, float b, float c, float d) { float h = orig.x * a + orig.y * b + orig.z * c + d; if (h < 0) { return -1; } else { float inner = dir.x * a + dir.y * b + dir.z * c; if (inner >= 0) { return -1; } else { return h / (-inner); } } }
class Material { vec diffuse = new vec(0, 0, 0); vec emissive = new vec(0, 0, 0);
Material(float difr, float difg, float difb) { diffuse.set(difr, difg, difb); emissive.set(0, 0, 0); } };
class Object { Material material;
float intersect_line(vec pNrm, vec orig, vec dir) { return -1; } }
class Sphere extends Object { vec center; float radius;
Sphere(vec _center, float _radius, Material _material) { center = _center; radius = _radius; material = _material; }
float intersect_line(vec normal, vec orig, vec dir) { float t = intersect_line_sphere(orig, dir, center, radius); if (t >= 0) { vec pos = new vec(orig.add(dir.scale(t))); normal.set(pos.sub(center).normal()); } return t; } }
class Plane extends Object { float a, b, c, d;
Plane(float _a, float _b, float _c, float _d, Material _material) { a = _a; b = _b; c = _c; d = _d; material = _material; }
float intersect_line(vec normal, vec orig, vec dir) { float t = intersect_line_plane(orig, dir, a, b, c, d); if (t >= 0) { normal.set(a, b, c); } return t; } }
class PointLight { vec pos; vec col;
PointLight(vec _pos, vec _col) { pos = _pos; col = _col; }
vec shading(vec hitpos, vec normal, Material material) { vec lv = pos.sub(hitpos).normal(); float f = max(normal.dot(lv), 0); return new vec(f * material.diffuse.x * col.x, f * material.diffuse.y * col.y, f * material.diffuse.z * col.z); } }
class Intersect { float t = -1; vec normal = new vec(0, 0, 0); Object obj = null;
boolean is_enable() { return t >= 0; } }
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; }
int shading(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 fcolor(col.x, col.y, col.z); }
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(); scene.add_obj(new Sphere(new vec(0, 0, 0), 0.5, new Material(1, 1, 1))); scene.add_obj(new Plane(0, 1, 0, 0.5, new Material(1, 1, 1))); scene.add_light(new PointLight(new vec( 500, 1000, -500), new vec(1, 0, 0))); scene.add_light(new PointLight(new vec(-500, 1000, -500), new vec(0, 1, 0))); scene.add_light(new PointLight(new vec( 0, 1000, +100), new vec(0, 0, 1))); }
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); Intersect isect = new Intersect(); for (int j=0; j<width; ++j) { float px = (j - xofs) / w2; vec raydir = (new vec(px, py, 1)).normal();
scene.find_nearest_intersect_with_ray(isect, eyepos, raydir); if (isect.is_enable()) { vec pos = eyepos.add(raydir.scale(isect.t)); img[j] = scene.shading(pos, isect.normal, isect.obj.material); } else { img[j] = color(0, 0, 0); } } }
|