[Open Source] Screen Space Path Tracing for URP

Hey, I followed Three-Eyed-Games’ ray tracing tutorials and created a screen space path tracing effect in URP 15.

I thought it was unusable because of the noisiness and speed, but surprisingly found that it can be usable in some cases. (Tested on a mobile device with TAA)


It would be nice if it is helpful for your project.

7 Likes

Hey, I just found out the reason that I cannot add reflection probes fallback to the effect. (currently the probe will be black or grey)

That’s because the current full screen pass renderer feature will always use “Draw Procedural” even if the mode is set to “Blit”.
8652462--1164477--DrawProcedural.jpg

I will test it further once the “Blit” mode works, and I think a box projected probe fallback will greatly improve the stability of this screen space effect.
8652462--1164483--FullScreenPass_Blit.jpg

1 Like

The report is confirmed as a duplicate issue of UUM-2631.

I think it won’t be fixed soon, so I tried to manually set reflection probes. (see this thread or this C# script)
8755933--1186552--AddProbeSetter.jpg

If you need to access reflection probes in a URP blit pass, you may try the method mentioned above. Now the effect is much better than before.

Custom Sky Fallback:
8755933--1186543--SkyFallBack.jpg

[Last Edited] Reflection Probe Fallback: (Probe Intensity set to 0.37)
8755933--1188319--ProbeFallBack2.jpg

[Last Edited] Off-Screen Light Plane:
8755933--1190419--EmissionFromReflectionProbe.jpg

The fall back is not perfect because reflection probes don’t capture depth information. But it’s enough to provide some off-screen data.

Reflection Probe Preview Only:
8755933--1186558--ProbePreview.jpg

Hi, I added Forward rendering path support to the repository. (URP forces Forward path on OpenGL platforms)

If you need to render GBuffers (0,1,2) in a Forward path, you can try this renderer feature.

For OpenGL platforms, some extra steps are needed.

amazing project!

1 Like

Hi, I’ve done many improvements to it since the last post. They can be find in the commits page.

The biggest improvement is the real-time accumulation (temporal re-projection).

Most of the artifacts (weird shadows) are fixed by considering back-face in ray marching. These back-faces reuse the front GBuffer to reduce performance cost.
Before:


After:

The back-face now appears in reflection when “Accurate Thickness” (render back-face depth) is enabled. This may not be 100% correct but looks much better than before (with hole).

The next steps might be:

  • Move this post-processing effect into object’s shader to allow more accurate reflection probe fallback.
  • Further reduce ghosting in real-time accumulation.
  • Move this post-processing effect into object’s shader to see if it’s possible to support other lighting models (refraction, …).
2 Likes

nice, very interesting

1 Like

Hey, I’m still looking for a way that is efficient enough (less draw call & overdraw) to implement per object reflection probe fallback.

So I added refraction support to it first. To render refractions, objects need to use “Universal Render Pipeline/Screen Space Path Tracing/Refraction Lit” shader graph, which is provided by the repository, and tick “Support Refraction” in the accumulation renderer feature.

The idea is similar to layered rendering.

Details:

  1. Render transparent objects to three transparent GBuffers (0, 1, 2) and write depth to “_CameraDepthAttachment” (camera’s depth target).
  2. Render both opaque & transparent objects’ back-face depth to “_CameraBackDepthTexture”.
  3. [Optional] Render back-face normals (DepthNormals) rather than rendering back-face depth (DepthOnly).

Now we have these for calculating refractions:

  • “_CameraDepthAttachment”: Opaque & Transparent Depth Layer 1
  • “_CameraBackDepthTexture”: Opaque & Transparent Depth Layer 2
  • “_CameraDepthTexture”: Opaque Depth Layer

This allows calculating the actual thickness of refracting objects, and find intersections for opaque objects that are covered by them.

The “_TransparentGBuffer1” (specular.rgb occlusion.a) is used to store index of refraction (ior.r) and surface type (surfaceType.a). The “occlusion.a” for other transparent objects will be 1.0.

As this effect is based on rasterization, it doesn’t support recursive refraction, which means that other refractions cannot be seen in refractions.

For Unity lights, (shadows) transparency uses dithered transparent shadows.
8958555--1230522--Raster_Shadows.jpg

Only path traced shadows (from indirect lighting, emission, …) can have things like refraction caustics.

It’s not perfect yet and I think it can be improved later. (URP transparent motion vectors, …)

1 Like

I saw a simple but effective open source spatial denoiser on shadertoy, and it works well after porting to URP. It uses different surface data to avoid blurring the edges and colors.

Now it’s possible to use recorder to export videos without setting extremely high SPPs.

Temporal Denoise Only (TAA + Real-time Accumulation): z15pf7

Temporal Spatial Denoise: rjm3a0

TAA causes severe ghosting, maybe need to find a way to replace it.

2 Likes

The reflection probe atlas in Forward+ makes accessing all reflection probes in a full screen shader possible. I’ve tried it and the results were satisfying.

Forward and Deferred:
9076246--1256107--Forward_or_Deferred.jpg

Forward+:
9076246--1256110--Forward+.jpg

I haven’t pulled it to the repo yet because I think it needs more tests and I’m considering downgrading the repo’s editor version to 2022 LTS (from 2023.1b).

1 Like

I didn’t forget about this repo and it’s actually actively developed (when I have time).

For example, recently I came up with a better way to handle both large and small objects in the same scene.

Let’s divide the total steps (ex. 24) of ray marching into 3 parts (small = 4, medium = 8, large = 12) and marching the ray according to steps order.

The size of small steps can be set very small (ex. 2 mm) to ensure that ray marching does not miss extremely small objects.

Medium step size can be set to a larger unit (ex. 2 cm) so that objects can produce reflections & shadows.

The large steps are used to “fill” the scene and allow rays to travel further. It’s set to “0.6 m” in the screenshot below.

Before and After (small objects):
9636278--1369610--before.jpg 9636278--1369613--after.jpg

This repo is also the foundation of adding a good enough SSGI for URP to me. I wasn’t very satisfied with my SSR (based on an early version of this SSPT), so I decided to spend more time improving this (ex. the most important denoise) first before starting to add SSGI.

2 Likes

looks amazing but for some reason the gray book looks off…

1 Like

Thanks for pointing it out! Do you mean the blue gray book in the first screenshot?

I increased the total steps (low: 24 → medium: 48) to test if it’s relevant, and found that it’s because of the lack of information in screen space (being occluded).
9636863--1369724--SmallObjects2.jpg

It could be improved if there was a way to render more layers of depth, but I doubt it’s worth it in terms of performance. Another solution might be to use inline ray tracing, but obviously it’s not the time yet. (Vulkan inline ray tracing in URP)

1 Like

Hey, I just updated the repo and would like to briefly introduce the changes. (with screenshots)

Added

Unified Renderer Features: Combined all renderer features (and shaders) into a single one, making the effect easier to use.

Add SSPT to URP Volume: Allows controlling SSPT settings in the scene’s URP Volume.
9830298--1413753--ScreenSpacePathTracingVolume.jpg

Render Graph Support: Added support for Render Graph. (Requires Unity 6000.0.0f1 or newer)
9830298--1413759--RenderGraph.jpg

Ray Marching Quality: Improved the quality of ray marching by dividing ray marching steps into small, medium, and large steps. (see “PathTracingConfig.hlsl”)

Denoising Redesign: Redesigned the real-time denoising for cleaner and less ghosting results.

Refraction: Improved path tracing refraction calculations. (ex. more stable caustics from reflection probes)
9830298--1413756--RefractionTest.gif

Fixed

Refraction: Fixed the incorrect Color Blend options in the Transparent GBuffer Pass.

Known Issues

When the active platform in the editor is set to Android, object’s compiling shaders may output incorrect extreme color values (e.g., green) to reflection probes (for one frame) which will be spread to the entire screen by SSPT. This does not appear in build.

After SSPT automatically sets the scene’s ambient lighting to zero, it will not restore the original ambient lighting settings (Lighting Panel → Environment → Environment Lighting).

I also found that TAA is applied after this effect in Unity 6 (preview) which is much better than before.

Note:
Make sure you removed “ScreenSpathPathTracingForwardGBuffer” and “FullScreenPass” renderer features before upgrading.

In the player settings, the “HDR Cubemap Encoding” should be an HDR-supported setting, such as “High Quality”.

1 Like

Hey, no updates, but I’m working on adding SSGI to URP. Hopefully I can release it before the forum moves.

WIP screenshot

SSGI:
9919065--1434282--SSGI_WIP.gif

SSPT converged:
9919065--1434303--SSPT_Reference.jpg

Even though from the screenshot it looks ready for release, there is still a lot of work to be done.

Edited:

I mistakenly changed the (SSPT) ray steps to 48, so they looked a bit different.

SSGI (48 ray steps):
9919065--1434324--SSGI_WIP2.jpg

2 Likes

Hi, maybe I should create a new SSGI thread and post there…

Yesterday I made a simple testing scene (Relaxing Corner, will be included in the repo) and was surprised by the results.

URP rendering with (full resolution) SSGI set to High:

Disable SSGI:

Performance?

Obviously “High” (4 rays + 64 steps) is a performance killer for most URP target devices (ex. mobiles), so I also tested “Custom” (1 ray + 32 steps + half resolution):

There’re still lots of things I need to check before release:

  • Usability check (rename some settings)
  • UPM package support (install & importing sample scene via package manager)
  • Non Forward+ fallback workflow improvements (currently requires attaching a C# script to the main camera, which I don’t like)
  • Build tests (multi-graphics APIs)

Hopefully these won’t take too long, if so then see you in Unity Discussions!

3 Likes

very good… but why the walls andd the window are blue on the first screenshot?

1 Like

Hi, sorry for the late reply, do you mean the slightly bluish tint in the corners?
9929121--1436505--SSGI.jpg

Thanks for pointing it out!:wink: I thought there was a bug somewhere, but later found out that it’s from the HDRI skybox. (specifically, sky background in reflection probes)

The room has an “open” ceiling to let in more sunlight. (weird design, isn’t it?)
9929121--1436583--ProbeWithSky.jpg

Fully black sky, no bluish tint:
9929121--1436586--ProbeIgnoreSky.jpg

If you find anything strange, please feel free to point it out!

Additionally,

it’s possible to have more accurate lighting, but it may further impact performance.

Backface Lighting: render the back-face lighting of all opaque objects at screen resolution.

looks good! Is this direct translation of HDRP SSGI or something else?