Raytracing side note: “almost zero”

As we will use float-values to do our computations we might run into situations where we get into precision-troubles. It’s because of this problems that we have to consider values the same if they differ by a small amount instead of exactly zero.

To get this out of our way let’s just write a couple of functions and active-patterns to help us in the future. I think it’s almost trivial so I don’t think I have to go over each line and explain – so without further due here is the helper code:

[< AutoOpen >]
module FloatHelpers =

    let ZeroThreshold = 0.0000000001

    let IsNearZero (f : float) =
        abs f <= ZeroThreshold

    let IsPositive (f : float) =
        f > ZeroThreshold

    let IsNegative (f : float) =
        f < -ZeroThreshold

    let (|NotNearZero|_|) (f : float) =
        if IsNearZero f
        then None
        else Some f

    let (|Negative|NearZero|Positive|) (f : float) =
        if f |> IsNegative then Negative
        elif f |> IsPositive then Positive
        else NearZero

You can find a good article on active patterns by Jessica Kerr right here: Pattern Matching in F# Part2.

To give a first simple use of this (and give some hint of why I included the somewhat strange NotNearZero (never make a negative predicate right … well no not “never”):

    let Normalize (v : Vector3) =
        match Length v with
        | NotNearZero l -> (1.0/l)*v
        | _             -> Zero

This is a function to normalize a vector – that is finding a vector with the same direction but length 1 so that  normalize( v ) = \frac{v}{\left| v \right|} if the vector is not zero.

We will need this often because many calculations are easier (and need fewer operations) if one (or any) of the participating vectors is a normal-vector.

This is why I will model a ray’s direction to always be a normal vector.