Software Engineer & Media Artist
๐ท Instagram
๐ป Github
๐ LinkedIn
๐ฎ A GPU-based progressive path tracer written in Vulkan.
flow
is a minimal, progressive path tracer implemented in Vulkan with GLSL shaders. It renders a small group of implicit surfaces (spheres, boxes, planes, etc.) with several different material models (primarily lambertian, metallic, and dielectric).
For the time being, flow
uses a single render pass instance with two distinct subpasses. The first subpass involves two floating-point images in a โping-pongโ arrangement. This is how the light accumulates over the course of many frames, leading to a well-converged image. Whichever of the two images was used as a color attachment during this first subpass serves as an input attachment to the next (and final) subpass. Input attachments are unique to Vulkan and allow a render pass attachment to be read in a fragment shader stage during a subpass. Input attachments come with several restrictions and do not support random access like a typical sampler2D
, for example.
The second subpass simply reads from this input attachment and writes to one of the swapchain images that are presented to the screen.
As such, there are two separate graphics pipelines - one that runs the main path tracing routine and another that normalizes the accumulated light (converts it from HDR to [0..1]
) and writes to the corresponding swapchain image.
Built on top of vkstarter.
Separately, as part of a R&D initiative for Obscura Digital, I was tasked with investigating NVIDIAโs new RTX graphics card line. One of the primary features enabled by the RTX cards is support for real-time raytracing.
Using C++ and the new Vulkan raytracing extensions, I created a sample app to demonstrate this new functionality. RTX introduces 5 new shader stages (3 of which are required) as part of a new raytracing-specific pipeline object. Geometry is uploaded into GPU-side buffers from which an acceleration structure is constructed to aid in efficient ray-triangle intersection calculations.
My application supported basic implicit surfaces (spheres and planes) as well as .obj loading via tinyobjloader (an external C++ header-only library).
The first example demonstrates a simple raytracer with direct lighting only. The second example demonstrates a path tracer, which calculates direct and indirect lighting via Monte Carlo sampling, which, of course, leads to visible noise in the final render.
On numerous occasions, I have experimented with small, GLSL-based path tracers. Another example can be seen below, along with the corresponding GLSL fragment shader code. At some point, I would love to consolidate my research and build a more fully featured global illumination renderer.