Convert Figma logo to code with AI

nvpro-samples logovk_mini_path_tracer

A beginner-friendly Vulkan path tracing tutorial in under 300 lines of C++.

1,106
61
1,106
0

Top Related Projects

Implementation of Peter Shirley's Ray Tracing In One Weekend book using Vulkan and NVIDIA's RTX extension.

Ray tracing examples and tutorials using VK_KHR_ray_tracing

One stop solution for all Vulkan samples

10,152

C++ examples for the Vulkan graphics API

Quick Overview

The vk_mini_path_tracer is a minimalistic path tracer implemented using Vulkan. It serves as an educational tool to demonstrate real-time ray tracing techniques and Vulkan ray tracing extensions. The project is part of the NVIDIA Vulkan Ray Tracing Tutorials and provides a compact, yet functional path tracer.

Pros

  • Excellent learning resource for Vulkan ray tracing
  • Compact and focused implementation
  • Well-documented code with explanatory comments
  • Demonstrates modern GPU-based rendering techniques

Cons

  • Limited features compared to full-fledged renderers
  • May require advanced graphics knowledge to fully understand
  • Specific to Vulkan, not applicable to other graphics APIs
  • Requires compatible hardware with ray tracing support

Code Examples

  1. Setting up a ray tracing pipeline:
void createRtPipeline()
{
  // Create the ray tracing pipeline
  nvvk::RayTracingPipelineGenerator rtPipelineGen;

  // Setup ray generation shader
  rtPipelineGen.addShader(readFile("spv/raytrace.rgen.spv"), VK_SHADER_STAGE_RAYGEN_BIT_KHR);
  
  // Setup miss shader
  rtPipelineGen.addShader(readFile("spv/raytrace.rmiss.spv"), VK_SHADER_STAGE_MISS_BIT_KHR);

  // Setup closest hit shader
  rtPipelineGen.addShader(readFile("spv/raytrace.rchit.spv"), VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);

  // Create the pipeline
  m_rtPipeline = rtPipelineGen.createPipeline(m_device);
}
  1. Tracing rays:
void traceRays()
{
  vkCmdBindPipeline(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_rtPipeline);
  vkCmdBindDescriptorSets(cmdBuf, VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, m_pipelineLayout, 0, 1, &m_rtDescSet, 0, nullptr);

  VkStridedDeviceAddressRegionKHR raygenShaderEntry{};
  // ... Set up shader binding table entries

  vkCmdTraceRaysKHR(cmdBuf, &raygenShaderEntry, &missShaderEntry, &hitShaderEntry, &callableShaderEntry, m_size.width, m_size.height, 1);
}
  1. Updating the scene:
void updateScene(float deltaTime)
{
  // Update camera
  m_camera.update(deltaTime);

  // Update push constants
  PushConstantRay pcRay{};
  pcRay.clearColor     = m_clearColor;
  pcRay.lightPosition  = m_lightPosition;
  pcRay.lightIntensity = m_lightIntensity;
  pcRay.lightType      = m_lightType;

  vkCmdPushConstants(cmdBuf, m_pipelineLayout, VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR | VK_SHADER_STAGE_MISS_BIT_KHR, 0, sizeof(PushConstantRay), &pcRay);
}

Getting Started

  1. Clone the repository:
    git clone https://github.com/nvpro-samples/vk_mini_path_tracer.git
    
  2. Install Vulkan SDK and required dependencies
  3. Build the project using CMake:
    mkdir build && cd build
    cmake ..
    make
    
  4. Run the executable:
    ./vk_mini_path_tracer
    

Competitor Comparisons

Implementation of Peter Shirley's Ray Tracing In One Weekend book using Vulkan and NVIDIA's RTX extension.

Pros of RayTracingInVulkan

  • More comprehensive implementation with advanced features like denoising and temporal accumulation
  • Includes a user interface for real-time parameter adjustments
  • Supports loading external 3D models and textures

Cons of RayTracingInVulkan

  • Higher complexity and steeper learning curve for beginners
  • Requires more system resources due to advanced features
  • Less focused on educational purposes compared to vk_mini_path_tracer

