<p>I've also been working on GTAO denoising, and came across the same equation.The function is weighing the neighbouring samples by their depth-difference from the center sample, and also by their slopes. (The higher their slope, the less influence they have)</p>
<p>The final line inverts the weighting, which is required, because as slope and depth differences increase, you want the weight of the sample to decrease. If the slope or depth differences were between 0 and 1, you'd invert it by subtracting it from 1, however as these numbers are essentially unbounded, they are mapped into an 0 to 1 range by inverting, and then adding a small bias of 1.25, then clamping within 0 to 1 with the saturate function.</p>
<p>The other part of the equation is dividing the weights by &quot;centerZ * 0.011.&quot; Using a uniform weighting does not work nicely for all distances. Samples close to the camera have much smaller depth deltas and their weights will all be very uniform, whereas samples far away from the camera will be weights that change very quickly, causing aliasing. Dividing the weight by the distance ensures that near and far samples will be affected similarly in screen space. This helps the edge-detection/sharpening appear uniform across different view distances.</p>
<p>For problems like this, it can be handy to convert the constants (1.25, 0.011 etc) to variables, and then playing around with them to see how it affects the image.</p>
<p>It can also be helpful to visualize the equation in desmos or similar, here's a quick example I made for this equation: <a href="https://www.desmos.com/calculator/rwsszxin7l" rel="nofollow noreferrer">https://www.desmos.com/calculator/rwsszxin7l</a></p>
<p>I hope this info helps!</p>

CC BY-SA 4.0
2022-08-07T10:59:04.293Z
2022-08-07T10:59:04.293Z
Benjamin Sims
<p>Reading through the source code of the <a href="https://github.com/GameTechDev/XeGTAO" rel="nofollow noreferrer">XeGTAO</a> project I found this function while looking for the denoise filter:</p>
<pre><code>lpfloat4 XeGTAO_CalculateEdges( const lpfloat centerZ, const lpfloat leftZ, const lpfloat rightZ, const lpfloat topZ, const lpfloat bottomZ )
{
    lpfloat4 edgesLRTB = lpfloat4( leftZ, rightZ, topZ, bottomZ ) - (lpfloat)centerZ;

    lpfloat slopeLR = (edgesLRTB.y - edgesLRTB.x) * 0.5;
    lpfloat slopeTB = (edgesLRTB.w - edgesLRTB.z) * 0.5;
    lpfloat4 edgesLRTBSlopeAdjusted = edgesLRTB + lpfloat4( slopeLR, -slopeLR, slopeTB, -slopeTB );
    edgesLRTB = min( abs( edgesLRTB ), abs( edgesLRTBSlopeAdjusted ) );
    return lpfloat4(saturate( ( 1.25 - edgesLRTB / (centerZ * 0.011) ) ));
}
</code></pre>
<p><em>(From XeGTAO.hlsli)</em></p>
<p>Where <code>centerZ</code>, <code>left/right/...Z</code> are view space z values.</p>
<p>As the name suggests the function is used to find edges for the denoising filter.</p>
<p>While I understand the general idea I find it difficult to make sense of the last line, this <em>thing</em> in particular: <code>1.25 - edgesLRTB / (centerZ * 0.011)</code>.</p>
<p>Could you guess where do those constants come from?
Could you suggest any resource about edge/silhouette extraction from depth
(to be used as input for a filter/displayed for non-photorealistic rendering)?</p>

<image-processing><direct3d><ambient-occlusion><denoise><silhouette>
Edge-aware spatial denoising (Ambient Occlusion)
leone ruggiero
# Edge-aware spatial denoising (Ambient Occlusion)

(Asked by: username_0 on 2022-07-10)

Reading through the source code of the [XeGTAO](https://github.com/GameTechDev/XeGTAO) project I found this function while looking for the denoise filter:

```
lpfloat4 XeGTAO_CalculateEdges( const lpfloat centerZ, const lpfloat leftZ, const lpfloat rightZ, const lpfloat topZ, const lpfloat bottomZ )
{
    lpfloat4 edgesLRTB = lpfloat4( leftZ, rightZ, topZ, bottomZ ) - (lpfloat)centerZ;

    lpfloat slopeLR = (edgesLRTB.y - edgesLRTB.x) * 0.5;
    lpfloat slopeTB = (edgesLRTB.w - edgesLRTB.z) * 0.5;
    lpfloat4 edgesLRTBSlopeAdjusted = edgesLRTB + lpfloat4( slopeLR, -slopeLR, slopeTB, -slopeTB );
    edgesLRTB = min( abs( edgesLRTB ), abs( edgesLRTBSlopeAdjusted ) );
    return lpfloat4(saturate( ( 1.25 - edgesLRTB / (centerZ * 0.011) ) ));
}

```

*(From XeGTAO.hlsli)*

Where `centerZ`, `left/right/...Z` are view space z values.

As the name suggests the function is used to find edges for the denoising filter.

While I understand the general idea I find it difficult to make sense of the last line, this *thing* in particular: `1.25 - edgesLRTB / (centerZ * 0.011)`.

Could you guess where do those constants come from?
Could you suggest any resource about edge/silhouette extraction from depth
(to be used as input for a filter/displayed for non-photorealistic rendering)?

**Tags:** image-processing, direct3d, ambient-occlusion, denoise, silhouette


---

## 1 answers

### Answer by username_1 on 2022-08-07. Score: 4 | Accepted answer

I've also been working on GTAO denoising, and came across the same equation.The function is weighing the neighbouring samples by their depth-difference from the center sample, and also by their slopes. (The higher their slope, the less influence they have)

The final line inverts the weighting, which is required, because as slope and depth differences increase, you want the weight of the sample to decrease. If the slope or depth differences were between 0 and 1, you'd invert it by subtracting it from 1, however as these numbers are essentially unbounded, they are mapped into an 0 to 1 range by inverting, and then adding a small bias of 1.25, then clamping within 0 to 1 with the saturate function.

The other part of the equation is dividing the weights by "centerZ \* 0.011." Using a uniform weighting does not work nicely for all distances. Samples close to the camera have much smaller depth deltas and their weights will all be very uniform, whereas samples far away from the camera will be weights that change very quickly, causing aliasing. Dividing the weight by the distance ensures that near and far samples will be affected similarly in screen space. This helps the edge-detection/sharpening appear uniform across different view distances.

For problems like this, it can be handy to convert the constants (1.25, 0.011 etc) to variables, and then playing around with them to see how it affects the image.

It can also be helpful to visualize the equation in desmos or similar, here's a quick example I made for this equation: <https://www.desmos.com/calculator/rwsszxin7l>

I hope this info helps!


---

