pixelColor = {
let { objects, lights, camera, viewport } = scene;
function pixelRay (px,py) {
let pointOnProjectionPlane = Vector3(camera.xsize*px/viewport.width+camera.xmin,
camera.ymin + camera.ysize -camera.ysize*py/viewport.height);
return new Ray (camera.pos, vec3.sub(vec3.create(),pointOnProjectionPlane,camera.pos))
}
function firstHit (ray) {
let intersections = objects.map(obj=>[obj.g.intersect(ray),obj])
intersections = intersections.filter(([dist,obj])=> dist > 0.001 && dist < Number.MAX_VALUE);
if (intersections.length == 0) return false;
return intersections.reduce ((a,b) => a[0]<b[0] ? a : b);
}
let black = Vector3 (0,0,0);
function raytrace (ray, level = 1) {
let hit = firstHit(ray);
if (!hit) return black;
let [dist,obj] = hit;
let {c,a,d,s,e} = obj.m;
// The final color starts with the ambient color
let rgb = vec3.scale (vec3.create(),c,a);
// The hit point
let q = ray.at(dist);
// The hit normal
let n = obj.g.normal(q);
// Vector from surface point to viewer
let qv = vec3.negate (vec3.create(), ray.v);
vec3.normalize(qv,qv);
// Take into account each light
for (let {p,l} of lights) {
// Vector from surface point to light position
let qp = vec3.sub (vec3.create(), p, q);
let lightDist = vec3.length(qp);
vec3.normalize(qp,qp);
// Cast shadow ray
let shadowRay = new Ray(q,qp);
let shadowHit = firstHit (shadowRay);
if (!shadowHit || shadowHit[0] >= lightDist) {
// Compute diffuse color
vec3.scaleAndAdd (rgb, rgb, c, d * Math.max(0, vec3.dot (qp, n)));
}
// Non-recursive specular computation if term non-zero
if (level <= 0 && s > 0) {
let ref = reflection(vec3.create(),qp,n);
if (ref) {
vec3.scaleAndAdd (rgb, rgb, l, s * Math.pow (vec3.dot (ref,qv), e));
}
}
}
// Recursive specular computation if term non-zero
if (level > 0 && s > 0) {
// Reflected vector
let ref = reflection(vec3.create(),qv,n);
if (ref) {
let color = raytrace(new Ray(q,ref), level-1);
vec3.scaleAndAdd (rgb,rgb, color, s)
}
}
// Clamp to 1
vec3.min (rgb, rgb, Vector3(1,1,1))
return rgb
}
return function (px,py) {
let ray = pixelRay (px,py);
let color = raytrace(ray,1);
vec3.scale(color,color,255);
return color
}
}