Thu Aug 22 2013

##FSharp Raytracer Part 4 - Specular Reflection and Mirrors

This episode, we're going to add reflection into our system! Luckily, reflections are extremely easy to add to a standard raytracer. Lets take a look at our previous raytrace function:

let raytrace ray =
    match closestIntersection (scene |> Seq.cast) ray with
    | None -> Vector3.Zero
    | Some(i) -> lambert i lights

We first need to add a depth-counter to the Ray type so we know when to stop reflecting. Otherwise, we'd keep bouncing around for too long in a scene with a lot of reflections. We'll initialize it so something like N=3 when we start the ray-cast. Then we'll have to calculate the reflected ray for each intersection. Luckily, we already have our incoming ray and normal vector, so it is a matter of simple vector math to arrive at the formula for the reflected ray:

let incident = Vector3.Normalize(-ray.Dir)
let reflected = 2.f * item.normal * (dot incident i.normal) - incident

We then recursively call raytrace again with the new ray, taking the current lambert term and adding 30% of the reflected light to our current point.

let rec raytrace ray =
    if ray.N < 0 then Vector3.Zero
    else match closestIntersection (scene |> Seq.cast) ray with
    | None -> Vector3.Zero
    | Some(i) -> 
        let incident = Vector3.Normalize(-ray.Dir)
        let reflected = 2.f * i.normal * (dot incident i.normal) - incident
        lambert i lights + 0.3f * raytrace { Pos = i.point; Dir = reflected; N = ray.N - 1 }