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

Adding Shadows Using Mesh Shaders

In the previous chapter, we added support for multiple lights using clustered deferred techniques with the latest innovations.

We added a hard limit of 256 maximum lights, with the possibility for each one to be dynamic and unique in its properties.

In this chapter, we will add the possibility for each of these lights to cast shadows to further enhance the visuals of any asset displayed in Raptor Engine, and we will exploit the possibilities given by mesh shaders of having many of these lights cast shadows and still be in a reasonable frame time.

We will also have a look at using sparse resources to improve shadow map memory usage, moving the possibility of having many shadow-casting lights from something almost impossible to something possible and performant with current hardware.

In this chapter, we’re going to cover the following main topics:

  • A brief history of shadow techniques
  • Implementing shadow mapping using mesh...

Technical requirements

A brief history of shadow techniques

Shadows are one of the biggest additions to any rendering framework as they really enhance the perception of depth and volume across a scene. Being a phenomenon linked to lights, they have been studied in graphics literature for decades, but the problem is still far from being solved.

The most used shadow technique right now is shadow mapping, but recently, thanks to hardware-enabled ray tracing, ray traced shadows are becoming popular as a more realistic solution.

There were some games—especially Doom 3—that also used shadow volumes as a solution to make lights cast shadows, but they are not used anymore.

Shadow volumes

Shadow volumes are an old concept, already proposed by Frank Crow in 1977. They are defined as the projection of each vertex of a triangle along the light direction and toward infinity, thus creating a volume.

The shadows are sharp, and they require each triangle and each light to process accordingly...

Implementing shadow mapping using mesh shaders

Now that we have looked at the different ways to render a shadow, we will describe the algorithm and the implementation’s detail used to render many shadow maps at once leveraging the mesh shader power.

Overview

In this section, we will give an overview of the algorithm. What we are trying to achieve is to render shadows using meshlets and mesh shaders, but this will require some compute work to generate commands to actually draw the meshlets.

We will draw shadows coming from point lights, and we will use cubemaps as textures to store the necessary information. We will talk about cubemaps in the following section.

Back to the algorithm, the first step will be to cull mesh instances against lights. This is done in a compute shader and will save a per-light list of visible mesh instances. Mesh instances are used to retrieve associated meshes later on, and per-meshlet culling will be performed using task shaders later on...

Improving shadow memory with Vulkan’s sparse resources

As we mentioned at the end of the last section, we currently allocate the full memory for each cubemap for all the lights. Depending on the screen size of the light, we might be wasting memory as distant and small lights won’t be able to take advantage of the high resolution of the shadow map.

For this reason, we have implemented a technique that allows us to dynamically determine the resolution of each cubemap based on the camera position. With this information, we can then manage a sparse texture and re-assign its memory at runtime depending on the requirements for a given frame.

Sparse textures (sometimes also referred to as virtual textures) can be implemented manually, but luckily, they are supported natively in Vulkan. We are now going to describe how to use the Vulkan API to implement them.

Creating and allocating sparse textures

Regular resources in Vulkan must be bound to a single memory allocation...

Summary

In this chapter, we extended our lighting system to support many point lights with an efficient implementation. We started with a brief history of shadow algorithms, and their benefits and shortcomings, up until some of the most recent techniques that take advantage of raytracing hardware.

Next, we covered our implementation of shadows for many point lights. We explained how cubemaps are generated for each light and the optimizations we implemented to make the algorithm scale to many lights. In particular, we highlighted the culling method we reused from the main geometry pass and the use of a single indirect draw call for each light.

In the last section, we introduced sparse textures, a technique that allows us to dynamically bind memory to a given resource. We highlighted the algorithm we used to determine the contribution of each point light to the scene and how we use that information to determine the resolution of each cubemap. Finally, we demonstrated how to use...

Further reading

The book Real-Time Shadows provides a good overview of many techniques to implement shadows, many of which are still in use today.

GPU Pro 360 Guide to Shadows collects articles from the GPU Pro series that are focused on shadows.

An interesting technique described in the book is called tetrahedron shadow mapping: the idea is to project the shadow map to a tetrahedron and then unwrap it to a single texture.

The original concept was introduced in the Shadow Mapping for Omnidirectional Light Using Tetrahedron Mapping chapter (originally published in GPU Pro) and later expanded in Tile-based Omnidirectional Shadows (originally published in GPU Pro 6).

For more details, we refer you to the code provided by the author: http://www.hd-prg.com/tileBasedShadows.html.

Our sparse texture implementation is based on this SIGGRAPH presentation: https://efficientshading.com/wp-content/uploads/s2015_shadows.pdf.

This expands on their original paper, found here: http...

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}