Python: Sliced Rendering#
Renders one 1024×1024 RenderProduct as four successive 512×512
dataWindowNDC crops using PathTracing at 64 samples per pixel. The example
uses zero client warmup frames, waits for each crop to converge, and stitches
the LdrColor outputs from the TL, TR, BL, and BR tiles into one RGBA image.
No quality attribute is authored; streaming wait uses the renderer defaults.
“Render one image as four successive dataWindowNDC crops without client warmup frames, and stitch the captured TL, TR, BL, and BR tiles into a full-resolution image.”
The tested crop-update and stitching pattern is:
def capture(ordinal):
"""Wait for the current crop to converge before copying its pixels."""
# A crop change clears accumulation; capture only the completed image.
while True:
products = renderer.step(
render_products={"/Render/Camera"},
delta_time=1.0 / 60,
ordinal=ordinal,
)
frame = products["/Render/Camera"].frames[-1]
if frame.converged:
break
var = frame.render_vars[LDR_COLOR_PATH].map(device=ovrtx.Device.CPU)
view = np.from_dlpack(var)
pixels = view.copy()
del view
var.unmap()
del var, frame, products
return pixels
full_frame = capture(ordinal=1)
assert full_frame.shape == (512, 512, 4)
assert full_frame.dtype == np.uint8
slices = (
# LdrColor rows follow dataWindowNDC's bottom-up Y order.
("TL", (0.0, 0.5, 0.5, 1.0), (256, 0)),
("TR", (0.5, 0.5, 1.0, 1.0), (256, 256)),
("BL", (0.0, 0.0, 0.5, 0.5), (0, 0)),
("BR", (0.5, 0.0, 1.0, 0.5), (0, 256)),
)
stitched = np.empty((512, 512, 4), dtype=np.uint8)
with ovstage.PathDictionary(stage) as paths:
path_list = paths.create_path_list_from_strings(["/Render/Camera"])
try:
with stage.query_from_path_list(path_list) as query:
attribute = paths.intern_token("dataWindowNDC")
crop_dtype = ovstage.numpy_to_dldatatype(np.dtype(np.float32), lanes=4)
for ordinal, (label, crop_ndc, (dst_y, dst_x)) in enumerate(slices, start=2):
crop_values = np.asarray([crop_ndc], dtype=np.float32)
crop_tensor = ovstage.make_dltensor(
crop_values,
dtype=crop_dtype,
shape=[1],
ndim=1,
)
stage.write_attribute(
query,
attribute,
ordinal=ordinal,
tensors=crop_tensor,
is_array=False,
).wait()
stage.advance_write_floor(ordinal, ovstage.Scope.ALL).wait()
pixels = capture(ordinal)
assert pixels.shape == (256, 256, 4)
assert pixels.dtype == np.uint8
reference_tile = full_frame[dst_y : dst_y + 256, dst_x : dst_x + 256, :3]
tile_error = np.abs(
pixels[:, :, :3].astype(np.int16) - reference_tile.astype(np.int16)
).mean()
assert tile_error < 8.0, f"{label} tile differs from its full-frame region: MAE={tile_error}"
stitched[dst_y : dst_y + 256, dst_x : dst_x + 256] = pixels
finally:
paths.destroy_path_list(path_list)
Image.fromarray(full_frame).save(output_dir / "base.Camera.LdrColor.full.png")
Image.fromarray(stitched).save(output_dir / "base.Camera.LdrColor.sliced.png")
Prerequisites#
Python 3.10-3.13
An NVIDIA RTX-capable GPU and a supported driver
Running#
cd examples/python/sliced-rendering
uv run main.py
Pass --png to save _output/render.png instead of displaying the image.
Note
This example uses Path Tracing. When using this technique with Real-Time
Path Tracing, changing dataWindowNDC clears temporal history. Render
additional warm-up frames for each crop after the first before using its
result.