Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Mastering Graphics Programming with Vulkan

You're reading from  Mastering Graphics Programming with Vulkan

Product type Book
Published in Feb 2023
Publisher Packt
ISBN-13 9781803244792
Pages 382 pages
Edition 1st Edition
Languages
Authors (2):
Marco Castorina Marco Castorina
Profile icon Marco Castorina
Gabriel Sassone Gabriel Sassone
Profile icon Gabriel Sassone
View More author details

Table of Contents (21) Chapters

Preface 1. Part 1: Foundations of a Modern Rendering Engine
2. Chapter 1: Introducing the Raptor Engine and Hydra 3. Chapter 2: Improving Resources Management 4. Chapter 3: Unlocking Multi-Threading 5. Chapter 4: Implementing a Frame Graph 6. Chapter 5: Unlocking Async Compute 7. Part 2: GPU-Driven Rendering
8. Chapter 6: GPU-Driven Rendering 9. Chapter 7: Rendering Many Lights with Clustered Deferred Rendering 10. Chapter 8: Adding Shadows Using Mesh Shaders 11. Chapter 9: Implementing Variable Rate Shading 12. Chapter 10: Adding Volumetric Fog 13. Part 3: Advanced Rendering Techniques
14. Chapter 11: Temporal Anti-Aliasing 15. Chapter 12: Getting Started with Ray Tracing 16. Chapter 13: Revisiting Shadows with Ray Tracing 17. Chapter 14: Adding Dynamic Diffuse Global Illumination with Ray Tracing 18. Chapter 15: Adding Reflections with Ray Tracing 19. Index 20. Other Books You May Enjoy

Rendering Many Lights with Clustered Deferred Rendering

Until now, our scene has been lit by a single point light. While this has worked fine so far as we focused our attention more on laying the foundations of our rendering engine, it’s not a very compelling and realistic use case. Modern games can have hundreds of lights in a given scene, and it’s important that the lighting stage is performed efficiently and within the budget of a frame.

In this chapter, we will first describe the most common techniques that are used both in deferred and forward shading. We will highlight the pros and cons of each technique so that you can determine which one best fits your needs.

Next, we are going to provide an overview of our G-buffer setup. While the G-buffer has been in place from the very beginning, we haven’t covered its implementation in detail. This is a good time to go into more detail, as the choice of a deferred renderer will inform our strategy for clustered...

Technical requirements

By the end of the chapter you will have a solid understanding of our G-buffer implementation. You will also learn how to implement a state of the art light clustering solution that can handle hundreds of lights.

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

A brief history of clustered lighting

In this section, we are going to explore the background of how clustered lighting came to be and how it has evolved over the years.

In real-time applications, until the early 2000s, the most common way to handle lighting was by using the so-called forward rendering, a technique that renders each object on the screen with all the information needed, including light information. The problem with this approach is that it would limit the number of lights that could be processed to a low number, such as 4 or 8, a number that in the early 2000s would be enough.

The concept of Deferred Rendering, and more specifically, shading the same pixel only once, was already pioneered by Michael Deering and colleagues in a seminal paper called The triangle processor and normal vector shader: a VLSI system for high performance graphics in 1988, even though the term deferred was still not used.

Another key concept, the G-buffer, or geometric buffer, was pioneered...

Implementing a G-buffer

From the beginning of this project, we decided we would implement a deferred renderer. It’s one of the more common approaches, and some of the render targets will be needed in later chapters for other techniques:

  1. The first step in setting up multiple render targets in Vulkan is to create the framebuffers – the textures that will store the G-buffer data – and the render pass.

This step is automated, thanks to the frame graph (see Chapter 4, Implementing a Frame Graph, for details); however, we want to highlight our use of a new Vulkan extension that simplifies render pass and framebuffer creation. The extension is VK_KHR_dynamic_rendering.

Note

This extension has become part of the core specification in Vulkan 1.3, so it’s possible to omit the KHR suffix on the data structures and API calls.

  1. With this extension, we don’t have to worry about creating the render pass and framebuffers ahead of time...

Implementing light clusters

In this section, we are going to describe our implementation of the light clustering algorithm. It’s based on this presentation: https://www.activision.com/cdn/research/2017_Sig_Improved_Culling_final.pdf. The main (and very smart) idea is to separate the XY plane from the Z range, combining the advantages of both tiling and clustering approaches. The algorithms are organized as follows:

  1. We sort the lights by their depth value in camera space.
  2. We then divide the depth range into bins of equal size, although a logarithmic subdivision might work better depending on your depth range.
  3. Next, we assign the lights to each bin if their bounding box falls within the bin range. We only store the minimum and maximum light index for a given bin, so we only need 16 bits for each bin, unless you need more than 65,535 lights!
  4. We then divide the screen into tiles (8x8 pixels, in our case) and determine which lights cover a given tile. Each tile...

Summary

In this chapter, we have implemented a light clustering solution. We started by explaining forward and Deferred Rendering techniques and their main advantages and shortcomings. Next, we described two approaches to group lights to reduce the computation needed to shade a single fragment.

We then outlined our G-buffer implementation by listing the render targets that we use. We detailed our use of the VK_KHR_dynamic_rendering extension, which allows us to simplify the render pass and framebuffer use. We also highlighted the relevant code in the G-buffer shader to write to multiple render targets, and we provided the implementation for our normal encoding and decoding. In closing, we suggested some optimizations to further reduce the memory used by our G-buffer implementation.

In the last section, we described the algorithm we selected to implement light clustering. We started by sorting the lights by their depth value into depth bins. We then proceeded to store the lights...

Further reading

lock icon The rest of the chapter is locked
You have been reading a chapter from
Mastering Graphics Programming with Vulkan
Published in: Feb 2023 Publisher: Packt ISBN-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.
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}