Time-gated rendering (offline)¶
This tutorial renders a time-gated image of the Cornell box offline with
TimeGatedPathTracerInline: only light whose total path length (laser -> scene -> camera) falls
inside a gate reaches the image. The scene is the Cornell box without its area light, so a laser is
the only light: download scene-v4-nolight.pbrt
and save it as cornell-box/scene-v4-nolight.pbrt next to the script. The other tutorials use the
same file. (The Cornell box is by Benedikt Bitterli, released under
CC0.)
1. Load the scene¶
import falcorcomp as falcor
testbed = falcor.Testbed(create_window=False)
testbed.load_scene("cornell-box/scene-v4-nolight.pbrt")
testbed.resize_frame_buffer(512, 512)
testbed.scene.camera.aspectRatio = 1.0
testbed.clock.pause()
2. Build the render graph¶
VBufferRT finds the primary hits and LaserLight places the laser; the execution edge
add_edge("Laser", "Tracer") (pass names only) makes it run before the tracer. The tracer keeps paths
whose length lies in a box gate of width timeGateWindow centered at timeMin (equal to
timeMax for a single gate). AccumulatePass averages the frames and ToneMapper makes a
displayable copy.
graph = testbed.create_render_graph("TimeGated")
graph.create_pass("VBuffer", "VBufferRT", {"samplePattern": "Center", "sampleCount": 1})
graph.create_pass("Laser", "LaserLight", {
"laserPosition": [0.0, 1.7, 6.8], "laserDirection": [0.0, 0.0, -1.0],
"laserPower": [170.0, 120.0, 40.0], "laserAngle": 0.0,
})
graph.create_pass("Tracer", "TimeGatedPathTracerInline", {
"samplesPerPixel": 16, "maxBounces": 6, "computeDirect": False,
"timeGateMode": "box", "timeGateWindow": 0.1, "timeMin": 17.337, "timeMax": 17.337,
})
graph.create_pass("Accumulate", "AccumulatePass", {"precisionMode": "SingleCompensated"})
graph.create_pass("ToneMapper", "ToneMapper", {"autoExposure": False})
graph.add_edge("VBuffer.vbuffer", "Tracer.vbuffer")
graph.add_edge("VBuffer.viewW", "Tracer.viewW")
graph.add_edge("Laser", "Tracer")
graph.add_edge("Tracer.color", "Accumulate.input")
graph.add_edge("Accumulate.output", "ToneMapper.src")
graph.mark_output("Accumulate.output") # output 0: linear radiance
graph.mark_output("ToneMapper.dst") # output 1: tone mapped
testbed.render_graph = graph
3. Render¶
Each frame traces samplesPerPixel paths per pixel and adds them to the accumulated image.
for _ in range(256): # 256 frames x 16 spp = 4096 spp
testbed.frame()
4. Save the image¶
Output 0 is the linear radiance (EXR); output 1 is the tone-mapped image (PNG).
testbed.capture_output("time_gated.exr", 0)
testbed.capture_output("time_gated.png", 1)
The full script: time_gated_offline.py.