Hello Triangle Ray Tracing¶

This example shows the fundamentals of Vulkan ray tracing: creating acceleration structures, ray tracing pipelines, shader binding tables, and tracing rays against geometry. Unlike Hello Sphere Ray Tracing which uses custom intersection shaders, this example uses Vulkan's built-in triangle intersection which is highly optimized. This is your starting point for learning modern GPU ray tracing for realistic lighting, reflections, and global illumination.
The example uses the KDGpuExample helper API, demonstrating low-level ray tracing setup.
Overview¶
What this example demonstrates:
- Enabling VK_KHR_ray_tracing_pipeline extension
- Creating bottom-level acceleration structures (BLAS) for triangle geometry
- Creating top-level acceleration structures (TLAS) for scene instances
- Ray tracing pipeline with ray generation, miss, and closest-hit shaders
- Shader binding table (SBT) setup and ray tracing dispatch
- Writing ray traced output to storage image
Use cases:
- Realistic lighting and shadows
- Reflections and refractions
- Global illumination
- Ambient occlusion
- Path tracing
Vulkan Requirements¶
- Vulkan Version: 1.2+
- Extensions:
- VK_KHR_ray_tracing_pipeline
- VK_KHR_acceleration_structure
- VK_KHR_buffer_device_address (required for ray tracing)
- VK_KHR_deferred_host_operations (optional, for async builds)
- Features:
rayTracingPipelineaccelerationStructurebufferDeviceAddress
- Shader: SPIR-V 1.4+ with ray tracing instructions
Key Concepts¶
Ray Tracing Pipeline:
Traditional rasterization: Vertices → Rasterization → Fragment Shaders → Pixels
Ray tracing: Rays → Acceleration Structure Traversal → Intersection → Shading
Ray tracing shaders:
- Ray Generation (
.rgen): Launches rays (one per pixel typically) - Miss (
.rmiss): Executed when ray hits nothing (sky color) - Closest Hit (
.rchit): Executed on nearest intersection (shading) - Any Hit (
.rahit): Executed on any intersection (transparency) - Intersection (
.rint): Custom intersection test (for non-triangles)
Spec: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_ray_tracing_pipeline.html
Acceleration Structures:
Ray-triangle intersection is expensive (O(N) for N triangles). Acceleration structures are BVH (Bounding Volume Hierarchy) trees that accelerate intersection to O(log N).
BLAS (Bottom-Level AS):
- Contains actual geometry (triangles or AABBs)
- Built from vertex/index buffers
- One BLAS per mesh typically
- Device address used for referencing
TLAS (Top-Level AS):
- Contains instances of BLAS (transforms + BLAS references)
- Defines scene layout
- One TLAS per scene
- Ray tracing traces against TLAS
Example:
1 2 3 4 | |
Spec: https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_acceleration_structure.html
Shader Binding Table (SBT):
SBT maps ray tracing shader groups to device memory regions:
1 2 3 4 | |
During tracing, SBT selects which shader to execute based on ray type, geometry hit, etc.
Implementation¶
Ray Tracing Pipeline¶
The bind group layout exposes the TLAS and the output storage image to the ray generation shader:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
Filename: hello_triangle_rt/hello_triangle_rt.cpp
The pipeline brings together all three shader stages and organises them into shader groups. A General group is used for both the ray generation and miss shaders. The closest-hit shader uses TrianglesHit, which tells the driver to use the GPU's built-in hardware triangle intersection unit rather than a custom intersection shader:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | |
Filename: hello_triangle_rt/hello_triangle_rt.cpp
Key points:
RayTracingShaderGroupType::TrianglesHit: delegates intersection to dedicated RT hardwaremaxRecursionDepth = 1: primary rays only — no recursive bounces
Shader Binding Table¶
The Shader Binding Table maps the pipeline's shader groups to device memory regions and is used by the traceRays call to select which shaders execute at runtime:
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Filename: hello_triangle_rt/hello_triangle_rt.cpp
Acceleration Structures¶
Bottom-Level AS (triangle geometry):
AccelerationStructureGeometryTrianglesData describes the vertex buffer layout. The BLAS is sized at creation time and filled during the GPU build step:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | |
Filename: hello_triangle_rt/hello_triangle_rt.cpp
Top-Level AS (scene instances):
The TLAS holds one instance of the BLAS with a scale transform applied. TriangleFacingCullDisable ensures both faces of the triangle are visible:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | |
Filename: hello_triangle_rt/hello_triangle_rt.cpp
Building the acceleration structures:
Both structures must be built on the GPU via a command buffer. A memory barrier between the BLAS and TLAS builds is mandatory — failing to synchronize here means the TLAS may read an incomplete BLAS:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | |
Filename: hello_triangle_rt/hello_triangle_rt.cpp
Rendering¶
Each frame the swapchain image is transitioned to General layout so it can be written by the ray generation shader as a storage image. The traceRays call dispatches one ray per pixel using the three SBT regions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
Filename: hello_triangle_rt/hello_triangle_rt.cpp
Ray Tracing Shaders¶
The pipeline uses three GLSL shaders located under assets/shaders/examples/hello_triangle_rt/.
Ray Generation — raygen.rgen¶
The ray generation shader fires one ray per pixel with a fixed forward direction (no camera matrix — the triangle lives in NDC space). traceRayEXT traverses the TLAS and the result written by the hit or miss shader is stored into the output image:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |
Filename: hello_triangle_rt/raygen.rgen
Closest Hit — closest.rchit¶
When the ray intersects the triangle the closest-hit shader runs. hitAttributeEXT vec2 rayAttributes contains the hardware-computed barycentric coordinates (u, v) of the hit point; the third coordinate is derived. The three barycentric weights are mapped directly to RGB to produce the classic multi-coloured triangle:
1 2 3 4 5 6 7 8 9 10 11 | |
Filename: hello_triangle_rt/closest.rchit
Miss — miss.rmiss¶
When no geometry is hit the miss shader writes a flat dark-gray background into the payload:
1 2 3 4 5 6 7 8 9 | |
Filename: hello_triangle_rt/miss.rmiss
Performance Notes¶
Ray Tracing Cost:
- More expensive than rasterization for primary visibility
- Excellent for secondary rays (reflections, shadows, GI)
- AS build cost: ~1-10ms for complex scenes (can be amortized)
- AS memory: ~10-30% of geometry size
Optimization Tips:
- Use
Opaqueflag when possible (skip any-hit) - Compact acceleration structures after build (reduces memory)
- Update TLAS for dynamic objects (cheaper than rebuild)
- Use ray culling (tMin/tMax, ray masks)
- Batch rays for coherence (nearby pixels shoot similar rays)
Hardware Requirements:
- NVIDIA: RTX series (Turing+), dedicated RT cores
- AMD: RDNA 2+ (RX 6000+), ray accelerators
- Intel: Arc series (Alchemist+)
- Mobile: Limited support; check vendor specs
See Also¶
- Hello Sphere Ray Tracing - Custom intersection shaders for spheres
- Hybrid Rasterization and Ray Tracing - Combining rasterization with ray tracing
- Buffer Device Address (GPU Pointers) - Buffer device address (required for RT)
- Ray Tracing In Vulkan - Official Vulkan blog
- Ray Tracing Guide - Official Vulkan documentation
- NVIDIA Ray Tracing Tutorial - Advanced techniques
Further Reading¶
- Ray Tracing Gems - Free book on ray tracing
- Path Tracing - Path tracing theory
Updated on 2026-03-31 at 00:02:07 +0000