GPU Path Tracing
GLSL Path Tracer
A GPU-accelerated global illumination path tracer implemented entirely in GLSL fragment shaders using OpenGL 3.3 and Qt 6. Each pixel is a fragment shader invocation that traces rays through the scene and progressively accumulates light across frames.
Overview
The renderer runs the full path tracing loop on the GPU. The CPU side uses Qt and C++ to load scene data, upload uniforms, manage OpenGL resources, and render a full-screen quad. The fragment shader performs ray-scene intersection, BSDF sampling, light sampling, multiple importance sampling, and frame accumulation.
Architecture
CPU Host and GPU Shader Pipeline
The project separates host orchestration from shader-side rendering. C++ and Qt upload scene state and drive the render loop; GLSL modules implement the actual path tracing logic.
CPU (Qt / C++) GPU (GLSL Fragment Shader)
---------------- ---------------------------------------
Upload uniforms -> pathtracer.defines.glsl structs, math, RNG
Upload scene data -> pathtracer.intersection.glsl ray-scene intersection
Render full-screen quad -> pathtracer.bsdf.glsl material / BSDF eval
Accumulate frames -> pathtracer.sampleWarping.glsl sampling functions
pathtracer.light.glsl lights and MIS
pathtracer.frag.glsl Li_Naive / Li_Full
Progressive rendering blends the current sample with the accumulated result over time.
accumulated = mix(lastFrame, currentSample, 1.0 / float(iteration));
Features
Integrators and Lighting
Li_Naive
Iterative path tracing that accumulates emitted radiance when a path directly hits a light. This baseline integrator does not perform direct light sampling.
Li_Full
Full path tracing integrator with direct lighting and global illumination at every bounce.
Supported Light Sources
Rectangle area lights, sphere area lights, point lights, spot lights, and HDR environment lighting. Area lights use explicit sampling; point and spot lights are evaluated directly; environment lighting uses hemisphere sampling.
Sampling
Multiple Importance Sampling
ComputeDirectLight_MIS combines light-source sampling and BSDF sampling using the power heuristic. Area lights use full MIS, point and spot lights use light sampling only, and specular surfaces skip MIS to avoid double-counting direct emission.
float PowerHeuristic(float nf, float fPdf, float ng, float gPdf)
{
float f = nf * fPdf;
float g = ng * gPdf;
return (f * f) / (f * f + g * g);
}
Materials
BSDF Material System
Diffuse
Lambertian evaluation with cosine-weighted hemisphere sampling.
Specular Reflection
Perfect mirror reflection using reflect(wo).
Specular Transmission and Glass
Snell's law refraction with Fresnel reflection/transmission blending for dielectric glass.
Microfacet GGX
Trowbridge-Reitz normal distribution with Smith shadowing-masking for rough mirror materials.
Geometry
Ray-Scene Intersection
The renderer supports multiple primitive types, all transformed through inverse transform matrices so rays can be evaluated in object space.
Analytic Primitives
Rectangle, box with slab intersection, and sphere with quadratic analytic intersection.
Triangle Meshes
Moller-Trumbore triangle intersection with mesh data packed into sampler2D textures for shader access.
Texture Support
Material Maps
Albedo Maps
Gamma-corrected color textures for surface base color.
Normal Maps
Tangent-space normal maps transformed through TBN for local detail.
Roughness Maps
Texture-driven roughness for microfacet material variation.
Tech Stack
Implementation Details
glsl/
pathtracer.defines.glsl constants, structs, math helpers, RNG
pathtracer.sampleWarping.glsl disk / hemisphere / sphere sampling
pathtracer.intersection.glsl primitive intersection
pathtracer.bsdf.glsl f(), Sample_f(), Pdf()
pathtracer.light.glsl Sample_Li(), Pdf_Li(), MIS
pathtracer.frag.glsl Li_Naive, Li_Full, main()
src/
scene/ scene loading, geometry, lights, materials
mygl.cpp OpenGL setup, render loop, framebuffer ping-pong
jsons/ scene description files
images/ render outputs