Posted by Søren Greiner Wed, February 24, 2010 13:26:46
The quick fix is to move the hit-point a small amount along the normal vector (in the incident direction) of the surface. This is what I usually do:
vOffsetHit = vHit + vNormal*0.00001
But why 0.00001? Originally I chose this number because it was larger than typical errors. This fixed some of the artifacts in my images where small holes appeared in my geometry.
However this number only works if the scene geometry has a magnitude around 1 or so. What if the scene geometry is very large? Perhaps the mirror is placed at coordinate 100000,100000,100000. In this case an offset of 0.00001 is too small. Due to limited precision in floating point numbers (~7 significant decimal digits) 100000+0.00001 gives the number 100000, where 100000.00001 was expected.
The solution is to compute a scaled epsilon value that guarantees that x + epsilon > x. I wrote a function called Epsilon that does exactly this. This is how it is defined:
// Difference between 1.0f and the minimum float greater than 1.0f
#define FLOAT_EPSILON 1.19209289550781e-007
float Epsilon(float x, float scale)
float f = FLOAT_EPSILON*scale;
x is the number to compute epsilon from. scale is used to scale epsilon and must be > 1.
This is how it can be used:
vHit.x = some number
vOffsetHit.x = vHit.x + Epsilon(vHit.x, 10)
Now we have a guarantee that vOffsetHit.x is larger than vHit.x with an amount at least 10 times larger than the smallest epsilon.
I have implemented a small unit test program that tests this function and it seems to be working well: