pfx

Got questions or doubts? Ping me on Discord

Path traced, then denoised

Stills, clips and the light bake on the GPU, with a denoiser of its own.

What it does

pfx render --recipe traces a recipe through pfx's offline path tracer. It stages the same parts, materials, sky, sun and lights the live renderer draws, so a traced render and a live shot of one recipe show one scene.

It traces with hardware ray queries wherever the device offers them (Vulkan, DX12, Metal on Apple Silicon) and with its own BVH elsewhere, samples with Cycles' tabulated Sobol sequence, and stops each pixel once its noise is under the threshold. Past four point and spot lights it picks one light per bounce through a light tree ported from Cycles.

Then pfx-denoise, Intel Open Image Denoise 2.5.1's RT filter ported to wgpu compute, takes the traced colour with its albedo and normal and gives back the clean colour. Traced adaptively with Sobol and then denoised, a final takes 16 to 64 samples a pixel and a draft 6 to 12.

  • Fewer samples, same noise

    On the neutral desk, Sobol reaches the noise PCG has at 256 samples a pixel with 101.4, and at 16 with 10.9.

  • Many lights, one pick

    Through the light tree, a street of 128 lamps costs 6% more than one of 4. Light by light it cost 105% more. With four lights, both paths write the same bytes.

  • Equal to OIDN

    On three neutral scenes the denoiser's output sits within 6.5e-5 of OIDN 2.5.1's own, 128.8 to 130.3 dB of PSNR in display space. The gap is float rounding.

  • Long renders survive

    pfx job runs a long clip or render detached under a name and carries on from its last finished frame after a pause, a stop, a crash or a reboot. With --checkpoint, a crash inside a long frame loses at most the time since its last save.

Measured

4K workshop still, adaptive to 64 samples
5,969 ms
Method: docs/trace.md
128 lights at 4K, from 9.4 s light by light
4.8 s
Method: docs/trace-lights.md
Denoiser at 4K, texture to texture
274 ms
Method: docs/denoise.md
Denoiser at 1080p
96 ms
Method: docs/denoise.md
Lowest PSNR against OIDN's own output
128.8 dB
Method: docs/denoise.md
Sobol samples for PCG's noise at 256
101.4
Method: docs/trace.md

How to use it

  1. Trace a recipe's camera to a picture. A .png comes out denoised; --spp caps the samples a pixel takes.

    pfx render --recipe samples/workshop.pitofx --camera hero --out hero.png
  2. --draft is a quick look: 12 samples a pixel at most and a looser noise threshold.

    pfx render --recipe samples/workshop.pitofx --camera hero --draft --out draft.png
  3. --trace path-traces a clip's frames, 64 samples a frame unless you say otherwise.

    pfx clip samples/workshop.pitofx --camera orbit --frames 120 --fps 30 --size 1280x800 --out traced --trace --spp 32
  4. A long one runs as a job under a name, which pfx job status, pause, stop and resume take.

    pfx job start night -- clip film.pitofx --camera main --timeline --size 3840x2160 --trace --spp 256 --out tmp/night

Build on pfx

pfx is open source under the AGPL-3.0: free for open-source projects, learning and hobby work. Read it, fork it, and send issues and pull requests on GitHub. Closed products and services built on pfx take a licence: free under $200k of yearly revenue plus funding, Indie and Pro above it.

© Catalin Ilinca, AGPL-3.0-only, with licences for closed products; releases up to 3.1.1 remain MIT. The PITO MD name, the pfx name and its logo are © Catalin Ilinca, all rights reserved.

Every picture and clip on this page is pfx's own, rendered or captured from its neutral scenes and licensed with its code (pfx's NOTICE.md); the pfx gui and game-editor clips were recorded by pfx from its v3.0.1 tag, the terminal clips with prec, the loops encoded with pito-codecs and the charts drawn with pito-compare from the numbers pfx v3.1.2 measures. Type: Exo 2 by NDISCOVER ( SIL Open Font License 1.1 ) and JetBrains Mono by JetBrains ( SIL Open Font License 1.1 ), from pfx's theme.