Code Comparison

vk_mini_path_tracer:

void trace_ray(Ray* ray, Hit* hit) {
  hit->t = 1e20f;
  for (int i = 0; i < g_num_spheres; i++) {
    intersect_sphere(ray, &g_spheres[i], hit);
  }
}

RayTracingInVulkan:

void TraceRay(const Ray& ray, HitInfo& hitInfo, float tMin, float tMax) {
    hitInfo.distance = tMax;
    for (const auto& object : scene.objects) {
        object->Intersect(ray, tMin, hitInfo);
    }
}

The code snippets show similar ray tracing logic, but RayTracingInVulkan uses more advanced C++ features and a more flexible object-oriented approach.

Ray tracing examples and tutorials using VK_KHR_ray_tracing

Pros of vk_raytracing_tutorial_KHR

  • More comprehensive tutorial covering various aspects of Vulkan ray tracing
  • Includes multiple examples demonstrating different ray tracing techniques
  • Better documentation and explanations for each step of the implementation

Cons of vk_raytracing_tutorial_KHR

  • More complex codebase, potentially harder for beginners to grasp
  • Requires more setup and dependencies compared to the mini path tracer
  • May be overkill for simple ray tracing projects

Code Comparison

vk_raytracing_tutorial_KHR:

void createRtDescriptorSet()
{
  m_rtDescSetLayoutBind.addBinding(RtDescriptorSetBindings::eAccelerationStructure, VK_DESCRIPTOR_TYPE_ACCELERATION_STRUCTURE_KHR, 1,
                                   VK_SHADER_STAGE_RAYGEN_BIT_KHR | VK_SHADER_STAGE_CLOSEST_HIT_BIT_KHR);
  m_rtDescSetLayout = m_rtDescSetLayoutBind.createLayout(m_device);
  m_rtDescPool      = m_rtDescSetLayoutBind.createPool(m_device);
  m_rtDescSet       = nvvk::allocateDescriptorSet(m_device, m_rtDescPool, m_rtDescSetLayout);
}

vk_mini_path_tracer:

void createDescriptorSet()
{
  VkDescriptorSetLayoutBinding binding{};
  binding.binding = 0;
  binding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
  binding.descriptorCount = 1;
  binding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT;

  VkDescriptorSetLayoutCreateInfo layoutInfo{};
  layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
  layoutInfo.bindingCount = 1;
  layoutInfo.pBindings = &binding;
}

One stop solution for all Vulkan samples

Pros of Vulkan-Samples

  • Comprehensive collection of Vulkan samples covering various aspects of the API
  • Official repository maintained by Khronos Group, ensuring up-to-date and accurate implementations
  • Includes performance best practices and optimization techniques

Cons of Vulkan-Samples

  • Larger and more complex codebase, potentially overwhelming for beginners
  • Focuses on general Vulkan usage rather than specific path tracing techniques
  • May require more setup and configuration to run individual samples

Code Comparison

vk_mini_path_tracer:

void traceRay(Ray& ray, vec3& color, int depth) {
    if (depth >= MAX_DEPTH) return;
    HitRecord rec;
    if (world.hit(ray, 0.001f, FLT_MAX, rec)) {
        // Handle ray intersection and recursive tracing
    }
}

Vulkan-Samples:

void VulkanSample::draw()
{
    auto command_buffer = getCommandBuffer(true);
    vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
    drawGeometry(command_buffer);
    vkCmdEndRenderPass(command_buffer);
    flushCommandBuffer(command_buffer);
}

The vk_mini_path_tracer focuses on ray tracing logic, while Vulkan-Samples demonstrates general Vulkan rendering pipeline setup and execution.

10,152

C++ examples for the Vulkan graphics API

Pros of Vulkan

  • Comprehensive collection of Vulkan examples covering a wide range of techniques and features
  • Well-documented and organized codebase with clear explanations for each example
  • Regularly updated to incorporate new Vulkan features and best practices

