I'm working on a hybrid real time ray tracing project and trying to tackle the problem of self-intersection with larger scenes due to loss of float accuracy. The logic I'm trying to use is based on Ray Tracing Gems chapter 6 with the code bellow adapted to work with HLSL. In the snippet, p is the unadjusted ray origin and n the surface normal.
float origin() { return 1.0f / 32.0f; }
float float_scale() { return 1.0f / 65536.0f; }
float int_scale() { return 256.0f; }
// Normal points outward for rays exiting the surface, else is flipped.
float3 offset_ray(const float3 p, const float3 n)
{
int3 of_i = {int_scale() * n.x, int_scale() * n.y, int_scale() * n.z};
float3 p_i = {
asfloat(asint(p.x)+((p.x < 0) ? -of_i.x : of_i.x)),
asfloat(asint(p.y)+((p.y < 0) ? -of_i.y : of_i.y)),
asfloat(asint(p.z)+((p.z < 0) ? -of_i.z : of_i.z))};
return float3(
(abs(p.x) < origin() ? p.x+ float_scale()*n.x : p_i.x),
(abs(p.y) < origin() ? p.y+ float_scale()*n.y : p_i.y),
(abs(p.z) < origin() ? p.z+ float_scale()*n.z : p_i.z));
}
I'm testing this system with Ray Traced Ambient Occlusion and a single model with plenty of detail. Since the model is rather small I'm not encountering any issues at a scale of 1 with the model centered around the origin. The output of the AO GBuffer therefore looks plausible. When changing the scale to 100 there is a huge amount of self-intersection with the floor always self-intersecting and other parts of the model flickering when moving the camera and large parts are often being falsely occluded (output of the GBuffer). When translating the model by 10000 units on each axis and back to a scale of 1 the problem is way less prevalent but still visible. The flickering only happens on parts of the model and underneath the tracks but overall fewer artifacts appear than with the scaling.
I already have taken a look at the shaders used by UE4 but could only find a method to offset depending on the ray angle instead of the translation and is not a system that will solve my issue as the largest offset used in their system is not sufficient in our test scene.
I'm curious why the problem is far more severe with a scale of 100 than with a translation of 10000 and what is causing the issues I'm experiencing. Is it a false translation of the shader code? Miss use of it? Or am I approaching the issue completely the wrong way?
precision highp float. Another idea I just had is offseting by the scaled normal - this way if your models are at a similar scale originally and you rescale, you'll get a rescaled offset too. – lightxbulb Mar 27 '19 at 14:31