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 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.