Reader small image

You're reading from  Mastering Graphics Programming with Vulkan

Product typeBook
Published inFeb 2023
PublisherPackt
ISBN-139781803244792
Edition1st Edition
Right arrow
Authors (2):
Marco Castorina
Marco Castorina
author image
Marco Castorina

Marco Castorina first got familiar with Vulkan while working as a driver developer at Samsung. Later he developed a 2D and 3D renderer in Vulkan from scratch for a leading media-server company. He recently joined the games graphics performance team at AMD. In his spare time, he keeps up to date with the latest techniques in real-time graphics.
Read more about Marco Castorina

Gabriel Sassone
Gabriel Sassone
author image
Gabriel Sassone

Gabriel Sassone is a rendering enthusiast currently working as a Principal Rendering Engineer at Multiplayer Group. Previously working for Avalanche Studios, where his first contact with Vulkan happened, where they developed the Vulkan layer for the proprietary Apex Engine and its Google Stadia Port. He previously worked at ReadyAtDawn, Codemasters, FrameStudios, and some non-gaming tech companies. His spare time is filled with music and rendering, gaming, and outdoor activities.
Read more about Gabriel Sassone

View More author details
Right arrow

Adding Reflections with Ray Tracing

In this chapter, we are going to implement reflections using ray tracing. Before ray tracing hardware was introduced, applications implemented reflections using screen-space techniques. However, this technique has drawbacks as it can only use information from what’s visible on the screen. If one of the rays goes outside the visible geometry on the screen, we usually fall back to an environment map. Because of this limitation, the rendered reflections can be inconsistent, depending on the camera position.

By introducing ray tracing hardware, we can overcome this limitation as we now have access to geometry that is not visible on the screen. The downside is that we might need to perform some expensive lighting computations. If the reflected geometry is outside the screen, this means we don’t have the data from the G-buffer and we need to compute the color, light, and shadow data from scratch.

To lower the cost of this technique...

Technical requirements

By the end of the chapter, you will have a good understanding of the different solutions available for reflections. You will also learn how to implement ray-traced reflections and how to improve the final result with the help of a denoiser.

The code for this chapter can be found at the following URL: https://github.com/PacktPublishing/Mastering-Graphics-Programming-with-Vulkan/tree/main/source/chapter15.

How screen-space reflections work

Reflections are an important rendering element that can provide a better sense of immersion in the scene. For this reason, developers have developed a few techniques over the years to include this effect, even before ray tracing hardware was available.

One of the most common approaches is to ray-march the scene after the G-buffer data becomes available. Whether a surface will produce reflections is determined by the material’s roughness. Only materials with a low roughness will emit a reflection. This also helps reduce the cost of this technique since usually, only a low number of surfaces will satisfy this requirement.

Ray marching is a technique similar to ray tracing and was introduced in Chapter 10, Adding Volumetric Fog. As a quick reminder, ray marching works similarly to ray tracing. Instead of traversing the scene to determine whether the ray hit any geometry, we move in the ray’s direction by small increments for a fixed...

Implementing ray-traced reflections

In this section, we are going to leverage the hardware ray tracing capabilities to implement reflections. Before diving into the code, here’s an overview of the algorithm:

  1. We start with the G-buffer data. We check whether the roughness for a given fragment is below a certain threshold. If it is, we move to the next step. Otherwise, we don’t process this fragment any further.
  2. To make this technique viable in real time, we cast only one reflection ray per fragment. We will demonstrate two ways to pick the reflection’s ray direction: one that simulates a mirror-like surface and another that samples the GGX distribution for a given fragment.
  3. If the reflection ray hits some geometry, we need to compute its surface color. We shoot another ray toward a light that has been selected through importance sampling. If the selected light is visible, we compute the color for the surface using our standard lighting model.
  4. ...

Implementing a denoiser

To make the output of our reflection pass usable for lighting computations, we need to pass it through a denoiser. We have implemented an algorithm called SVGF, which has been developed to reconstruct color data for path tracing.

SVGF consists of three main passes:

  1. First, we compute the integrated color and moments for luminance. This is the temporal step of the algorithm. We combine the data from the previous frame with the result of the current frame.
  2. Next, we compute an estimate for variance. This is done using the first and second moment values we computed in the first step.
  3. Finally, we perform five passes of a wavelet filter. This is the spatial step of the algorithm. At each iteration, we apply a 5x5 filter to reduce the remaining noise as much as possible.

Now that you have an idea of the main algorithm, we can proceed with the code details. We start by computing the moments for the current frame:

float u_1 = luminance( reflections_color...

Summary

In this chapter, we described how to implement ray-traced reflections. We started with an overview of screen-space reflection, a technique that was used for many years before ray tracing hardware was available. We explained how it works and some of its limitations.

Next, we described our ray tracing implementation to determine reflection values. We provided two methods to determine the reflected ray direction and explained how the reflected color is computed if a hit is returned.

Since we only use one sample per fragment, the result of this step is noisy. To reduce as much of this noise as possible, we implemented a denoiser based on SVGF. This technique consists of three passes. First, there’s a temporal accumulation step to compute color and luminance moments. Then, we compute the luminance variance. Finally, we process the color output by passing it through five iterations of a wavelet filter.

This chapter also concludes our book! We hope you enjoyed reading...

Further reading

We have only provided a brief introduction to screen-space reflections. The following articles go into more detail about their implementation, their limitations, and how to improve the final results:

We have only used one of the many hashing techniques presented in the paper Hash Functions for GPU Rendering: https://jcgt.org/published/0009/03/02/.

This link contains more details about the sampling technique we used to determine the reflection vector by sampling the BRDF – Sampling the GGX Distribution of Visible Normals: https://jcgt.org/published/0007/04/01/.

For more details about the SVGF algorithm we presented, we recommend reading the original paper and supporting material...

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Mastering Graphics Programming with Vulkan
Published in: Feb 2023Publisher: PacktISBN-13: 9781803244792
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Authors (2)

author image
Marco Castorina

Marco Castorina first got familiar with Vulkan while working as a driver developer at Samsung. Later he developed a 2D and 3D renderer in Vulkan from scratch for a leading media-server company. He recently joined the games graphics performance team at AMD. In his spare time, he keeps up to date with the latest techniques in real-time graphics.
Read more about Marco Castorina

author image
Gabriel Sassone

Gabriel Sassone is a rendering enthusiast currently working as a Principal Rendering Engineer at Multiplayer Group. Previously working for Avalanche Studios, where his first contact with Vulkan happened, where they developed the Vulkan layer for the proprietary Apex Engine and its Google Stadia Port. He previously worked at ReadyAtDawn, Codemasters, FrameStudios, and some non-gaming tech companies. His spare time is filled with music and rendering, gaming, and outdoor activities.
Read more about Gabriel Sassone