I've been following Ray Tracing In One Weekend in Javascript and have been doing well until it was time to implement diffuse lighting. After a lot of debugging, the output it produced didn't match the expected output.
The diffuse lighting cuts off sharply, almost resembling reflections instead? I have no clue what has cause this to happen; perhaps there's something wrong with how new rays are calculated?
Here are some of the most important chunks of code:
This is a recursive function that calculates colour output from rays
function rayColour(r, world, depth) {
if (depth <= 0) {
return new Colour(0, 0, 0);
}
var rec = world.hit(r, 0, infinity, rec);
if (rec[0]) {
var target = rec[1].p.add(rec[1].normal).add(randomInUnitSphere());
return rayColour(new Ray(rec[1].p, target.subtract(rec[1].p)), world, depth-1).multiply(0.5);
}
var unitDirection = normalize(r.dir);
var t = 0.5 * (unitDirection.y + 1);
return new Colour(1, 1, 1).multiply(1-t).add(new Colour(0.5, 0.7, 1).multiply(t));
}
Main rendering function for a pixel
for(var p = 0; p < ppt; p++) {
var i = curPixel % WIDTH;
var j = HEIGHT-1 - Math.floor(curPixel / WIDTH);
var pixelColour = new Colour(0, 0, 0);
for (var s = 0; s < samplesPerPixel; ++s) {
var u = (i + Math.random()) / (WIDTH-1);
var v = (j + Math.random()) / (HEIGHT-1);
var r = cam.getRay(u, v);
pixelColour = pixelColour.add(rayColour(r, world, maxDepth));
}
putPixel(i, HEIGHT-1-j, pixelColour, samplesPerPixel);
curPixel++;
}
Sphere Ray collision
hit(r, tMin, tMax, rec) {
var oc = r.origin().subtract(this.center);
var a = r.dir.lengthSquared();
var halfb = dot(oc, r.dir);
var c = oc.lengthSquared() - this.radius*this.radius;
var discriminant = halfb*halfb - a*c;
if (discriminant < 0) return [false, rec];
var sqrtd = Math.sqrt(discriminant);
// find nearest collision
var root = (-halfb - sqrtd) / a;
if (root < tMin || tMax < root) {
root = (-halfb + sqrtd) / a;
if (root < tMin || tMax < root) return [false, rec];
}
rec.t = root;
rec.p = r.at(rec.t);
var outwardNormal = (rec.p.subtract(this.center)).divide(this.radius);
rec.setFaceNormal(r, outwardNormal);
return [true, rec];
}
Collision for all physical objects
hit(r, tMin, tMax, rec) {
var tempRec = new hitRecord();
var hitAnything = false;
var closestSoFar = tMax;
for (var i in this.list) {
var tempRec = this.list[i].hit(r, tMin, closestSoFar, tempRec)
if (tempRec[0]) {
hitAnything = true;
closestSoFar = tempRec[1].t;
rec = tempRec[1];
}
tempRec = new hitRecord();
}
return [hitAnything, rec];
}
Any help would be appreciated!