Ray-tracing Refraction – Floating Point Error

To implement refraction in ray-tracing rendering, we can simply use the refraction equation:

$\frac { \sin { { \theta }_{ 1 } } }{ \sin { { \theta }_{ 2 } } } =\frac { { n }_{ 2 } }{ { n }_{ 1 } }$

sin(theta1)/sin(theta2) = n2/n1

To compute sin(theta1), simply:

cos(theta1)= v1.dot(N); sin(theta1) = sqrt(1-cos(theta1) * cos(theta1)); 

where v1 is the incomming ray direction, and N is the surface normal.
However, there may be trouble when this implementation runs in computer. In C++, since we can’t avoid floating point error, when v1 is almost perpendicular to the surface, that is, v1 and N almost the same (or they just be the same), cos(theta1) could slightly greater than 1 (something like 1.00001). Then, this result would cause:

1-cos(theta1) * cos(theta1) < 0

And $\sqrt { a }$ would return invalid result if $a<0$. So that $\sin{{\theta}_1}$ becomes a invalid value. Eventually, all the computation mess up. The pixel we want to shade becomes an error pixel.

To avoid this, simply put a check routine like:

cos(theta1) = min(1.0f, v1.dot(N))

Never trust floating point number!!