<p>The termination condition is that the ray passes through the surface represented in the depth buffer. To track this, you have to calculate the z position of the ray at the current step, and compare it to the value sampled from the depth buffer at the ray's current screen-space position. In terms of your code, this would be something like <code>RaySample.z &gt; ZBufferVal</code> (assuming that your Z is increasing with distance from the camera).</p>
<p>To make it a bit fancier and more accurate, you could also interpolate the position over the last two steps: the second to last step is known to be in front of the depth buffer, and the last step is known to be behind it, so you could calculate the intersection point of the ray approximating the depth as linear between those last two steps.</p>

CC BY-SA 4.0
2021-10-23T18:35:50.577Z
I've tried it but it doesn't work (I've also tried it in the past and it also failed). Using this condition, iterations stops after first step because moving farther from camera increases Z value. My Z buffer (or Hi-Z buffer mip0) is simply Z position in Projection Space obtained by multiplying MVP matrix, so if I understand correctly, my Z Buffer is exactly the same as RaySample.z which causes the problem. I assume that I should use different Z buffer, but I don't know what this buffer should contain.
DirectX_Programmer
CC BY-SA 4.0
2021-10-23T18:43:19.213Z
You probably have to skip the check on the first step. (Try starting `RayStepIdx` at 1 instead of 0.) Once you are stepping along the ray, it is heading away from the surface where it was reflected, so it should not be immediately going behind the depth buffer unless it's in a concavity where the reflected ray would actually be blocked.
Nathan Reed
CC BY-SA 4.0
2021-10-23T18:44:40.150Z
And just to be clear, you're stepping the ray position in 3D - so it steps through Z at a fixed rate, the same as it steps through the UV space. The Z position of the ray is that obtained from the parametric ray equation, and you compare against the Z value obtained from the Hi-Z buffer under the ray's sample point.
Nathan Reed
CC BY-SA 4.0
2021-10-25T08:33:22.620Z
It doesn't work unfortunatelly. If you have a working and simple source code of SSR/RTLR implementation, I would appreciate it. Because it seems that maybe I've made several mistakes in my code that I cannot see.
DirectX_Programmer
CC BY-SA 4.0
2021-10-25T16:38:29.117Z
Sadly, my previous implementations of Hi-Z ray marching were for past jobs where I no longer have source access. But I think there are many implementations of it available on the web. You could also look at the UE4 source code (I'm not sure off the top of my head if it uses Hi-Z or not).
Nathan Reed
CC BY-SA 4.0
2021-10-23T03:38:23.547Z
2021-10-23T03:55:09.610Z
2021-10-23T03:55:09.610Z
Nathan Reed
<p><strong>My main problem is:</strong> When I'm raymarching (should I use View Space or Screen Space/Clip Space?), how do I determine condition to end marching and find which UV's color should be used?</p>
<p>My current code and results:</p>
<pre><code>bool GetReflection(float3 ScreenSpaceReflectionVec, float3 ScreenSpacePos, out float3 ReflectionColor)
{
    for (int RayStepIdx = 0; RayStepIdx &lt; NUM_RAY_MARCH_SAMPLES; RayStepIdx++)
    {
        float3 RaySample = (RayStepIdx * MAX_REFLECTION_RAY_MARCH_STEP) * ScreenSpaceReflectionVec + ScreenSpacePos;
        float ZBufferVal = (hiZBuffer.Sample(pointSampler, RaySample.xy).r); // Current Pos
        float ZBufferOrigin = (hiZBuffer.Sample(pointSampler, ScreenSpacePos.xy).r); // Origin Pos
                
        if (ZBufferOrigin &gt; ZBufferVal)
        {
            ReflectionColor = colorBuffer.SampleLevel(pointSampler, RaySample.xy, 0).rgb;
            return true;
        }
    }

    return false;
}

// Camera ray in CS
inline void GenerateCameraRay(uint2 index, uint2 dimensions, float4x4 projectionToWorld, inout float3 origin, out float3 direction)
{
    // Doesn't really matter, works correctly
}

float4 SSR(PixelInputType input) : SV_TARGET
{
    float3 normalVS = normalBuffer.Sample(pointSampler, input.uv).xyz;
    if (!any(normalVS))
    {
        return float4(colorBuffer.SampleLevel(pointSampler, input.uv, 0).rgb, 1.0f);
    }
    normalVS = mul(float4(normalVS, 0.0f), g_matricesCB.viewMatrix).xyz;
    
    float depthCS = hiZBuffer.Sample(pointSampler, input.uv).r;
    
    // Calculate primary ray origin and direction
    float3 primaryRayOrigin = g_constantBuffer.cameraPosition.xyz;
    float3 primaryRayDirection;
    GenerateCameraRay(input.uv * float2(1024.0f, 512.0f), float2(1024.0f, 512.0f), g_matricesCB.invViewProjMatrix, primaryRayOrigin, primaryRayDirection);      
    
    float3 ReflectionColor = float3(0, 0, 0);
    if (GetReflection(primaryRayDirection, float3(input.uv, depthCS), ReflectionColor))
    {
        return float4(ReflectionColor + colorBuffer.SampleLevel(pointSampler, input.uv, 0).rgb, 1.0f);
    // * float4(1, 0, 0, 1); // DEBUG multiply
    }
    
    return float4(colorBuffer.SampleLevel(pointSampler, input.uv, 0).rgb, 1.0f); // Just return scene color
}
</code></pre>
<p>White is 3D plane model and red is reflection of that model reflected on black plane:
<a href="https://i.sstatic.net/LywJr.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/LywJr.png" alt="enter image description here" /></a>
<a href="https://i.sstatic.net/bUXyR.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/bUXyR.png" alt="enter image description here" /></a></p>
<p>But using presented code above with textures, it looks like this (because iteration always stops on first Suzanne's pixel due to current depth condition):
<a href="https://i.sstatic.net/UfFzu.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/UfFzu.png" alt="enter image description here" /></a></p>
<p>My question is - <strong>how can I correctly obtain UV in reflection plane and what should be terminating condition of raymarching?</strong></p>

<raymarching><post-processing>
SSR/RTLR - hitting object/ending condition
DirectX_Programmer
# SSR/RTLR - hitting object/ending condition

(Asked by: username_0 on 2021-10-22)

**My main problem is:** When I'm raymarching (should I use View Space or Screen Space/Clip Space?), how do I determine condition to end marching and find which UV's color should be used?

My current code and results:

```
bool GetReflection(float3 ScreenSpaceReflectionVec, float3 ScreenSpacePos, out float3 ReflectionColor)
{
    for (int RayStepIdx = 0; RayStepIdx < NUM_RAY_MARCH_SAMPLES; RayStepIdx++)
    {
        float3 RaySample = (RayStepIdx * MAX_REFLECTION_RAY_MARCH_STEP) * ScreenSpaceReflectionVec + ScreenSpacePos;
        float ZBufferVal = (hiZBuffer.Sample(pointSampler, RaySample.xy).r); // Current Pos
        float ZBufferOrigin = (hiZBuffer.Sample(pointSampler, ScreenSpacePos.xy).r); // Origin Pos
                
        if (ZBufferOrigin > ZBufferVal)
        {
            ReflectionColor = colorBuffer.SampleLevel(pointSampler, RaySample.xy, 0).rgb;
            return true;
        }
    }

    return false;
}

// Camera ray in CS
inline void GenerateCameraRay(uint2 index, uint2 dimensions, float4x4 projectionToWorld, inout float3 origin, out float3 direction)
{
    // Doesn't really matter, works correctly
}

float4 SSR(PixelInputType input) : SV_TARGET
{
    float3 normalVS = normalBuffer.Sample(pointSampler, input.uv).xyz;
    if (!any(normalVS))
    {
        return float4(colorBuffer.SampleLevel(pointSampler, input.uv, 0).rgb, 1.0f);
    }
    normalVS = mul(float4(normalVS, 0.0f), g_matricesCB.viewMatrix).xyz;
    
    float depthCS = hiZBuffer.Sample(pointSampler, input.uv).r;
    
    // Calculate primary ray origin and direction
    float3 primaryRayOrigin = g_constantBuffer.cameraPosition.xyz;
    float3 primaryRayDirection;
    GenerateCameraRay(input.uv * float2(1024.0f, 512.0f), float2(1024.0f, 512.0f), g_matricesCB.invViewProjMatrix, primaryRayOrigin, primaryRayDirection);      
    
    float3 ReflectionColor = float3(0, 0, 0);
    if (GetReflection(primaryRayDirection, float3(input.uv, depthCS), ReflectionColor))
    {
        return float4(ReflectionColor + colorBuffer.SampleLevel(pointSampler, input.uv, 0).rgb, 1.0f);
    // * float4(1, 0, 0, 1); // DEBUG multiply
    }
    
    return float4(colorBuffer.SampleLevel(pointSampler, input.uv, 0).rgb, 1.0f); // Just return scene color
}

```

White is 3D plane model and red is reflection of that model reflected on black plane:
[![enter image description here](https://i.sstatic.net/LywJr.png)](https://i.sstatic.net/LywJr.png)
[![enter image description here](https://i.sstatic.net/bUXyR.png)](https://i.sstatic.net/bUXyR.png)

But using presented code above with textures, it looks like this (because iteration always stops on first Suzanne's pixel due to current depth condition):
[![enter image description here](https://i.sstatic.net/UfFzu.png)](https://i.sstatic.net/UfFzu.png)

My question is - **how can I correctly obtain UV in reflection plane and what should be terminating condition of raymarching?**

**Tags:** raymarching, post-processing


---

## 1 answers

### Answer by username_1 on 2021-10-23. Score: 1 | Accepted answer

The termination condition is that the ray passes through the surface represented in the depth buffer. To track this, you have to calculate the z position of the ray at the current step, and compare it to the value sampled from the depth buffer at the ray's current screen-space position. In terms of your code, this would be something like `RaySample.z > ZBufferVal` (assuming that your Z is increasing with distance from the camera).

To make it a bit fancier and more accurate, you could also interpolate the position over the last two steps: the second to last step is known to be in front of the depth buffer, and the last step is known to be behind it, so you could calculate the intersection point of the ray approximating the depth as linear between those last two steps.

> **Comments:**
> **username_0**: I've tried it but it doesn't work (I've also tried it in the past and it also failed). Using this condition, iterations stops after first step because moving farther from camera increases Z value. My Z buffer (or Hi-Z buffer mip0) is simply Z position in Projection Space obtained by multiplying MVP matrix, so if I understand correctly, my Z Buffer is exactly the same as RaySample.z which causes the problem. I assume that I should use different Z buffer, but I don't know what this buffer should contain.  
> **username_1**: You probably have to skip the check on the first step. (Try starting `RayStepIdx` at 1 instead of 0.) Once you are stepping along the ray, it is heading away from the surface where it was reflected, so it should not be immediately going behind the depth buffer unless it's in a concavity where the reflected ray would actually be blocked.  
> **username_1**: And just to be clear, you're stepping the ray position in 3D - so it steps through Z at a fixed rate, the same as it steps through the UV space. The Z position of the ray is that obtained from the parametric ray equation, and you compare against the Z value obtained from the Hi-Z buffer under the ray's sample point.  
> **username_0**: It doesn't work unfortunatelly. If you have a working and simple source code of SSR/RTLR implementation, I would appreciate it. Because it seems that maybe I've made several mistakes in my code that I cannot see.  
> **username_1**: Sadly, my previous implementations of Hi-Z ray marching were for past jobs where I no longer have source access. But I think there are many implementations of it available on the web. You could also look at the UE4 source code (I'm not sure off the top of my head if it uses Hi-Z or not).  

---

