r/GraphicsProgramming • u/too_much_voltage • 6h ago
Hierarchical screen-space tracing against depth buffers
Enable HLS to view with audio, or disable this notification
Dear r/GraphicsProgramming,
Before I commence: this effect is really reserved for the reflection component of transparent materials with the refraction being screen-space as well. My gloss trace resolution is low in both SDF-BVH and HWRT approaches and the SDF-BVH one produces blocky reflections which is not a good fit here.
So my engine already had a screen-space tracing approach. But it was fetching world positions from the gather resolve pass which was incredibly slow and sampling pressure heavy. It would sample world positions along a screen-space ray until said position would form a unit vector against the origin that was very directionally similar to the reflection vector. It had to do this for hundreds of fragments for the reflections to not cut-off prematurely. Which prompted me to gimp it to 10 iterations and relax the similarity requirement for the recent release, effectively killing the feature.
Having had to spend the last almost 3 years gutting Unreal for work, I was intrigued by how they simply just traced against the depth buffer. Additionally, their hole skipping approach via using coarser depth tiles was saving them tons of needless sampling. So these past couple of days I set out to produce something similar:
https://github.com/toomuchvoltage/HighOmega-public/commit/d304558dacbf495f286301bfc198e3f67b5886fe
The first thing I had to change was my depth mipping approach. I now had to effectively generate both MinZ and MaxZ depth pyramids. Previously only MaxZ would be generated (MinZ for the visibility buffer pass since it used ReverseZ):
The second thing was to effectively trace the 32x32 mip and capture hits within some threshold (0.006 to be specific):
If a hit was found, proceeding to step back and continue tracing the 64x64 mip within a smaller threshold (this really is my highest depth mip resolution before the full depth buffer):
And finally, trace against the actual thing in case there's a hit with the 64x64 mip:
Now the trace loops aren't water-tight. Which brings me to this paper: https://jcgt.org/published/0003/04/04/paper.pdf . It would be interesting to implement a full on DDA approach. It would probably remove the blocky artifacts near the edge of the screen where the probability of disocclusion is high. That said, I find some of the additions in the paper quite prohibitive. Depth peeling is interesting and quite possibly reduces disocclusion by a decent amount but is also very slow.
My approach is probably closer to something like this: https://sugulee.wordpress.com/2021/01/19/screen-space-reflections-implementation-and-optimization-part-2-hi-z-tracing-method/
One of the annoying things in this approach is the fact that I'm using the mip chain from the TwoPass culling pre-pass. Which blanks out under scene changes -- as in samples the skybox only -- for 1 frame. This is due to the tracking buffer being recreated. Fixing this means generating yet another mip chain for the main pass in TwoPass and since it doesn't happen very frequently, I'm going to leave it. Curious to hear feedback. And if you liked the post, consider buying a copy of my game C.L.A.S.H :D. Which runs on the same engine: https://store.steampowered.com/app/4796200/
Cheers,
Baktash.
HMU: https://x.com/toomuchvoltage
3
u/snerp 1h ago
Thanks for linking the papers you reference! Also congrats on releasing your game! I've seen your engine posts for a while now, can't wait to try it out!