<p>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 <a href="http://www.realtimerendering.com/raytracinggems/" rel="noreferrer">Ray Tracing Gems</a> chapter 6 with the code bellow adapted to work with HLSL. In the snippet, <code>p</code> is the unadjusted ray origin and <code>n</code> the surface normal.</p>

<pre class="lang-cpp prettyprint-override"><code>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 &lt; 0) ? -of_i.x : of_i.x)),
    asfloat(asint(p.y)+((p.y &lt; 0) ? -of_i.y : of_i.y)),
    asfloat(asint(p.z)+((p.z &lt; 0) ? -of_i.z : of_i.z))};

    return float3(
    (abs(p.x) &lt; origin() ? p.x+ float_scale()*n.x : p_i.x),
    (abs(p.y) &lt; origin() ? p.y+ float_scale()*n.y : p_i.y),
    (abs(p.z) &lt; origin() ? p.z+ float_scale()*n.z : p_i.z));
}
</code></pre>

<p>I'm testing this system with Ray Traced Ambient Occlusion and <a href="https://sketchfab.com/3d-models/kv-2-heavy-tank-1940-ba8b84d78c0a42038cf2eaa4210ef296" rel="noreferrer">a single model</a> 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 <a href="https://i.sstatic.net/4WTrZ.png" rel="noreferrer">output of the AO GBuffer</a> 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 (<a href="https://i.sstatic.net/pGGSN.png" rel="noreferrer">output of the GBuffer</a>). When translating the model by <a href="https://i.sstatic.net/XnGvr.png" rel="noreferrer">10000 units on each axis</a> 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.</p>

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

<p>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?</p>

CC BY-SA 4.0
2019-03-22T15:09:56.550Z
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: https://www.iquilezles.org/www/articles/floatingbar/floatingbar.htm
Do you keep your ray and normal normalized?
lightxbulb
CC BY-SA 4.0
2019-03-25T02:45:07.470Z
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
CC BY-SA 4.0
2019-03-25T02:46:38.453Z
Looking at your tank/gbuffer picture, are you using 2 sided polygons or is front-face culling used ?
PaulHK
CC BY-SA 4.0
2019-03-27T13:53:39.220Z
@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](https://i.sstatic.net/pGGSN.png) 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
CC BY-SA 4.0
2019-03-27T14:02:09.190Z
@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
CC BY-SA 4.0
2019-03-27T14:31:08.250Z
The code you're using is for geometric normals though. Try to use the geometric normals just to check whether there's a difference. By precision of FP (floating point) numbers I mean the precision that the hardware you use supports. For example on some mobile devices no 32bits is supported or it requires an explicit ``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
<raytracing><c++><directx12>
How to account for self intersection with large ray tracing scenes?
Florian Schut
# How to account for self intersection with large ray tracing scenes?

(Asked by: username_0 on 2019-03-22)

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](http://www.realtimerendering.com/raytracinggems/) 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.

```cpp
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](https://sketchfab.com/3d-models/kv-2-heavy-tank-1940-ba8b84d78c0a42038cf2eaa4210ef296) 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](https://i.sstatic.net/4WTrZ.png) 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](https://i.sstatic.net/pGGSN.png)). When translating the model by [10000 units on each axis](https://i.sstatic.net/XnGvr.png) 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?

**Tags:** raytracing, c++, directx12

> **Comments:**
> **username_1**: 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: https://www.iquilezles.org/www/articles/floatingbar/floatingbar.htm Do you keep your ray and normal normalized?  
> **username_2**: 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.  
> **username_2**: Looking at your tank/gbuffer picture, are you using 2 sided polygons or is front-face culling used ?  
> **username_0**: @username_1 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](https://i.sstatic.net/pGGSN.png) 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.  
> **username_0**: @username_2 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.  
> **username_1**: The code you're using is for geometric normals though. Try to use the geometric normals just to check whether there's a difference. By precision of FP (floating point) numbers I mean the precision that the hardware you use supports. For example on some mobile devices no 32bits is supported or it requires an explicit ``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.  

---

## 0 answers

