This repository contains the code for the SIGGRAPH 2025 paper:
Reservoir Splatting for Temporal Path Resampling and Motion Blur
Jeffrey Liu (University of Illinois Urbana-Champaign), Daqi Lin (NVIDIA), Markus Kettunen (NVIDIA), Chris Wyman (NVIDIA), Ravi Ramamoorthi (NVIDIA and University of California San Diego)
The code is implemented as a standalone ReSTIR path tracer on top of the Falcor 8.0 framework [Kallweit et al. 2022]. Reservoir splatting is an extension of GRIS [Lin et al. 2022] and Area ReSTIR [Zhang et al. 2024], which forward-reprojects primary hits from the prior frame to the current frame. This preserves exact primary hits across frames, which generally improves the robustness of temporal resampling.
- All relevant code can be found in the
Source/RenderPasses/ReservoirSplattingrender pass. - The script
scripts/ReservoirSplatting.pycan be used to set up the render graph. - Falcor loads the
pysceneformat, which can import different scene formats.- Check out
media/test_scenes/cornell_box.pyscenefor a simple scene, but fancier scenes can be imported through Benedikt's rendering resources or pbrt-v4's scenes! - This implementation uses the reconnection shift after the primary hit, so delta materials are not supported. Refer to the GRIS paper [Lin et al. 2022] or the ReSTIR Course Notes [Wyman et al. 2023] for more details on different ReSTIR shift mappings.
- Check out
Note that most of the reservoir splatting code has not been thoroughly optimized. Contributions are welcome!
Make sure to clone the repository with its required submodules:
git clone --recursive https://github.com/Jebbly/Reservoir-Splatting.git
For hardware / software prerequisites and instructions on how to build Falcor, check out Falcor's documentation.
After building and running Mogwai, run the script in scripts/ReservoirSplatting.py to set up the reservoir splatting render graph.
Depth of field and motion blur depend on the camera settings. When a scene is loaded, these can be enabled through Scene Settings -> Camera:
- A non-zero aperture radius will enable depth of field.
- A non-zero shutter speed will enable motion blur.
- Since actual frame rate is variable, we use an artificial time between frames to compute motion blur. For example, if the shutter speed is set to 1/24 s and the artificial frame time is 1/48 s, motion blur is computed across half the frame time (even if the actual frame took less time to render).
- You can change the simulated time between frames (defaults to 60 FPS) under
ReservoirSplatting -> Rendering Options -> Simulated Frame Time.
The script defaults to splat-only temporal resampling, but different options can be enabled through the UI or by modifying the script. In the UI, under ReservoirSplatting -> ReSTIR Options -> Temporal Resampling, the following temporal resampling options are supported:
GatherOnlyis our (un-optimized) reimplementation of Area ReSTIR [Zhang et al. 2024].FastandRobustare the two options presented in Area ReSTIR, whileClampeduses integer motion vectors.- The robust reuse optimization is enabled by default, when the
Robustoption is selected. - If the camera has a non-zero aperture radius, both the lens vertex copy and the primary hit reconnection are used.
ScatterOnlyis our single-splat implementation.ScatterBackupis our splat + backup implementation.- Our results use
Clampedas the gather method andBalanceas the MIS weighting scheme.
- Our results use
MultiSplattingis our multi-splat implementation.- This option is only available when the camera has a non-zero shutter speed.
- If the partition count is set too high, your GPU may run out of memory.
We provide a set of utility in the UI for debugging and/or capturing output.
- Using
Scene Settings -> Freeze, you can pause at your current frame and preserve the temporal history from the previous frame.- This is helpful for debugging / capturing under motion.
- A reference image under motion can be captured by disabling all ReSTIR options and enabling the
AccumulationPass. This is used for motion blurred reference images.
- Using
Scene Settings -> User Interaction:- You can record the camera motion to a text file, and then replay the same motion from the output text file.
- By default with
Freeze Frame IDset to -1, the recorded motion will loop. - Setting
Freeze Frame IDto a value greater than -1 will freeze the frame at the specified frame ID.- Unfreeze to continue playing the motion!
- If
Replay for Accumulationis enabled, the frame will no longer freeze but will instead contribute to theAccumulationPass. EnableView Accumulated ImageandAccumulatePass -> Enabledto view the accumulation under motion, at the specified frame ID. This is useful for verifying unbiasedness under motion, but note that this is a very slow process since it effectively replays the entire motion sequence for one accumulated sample.
- Use the
FrameDumperpass at the end to output every frame, which can be used to capture a sequence of frames and/or generate a video.- Warning: if you want to generate a video, disable
Save PNG Filesfor better performance, and use FFmpeg.
- Warning: if you want to generate a video, disable
A video can be generated as follows:
ffmpeg.exe -framerate 30 -i "C:/frameDump/frame.%05d.pam" -c:v h264_nvenc -preset slow -b:v 4M -pix_fmt yuv420p output.mp4
Note that higher bitrates are usually necessary to capture the noise characteristics properly.