Skip to content

leotmp/LupinPathTracer

Repository files navigation

Lupin: A WGPU Path Tracing Library

Warning: This project uses WGPU features that are currently experimental, so use at your own risk.

Lupin is a data-oriented library for fast photorealistic rendering on the GPU with WGPU. It's meant to be simple and C-like, and while it supports hardware raytracing, it still provides a software implementation for compatibility with older devices. It is mainly designed for research and testing.

  • Physically based path tracing with multiple importance sampling (MIS).
  • Naive path tracing and other algorithms are also supported.
  • Russian Roulette path termination.
  • Progressive and tiled rendering.
  • Emissive mesh lights and HDRIs.
  • Materials: Matte, glossy, reflective, transparent, refractive, subsurface, volumetric, with GLTF-PBR compatibility.
  • Support for emission-maps, metallic and roughness maps and normal-maps.
  • Support for different aperture, aspect ratio, focal length, and orthographic cameras.
  • Optional GPU Denoising with OIDN.

During the development of this project I've used Yocto/GL as a reference for the theoretical foundations of material models and light sampling. This project also uses its scene format and scenes (with permission by its author, who I know personally).

Scene serialization could be implemented using lupin_loader, or a custom loader which can use Lupin's scene building API.

Showcase:

lonemonk Scene by Carlo Bergonzini.

classroom Scene by Christophe Seux.

bistroexterior Scene by Amazon Lumberyard.

landscape Scene by Jan-Walter Schliep, Burak Kahraman, Timm Dapper.

lupin_clip.mp4

(Full video here).

Depending on the hardware and on the complexity of the scene, the user can likely move the camera and visualize the path traced scene in a pseudo-real-time fashion. Try it yourself by downloading the latest release, which includes Lupin Viewer and a few test scenes! More complex scenes can be found here.

API Usage:

Here's a simple example of loading a scene and producing a path traced image:

use lupin_pt as lp;
use lupin_loader as lpl;
use lupin_pt::wgpu as wgpu;

fn main()
{
    // Initialize WGPU
    let (device, queue, _) = lp::init_default_wgpu_context_no_window();
    // Initialize lupin resources (all desc-type structs have reasonable defaults)
    let pathtrace_res = lp::build_pathtrace_resources(&device, &lp::BakedPathtraceParams {
        with_runtime_checks: false,  // This greatly affects render time!
        max_bounces: 8,
        samples_per_pixel: 5,
    });

    // Load/create the scene.
    let (scene, cameras) = lpl::build_scene_cornell_box(&device, &queue, false);
    // let (scene, cameras) = lpl::load_scene_yoctogl_v24("scene_path", &device, &queue, false).unwrap();
    // Set up double buffered output texture for accumulation
    let mut output = lp::DoubleBufferedTexture::create(&device, &wgpu::TextureDescriptor {
        label: None,
        size: wgpu::Extent3d { width: 1000, height: 1000, depth_or_array_layers: 1 },
        mip_level_count: 1,
        sample_count: 1,
        dimension: wgpu::TextureDimension::D2,
        format: wgpu::TextureFormat::Rgba16Float,
        usage: wgpu::TextureUsages::STORAGE_BINDING | wgpu::TextureUsages::TEXTURE_BINDING |
               wgpu::TextureUsages::COPY_SRC | wgpu::TextureUsages::COPY_DST |
               wgpu::TextureUsages::RENDER_ATTACHMENT,
        view_formats: &[]
    });

    // Accumulation loop. This is highly recommended as opposed to increasing the sample
    // count in lp::BakedPathtraceParams, because shader invocations that run for too long
    // will cause most current OSs to issue a complete driver reset. Accumulation is useful
    // as a way to break-up the GPU work into multiple invocations.
    let num_accums = 200;
    for accum_idx in 0..num_accums
    {
        lp::pathtrace_scene(&device, &queue, &pathtrace_res, &scene, output.front(), Default::default(), &lp::PathtraceDesc {
            accum_params: Some(lp::AccumulationParams {
                prev_frame: output.back(),
                accum_counter: accum_idx,
            }),
            tile_params: None,
            camera_params: cameras[0].params,
            camera_transform: cameras[0].transform,
            force_software_bvh: false,
            advanced: Default::default(),
        });
        output.flip();
    }
    output.flip();

    lpl::save_texture(&device, &queue, std::path::Path::new("output.hdr"), output.front()).unwrap();
}

To run this example: cargo run --release --bin=example1. For more information see the project's crates.io page.

Support Matrix:

DX12 Vulkan Metal
Windows ⏳* /
Linux / /
Mac / / ⏳**

⏳: Automatically supported once WGPU implements certain features.

*: This can run, but only with software raytracing.

**: Currently does not support GPU denoising. Will fall back to CPU denoising. Other than that, needs upstream WGPU work to be able to run at all.

Build:

Just add the following line to your Cargo.toml:

[dependencies]
lupin_pt = "*"

This library optionally supports denoising using OIDN. To enable denoising, make sure to add features = [ "denoising" ] to your Cargo.toml. OIDN has to be installed separately (binaries can be found here). Make sure CUDA/HIP (NVIDIA/AMD) is installed on your system for proper GPU denoising.

Other features are "denoise-force-disable-shared-device", which forces the CPU denoising fallback, and "force-swrt" which acts like the device doesn't support hardware raytracing, even if it does.

About

No description, website, or topics provided.

Resources

License

Stars

16 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors