Unreal SSR intersections detection

Screen Space Glossy Reflections Screen Space Glossy Reflections

This article does not consider roughness or multiple reflection rays, but uses the way the Unreal engine computs intersection points when dealing with a single ray ray step to improve the reflection performance of my plugin LWRP/URP SSR Water.

Take a look at the following snippet of the simplest ray-stepping code:

#if SCALAR_BRANCHLESS    

    float MinHitTime = 1;
    float LastDiff = 0;

    float SampleTime = StepOffset * Step + Step; 

    UNROLL
    for( int i = 0; i < NumSteps; i++ )
    {
        float3 SampleUVz = RayStartUVz + RayStepUVz * SampleTime;
        
        // Use lower res for farther samples
        float Level = Roughness * (i * 4.0 / NumSteps) + HZB_LEVEL_OFFSET;
        float SampleDepth = Texture.SampleLevel( Sampler, SampleUVz.xy, Level ).r;

        float DepthDiff = SampleUVz.z - SampleDepth;
        bool Hit = abs( DepthDiff + CompareTolerance ) < CompareTolerance;

        // Find more accurate hit using line segment intersection 
        float TimeLerp = saturate( LastDiff / (LastDiff - DepthDiff) ); 
        float IntersectTime = SampleTime + TimeLerp * Step - Step; 
        float HitTime = Hit ? IntersectTime : 1;
        MinHitTime = min( MinHitTime, HitTime );

        LastDiff = DepthDiff;     

        SampleTime += Step;       
    }

    float3 HitUVz = RayStartUVz + RayStepUVz * MinHitTime;

    Result = float4( HitUVz, MinHitTime );
Copy the code

Here’s an interesting note:

Find more accurate hit using line segment intersection

After determining that the ray intersects the scene, Unreal does not rush to return the screen coordinates corresponding to the end of the current ray, but instead interpolates a more accurate screen coordinates based on the offset of the end of the previous ray and the end of the current ray relative to the depth of the scene.

It’s a little tricky, but I’ll draw a picture to make it clear:

The graph above shows the situation when the ray depth just exceeds the scene depth. CurrentDiff is positive and LastDiff is negative. If the positive and negative signs are taken into account, the screen coordinates of the intersection are calculated as follows:

HitScreenUV = lerp(LastScreenUV, CurrentScreenUV, -LastDiff / (CurrentDiff - LastDiff)))
Copy the code

In the code above, LastScreenUV is the screen coordinates corresponding to the end of the previous ray, and CurrentScreenUV is the screen coordinates corresponding to the end of the current ray.

Multiply the numerator and denominator of -lastdiff/(currentDiff-lastdiff) by -1,

HitScreenUV = lerp(LastScreenUV, CurrentScreenUV, LastDiff / (LastDiff - CurrentDiff)))
Copy the code

This corresponds to the Unreal code.

Effect of contrast

In the calculation of ray step intersection point of LWRP/URP SSR Water, I did not use the above interpolation operation, but directly returned the screen coordinates corresponding to the end point of the current ray after judging the intersection.

With jitter, this approach is also good when sampling steps and screen resolution are relatively high.

However, when I set the resolution to 1200 x 600, the previous performance was just so-so, as shown below:

After interpolating, the resolution is still 1200 x 600, and the performance is much better:

It’s even better to scale up to 2160 x 1080, a common mobile resolution:

As a shader of water, this is about right, because when you add water ripples, everything is floating clouds:

Personal home page

Links to personal home page of this article: baddogzz. Making. IO / 2020/03/06 /… .

Okay, bye!