Cons of Vulkan

  • Focuses on individual techniques rather than a complete path tracing implementation
  • May be overwhelming for beginners due to the large number of examples and advanced concepts
  • Less emphasis on performance optimization compared to vk_mini_path_tracer

Code Comparison

vk_mini_path_tracer:

void PathTracer::trace_rays() {
  // Simplified path tracing implementation
  for (int y = 0; y < height; y++) {
    for (int x = 0; x < width; x++) {
      // Ray tracing logic
    }
  }
}

Vulkan:

void VulkanExample::buildCommandBuffers() {
  VkCommandBufferBeginInfo cmdBufInfo = {};
  cmdBufInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  // Command buffer setup and recording
}

The vk_mini_path_tracer focuses on implementing a compact path tracer, while Vulkan provides examples of various Vulkan concepts and techniques. The code snippets illustrate the different approaches: vk_mini_path_tracer implements core path tracing logic, while Vulkan demonstrates Vulkan-specific command buffer setup.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

logo

vk_mini_path_tracer

A relatively small, beginner-friendly path tracing tutorial.

:arrow_forward: Load the tutorial! :arrow_backward:

This tutorial is a beginner-friendly introduction to writing your own fast, photorealistic path tracer in less than 300 lines of C++ code and 250 lines of GLSL shader code using Vulkan. Here's an example of what you'll render at the end of this tutorial!

Vulkan is a low-level API for programming GPUs – fast, highly parallel processors. It works on a wide variety of platforms – everything from workstations, to gaming consoles, to tablets and mobile phones, to edge devices.

Vulkan is usually known as a complex API, but I believe that when presented in the right way, it's possible to make learning Vulkan accessible to people of all skill levels, whether they're never programmed graphics before or whether they're a seasoned rendering engineer. Perhaps surprisingly, one of the best ways to introduce Vulkan may be with GPU path tracing, because the API involved is relatively small.

We'll show how to write a small path tracer, using the NVVK helpers, included in the nvpro-samples framework, to help with some Vulkan calls when needed. For advanced readers, we'll also optionally talk about performance tips and some of the implementation details inside the helpers and Vulkan itself.

The final program uses less than 300 lines of C++ and less than 250 lines of GLSL shader code, including comments. You can find it here.

Here are all the Vulkan functions, and NVVK functions and objects, that we'll use in the main tutorial:

Vulkan Functions
vkAllocateCommandBuffersvkBeginCommandBuffervkCmdBindDescriptorSets
vkCmdBindPipelinevkCmdDispatchvkCmdFillBuffer
vkCmdPipelineBarriervkCreateCommandPoolvkCreateComputePipelines
vkDestroyCommandPoolvkDestroyPipelinevkDestroyShaderModule
vkFreeCommandBuffersvkGetBufferDeviceAddressvkQueueSubmit
vkQueueWaitIdlevkUpdateDescriptorSets
NVVK Functions and Objects
nvvk::BufferNVVK_CHECKnvvk::Context
nvvk::ContextCreateInfonvvk::createShaderModulenvvk::DescriptorSetContainer
nvvk::makenvvk::RayTracingBuilderKHRnvvk::ResourceAllocatorDedicated

Chapters

Chapter
small
Hello, Vulkan!
small
Device Extensions and Vulkan Objects
small
Memory and Commands
small
Writing an Image
small
Compute Shaders
small
Descriptors
small
Acceleration Structures and Ray Tracing
small
Four Uses of Intersection Data
small
Accessing Mesh Data
small
Perfectly Specular Reflections
small
Antialiasing and Pseudorandom Number Generation
small
Diffuse Reflection

Extra Chapters

These are optional, extra tutorials that show how to polish and add new features to the main tutorial's path tracer. Make sure to check out the list of further Vulkan and ray tracing resources at the end of the main tutorial as well!

Extra Chapter

Gaussian Filter Antialiasing

Measuring Performance

Compaction

Including Files and Matching Values Between C++ And GLSL

Push Constants

More Samples

Images

Debug Names

Instances and Transformation Matrices

Multiple Materials

Ray Tracing Pipelines

Building and Running

Please see the instructions here.