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.