Skip to content

Interactive Mode

Modes 3 (CUDA) and 5 (OptiX) open an SDL2 window where any scene can be explored in real time: mouse-driven camera, progressive accumulation, and a Dear ImGui panel holding every rendering parameter. Mode 5 is the default when the OptiX SDK is available; it is also the one with the motion regulator and the AI denoiser.


Starting interactive mode

cd build
./rayon --scene ../resources/scenes/17_cloud_bunny.yaml        # mode 5 (or 3 without OptiX)
./rayon -m 3 --scene ../resources/scenes/09_color_bleed_box.yaml

SDL2 required

The interactive modes exist only when SDL2 was found at CMake configure time. On a remote GPU server, run the window through VNC with scripts/rayon_vnc.sh (see Getting Started).


Camera controls

Input Effect
Left mouse + drag Orbit around the look-at point
Right mouse + drag Pan the camera and the look-at point
Scroll wheel Zoom (distance to the look-at point)
O Auto orbit

Any camera change restarts the accumulation.

Keyboard shortcuts

Key Effect
Space Pause or resume the accumulation
Left / Right Previous / next scene (every YAML file of resources/scenes/)
Numpad + / − (or = / −) Next / previous HDR sky
N Toggle the normal visualisation
F Toggle the samples-per-second counter
L Toggle the logo
H Hide / show the panel
Enter Collapse / expand the panel window
C Collapse / expand every section
R Reset the light, material and camera settings to their defaults
Esc Quit

How accumulation works

Each frame adds a batch of Samples/Batch samples to every pixel (8 by default; a scene can set settings.samples_per_batch, and --samples-per-batch on the command line wins). The samples go into a float accumulation buffer that stays on the GPU; a small kernel converts it to the 8-bit display image.

While the camera is still, the renderer keeps adding batches until one of these happens:

  • Adaptive sampling reports that 99.9 % of the pixels have converged (see below),
  • the budget of 100 000 samples per pixel is reached,
  • you pause it with Space, or started with --no-auto-accumulate.

While the camera moves, the OptiX renderer trades quality for frame rate (see Camera Motion below). The CUDA renderer keeps rendering full batches.


The control panel

The panel sits at the right of the window. Every section is a collapsible header.

Scene

The scene combo lists every YAML file found in resources/scenes/; the arrow keys cycle through it. The current camera position and look-at point are displayed, and the button Save camera, lights & tone map to scene YAML writes them back into the file the scene was loaded from, together with the light settings and the tone map. Only the camera: lines (position, look_at, fov) and the settings: keys background_intensity, light_intensity, light_falloff, tone_mapping, exposure (and indirect_clamp on OptiX) are rewritten; comments and everything else are kept. This is how the bundled scenes got their viewpoints.

Performance Monitoring

Samples per pixel so far, throughput in samples per second, time per pass, and a history graph of both. Two diagnostic maps replace the image while checked (one at a time):

Control Effect
Sample Heatmap Plasma colour map of the samples spent per pixel by adaptive sampling (purple = few, yellow = many); greyed out when adaptive sampling is off
Cost Heatmap The work per sample of each pixel (path bounces plus volume tracking steps, averaged over its samples), on the same scale with yellow at the most expensive pixel, whose value is printed under the checkbox. It shows where the time goes: the inside of a cloud, glass seen through glass, the dark corners where paths bounce until the depth limit

Camera Settings

Field of view, depth of field (aperture and focus distance), auto orbit.

Environment & Materials

Control Effect
Sky Built-in gradient or any .hdr file of resources/hdri/ (HDR Sky Dome)
Lights inten. Multiplier on every light's emission (settings.light_intensity)
Lights falloff Distance exponent of the lights' reach, 2 = physical (Lights & Shadows)
Ambient Light Brightness of the sky (settings.background_intensity)
Metal Fuzz Multiplier on the roughness of rough mirrors
Glass IOR Index a standard 1.5 glass takes: every glass is scaled by slider / 1.5, so at the default each keeps its own refractive_index

The light and sky values are live: they are launch parameters, no scene rebuild is needed.

Procedural Patterns

Shown when the scene holds a golf ball (displaced sphere): number, radius and depth of the dimples.

Cloud / Smoke

Shown when the scene holds a volume material: albedo, density, phase asymmetry, noise scale and strength, edge, lumps, billow. Every change re-bakes the density field in a few milliseconds (Volumes).

Adaptive Sampling

Control Default Effect
Adaptive Sampling on After 32 samples, a pixel whose standard error falls below the threshold stops taking samples
Threshold 0.01 Standard error of the displayed value, in levels of 255 (about 2.5 levels)

Pixels lit only by rare bright paths are protected from freezing too early. Disable with --no-adaptive-sampling. The map of the samples spent per pixel is the Sample Heatmap of the Performance Monitoring section.

MIS / NEE

Enable MIS (master toggle for next event estimation and the MIS weights), NEE stride (beyond the first bounce, shadow rays on 1 of every N samples, 1 by default) and the Sobol sampler checkbox (uncheck for PCG). See Multiple Importance Sampling.

Camera Motion (OptiX)

Everything in this section applies only while the camera moves. The accumulation restarts on every move, so none of it changes the final image.

Control Default Effect
Max while moving 3/4 Highest fraction of the width and height rendered while moving; the frame is upscaled for display
Hold a target frame rate on, 60 fps The regulator lowers the render fraction first, then the samples per frame, until the frame rate holds, and raises them back when there is headroom
Min while moving 1/4 Floor of the render fraction (1/16 of the pixels)
Min samples 4 Floor of the samples per pixel per motion frame; Samples/Batch is the ceiling
Intermediate stages off When the camera stops, climb through 1/2 and 3/4 resolution before full, with a stage length, a fade and a motion cooldown
One sample per frame off Ignore the batch size while moving
Fast sampler (PCG) off PCG instead of Sobol' while moving
Limit bounce depth off Cap the bounces at 4 while moving (about 10 % faster, indirect light slightly darker)
Disable MIS / NEE while moving off Skip the shadow rays while moving (--motion-gate-mis)
Despeckle motion frames on, ratio 2 At display time, a pixel far brighter than its 8 neighbours is scaled down; the accumulation is untouched
AI denoiser (OptiX) off Run the OptiX neural denoiser on every motion frame, guided by the albedo and normal of the first hit. Display only. Fade out until (64 spp) keeps denoising the first still frames with a weight that fades to zero, so the image does not snap from smooth to noisy

The readout under the sliders shows the resolution fraction and the samples used by the last motion frame, and the denoiser time when it runs.

Appearance

Theme (light, classic, nord, dracula, gruvbox, catppuccin), logo, samples-per-second counter.

Controls & Help

The mouse and keyboard reference above.


Display pipeline

flowchart TD
    A["Path tracing kernel\n(CUDA or OptiX)"] -->|adds a batch of samples| B["float4 accumulation buffer\n(device memory)"]
    B -->|gamma kernel, upscale of motion frames| C["uint8 display buffer\n(device memory)"]
    C -->|async copy to pinned host memory| D["uint8 host buffer"]
    D -->|SDL_UpdateTexture| E["SDL texture"]
    E -->|SDL_RenderCopy| F["Window"]

Only three bytes per pixel cross from the device to the host each frame, about 6 MB at 1920×1080. The float accumulation buffer never leaves the GPU.


Sample screenshot

Interactive SDL2 window showing a path-traced scene with the Dear ImGui panel

The interactive window after a few seconds of stillness. The panel on the right shows the sample count, the throughput graph and the live sliders.