So, I found a source online that went over ray tracing for c++ (https://www.scratchapixel.com/code.php?id=3&origin=/lessons/3d-basic-rendering/introduction-to-ray-tracing)
I decided to go into p5.js and attempt to replicate what they have in their source code, but ran into an error when I got to function recursion. To add reflections they used recursion and ran the same function again, but when I attempt the same thing I get all sorts of incorrect outputs… This is my code:
https://editor.p5js.org/20025249/sketches/0LcyoY8yS
function trace(rayorig, raydir, spheres, depth) {
let tnear = INFINITY;
let sphere;
// find intersection of this ray with the spheres in the scene
for (let i = 0; i < spheres.length; i++) {
t0 = INFINITY;
t1 = INFINITY;
if (spheres[i].intersect(rayorig, raydir)) {
if (t0 < 0) t0 = t1;
if (t0 < tnear) {
tnear = t0;
sphere = spheres[i];
}
}
}
// if there's no intersection return black or background color
if (!sphere) return createVector(2, 2, 2);
let surfaceColor = createVector(0); // color of the ray/surfaceof the object intersected by the ray
let phit = createVector(rayorig.x, rayorig.y, rayorig.z).add(createVector(raydir.x, raydir.y, raydir.z).mult(tnear)); // point of intersection
let nhit = createVector(phit.x, phit.y, phit.z).sub(sphere.center); // normal at the intersection point
nhit.normalize(); // normalize normal direction
// If the normal and the view direction are not opposite to each other
// reverse the normal direction. That also means we are inside the sphere so set
// the inside bool to true. Finally reverse the sign of IdotN which we want
// positive.
let bias = 1e-4; // add some bias to the point from which we will be tracing
let inside = false;
if (createVector(raydir.x, raydir.y, raydir.z).dot(nhit) > 0) {
nhit = -nhit;
inside = true;
}
if ((sphere.transparency > 0 || sphere.reflection > 0) && depth < MAX_RAY_DEPTH) {
let facingratio = createVector(-raydir.x, -raydir.y, -raydir.z).dot(nhit);
// change the mix value to tweak the effect
let fresneleffect = mix(pow(1 - facingratio, 3), 1, 0.1);
// compute reflection direction (not need to normalize because all vectors
// are already normalized)
let refldir = createVector(raydir.x, raydir.y, raydir.z).sub(createVector(nhit.x, nhit.y, nhit.z).mult(2).mult(createVector(raydir.x, raydir.y, raydir.z).dot(nhit)));
refldir.normalize();
// Here is the error:
let reflection = trace(createVector(phit.x, phit.y, phit.z).add(createVector(nhit.x, nhit.y, nhit.z).mult(bias)),
refldir,
spheres,
depth+1
);
let refraction = createVector(0);
// // if the sphere is also transparent compute refraction ray (transmission)
// if (sphere.transparency) {
// let ior = 1.1
// let eta = (inside) ? ior : 1 / ior; // are we inside or outside the surface?
// let cosi = createVector(-nhit.x, -nhit.y, -nhit.z).dot(raydir);
// let k = 1 - eta * eta * (1 - cosi * cosi);
// let refrdir = createVector(raydir.x, raydir.y, raydir.z).mult(eta).add(createVector(nhit.x, nhit.y, nhit.z).mult(eta * cosi - sqrt(k)));
// refrdir.normalize();
// refraction = trace(createVector(phit.x, phit.y, phit.z).sub(createVector(nhit.x, nhit.y, nhit.z).mult(bias)),
// refrdir,
// spheres,
// depth + 1
// );
// }
// the result is a mix of reflection and refraction (if the sphere is transparent)
surfaceColor = (
createVector(reflection.x, reflection.y, reflection.z)
.mult(fresneleffect)
.add(
createVector(refraction.x, refraction.y, refraction.z).mult(1 - fresneleffect).mult(sphere.transparency)
)
)
.mult(sphere.surfaceColor);
}
return createVector(surfaceColor.x, surfaceColor.y, surfaceColor.z).add(sphere.emissionColor);
}
The error is that the reflections don’t give me the same output as the c++ script and seems to be wonky. I cannot for the love of me figure out why the recursive function just doesn’t work.
I have attempted to run it without the recursion and it worked perfectly fine but the recursion is where is breaks
The way I found the error was by printing on the original c++ script and printing on the one I was making and it all works up until the recursive reflections. I get the correct first output but then it all goes down hill.
Their outputs:
[-0.224259 3.89783 -19.1297]
[-0.202411 3.88842 -19.0835]
[-0.180822 3.88236 -19.0538]
My outputs:
[-0.224259 3.89783 -19.1297] // correct
[-0.000065 0.001253 -0.005654] // incorrect
[-0.000064 0.00136 -0.00618] // incorrect
Summary: I made a function that works but the recursion breaks it and I cannot figure out why