Enabling Raytracing - Part 1

Code so Far

Here is the code after this section

Enabling Raytracing - Part 1

Now that we have created a basic render using rasterization, the next goal is to create the same render using ray tracing, and a mechanism to switch between the two rendering modes. For this I followed the NVidia raytracing tutorial which is split into two parts.

In order to switch between the the two modes I needed to bind keyboard events from the Window to the Game class. Just like how the WM_Paint method is subscribed to currently, I added subscription callback mechanism for WM_KEYDOWN, and WM_KEYUP Window's events that the game class now subscribes to. 

On space bar, the window is configured to switch between raytracing and rasterization. For now, since raytracing is not implemented, if the user presses space bar, it goes between using rasterization, and rendering nothing. This was updated within the render loop of the game.

After making these updates, this is the current state of the program:


After adding in the toggle, I began setting up the components needed to get raytracing up and running.

Before setting up the pipeline for raytracing, some initial things needed to be done. The first thing was to change the device and command lists class types we are retrieving during initialization. Raytracing APIs were included in ID3DDevice5, and ID3D12GraphicsCommandList4, so initialization of these objects was updated. I then created a method for checking whether the the device supports raytracing. If the application does not support it, the application asserts. 

Setting up the Raytracing pipeline

Unlike how rasterization writes to a render target, the raytracing pipeline writes to an image using a unordered access view (UAV). With rasterization we execute a draw through Draw* methods on the command list. With Raytracing, we will execute the DispatchRays method. The number of rays we generate can be customized, but for our rendering we will draw one ray per pixel. The GPU pipeline for raytracing is depicted through this simplified control flow diagram:


In the ray generation shader, the the ray is created. The rays collision with primitives is calculated using an accelerated structure for speeding up collision traversal. The intersection and any hit are set to passthrough for this project. After computing the closest triangle hit, the closests hit shader is ran. If the ray never hit anything, the miss shader is ran. The output of the closest hit and miss shader is a color an distance. These outputs are returned to the RayGen which writes that pixel's color to the UAV.

To set this up we need the following:
- Create the acceleration structures,
- Create the raytracing shaders
- Describe the shaders in the raytracing pipeline state object
- Create resources on the heap for shaders
- Setting up the Shader Binding Table



I began by setting up the acceleration structures. The acceleration consists of a top-level acceleration structure, and a bottom-level acceleration structure. The bottom-level acceleration structure contains the vertices of our cube in local space. The top level acceleration structure, also called an instance, points to the bottom level acceleration structure and contains a model matrix associated with the cube.

After the acceleration structures are created, the shaders were created as well as the root signatures. All of them are bundled into the raytracing pipeline state object.

Things to note when coding this part, a recent Windows SDK is needed. I struggled with linker errors due to not having the latest SDK. Additionally, the Nvidia tutorials compiled the shader libraries at runtime using the DirectX compiler. This ran into problems with hash issues, and DXR not being able to find function name symbols in the shaders. I deviated from the tutorial's implementation to be more consistent with previous compilation of shaders. Instead I rely on visual studio to use the DirectX compiler to create the CSO files and load the CSO's to Blobs at runtime just like I am doing for the vertex and fragment shaders.

Up Next

This was just the start to setting up raytracing. In the next post, I will complete the enabling raytracing setup. I will setup the shader binding table and finally get our cube rendering in the render loop.



Comments

Popular posts from this blog

Rendering a Scene

Denoising

Enabling Raytracing - Part 2