# How to account for self intersection with large ray tracing scenes?

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?

• Scaling is multiplicative, translation is additive. Also are you translating along the geometric or shading normal? You could also check the precision of the fp numbers you use and the precision of the operations. Finally, fixed point, or even rational numbers are a thing: iquilezles.org/www/articles/floatingbar/floatingbar.htm Do you keep your ray and normal normalized? – lightxbulb Mar 22 at 15:09
• How about raytracing in model space coordinates ? There will still be some inprecision when converting the ray from world->model but the triangle intersections will be done in a higher precision coordinate space. – PaulHK Mar 25 at 2:45
• Looking at your tank/gbuffer picture, are you using 2 sided polygons or is front-face culling used ? – PaulHK Mar 25 at 2:46
• @lightxbulb The scaling vs translations makes sense! We are using the shading normals, we don't have geometric ones handly available so this prototype used the shading normals, though I doubt that would have caused all of the issues because for example in the scaling output the top planes of the tank are intersecting even though the normal map has barely any detail in that area. What do you mean with the precision of the FP, how do I check the specific cases. And we should be using normalized normals indeed. – Florian Schut Mar 27 at 13:53
• @PaulHK Thanks for the suggestion but I doubt moving the intersections to model space will work, the reason is two-fold. Firstly the raytracing is largely abstracted by DXR which uses pre-calculated acceleration structures containing all geometry in world space we can't simply take matters in our own hands and do the AO in model space due to this. Secondly, it sounds like moving to model space will rule out occlusion between models in which case we would be better off using pre-calculated AO maps and use the benefit of raytracing. We are using backface culling but struggle to see the relation. – Florian Schut Mar 27 at 14:02