Cameras#

Camera sensors in ovrtx simulate physically accurate imaging and produce rendered outputs through RenderVar prims attached to a RenderProduct.

For how to configure RenderProducts and RenderVars, refer to Sensor Configuration.

Example USD#

A RenderProduct that outputs both LdrColor and HdrColor from a camera:

def "Render" {
    def RenderProduct "Camera" {
        int2 resolution = (1920, 1080)
        rel camera = </World/Camera>
        rel orderedVars = [<LdrColor>, <HdrColor>]

        def RenderVar "LdrColor" {
            string sourceName = "LdrColor"
        }

        def RenderVar "HdrColor" {
            string sourceName = "HdrColor"
        }
    }
}
render_scope = stage.DefinePrim("/Render")
camera_product = UsdRender.Product.Define(stage, "/Render/Camera")
camera_product.GetResolutionAttr().Set(Gf.Vec2i(1920, 1080))
camera_product.GetCameraRel().SetTargets(["/World/Camera"])

ldr_var = UsdRender.Var.Define(stage, "/Render/Camera/LdrColor")
ldr_var.GetSourceNameAttr().Set("LdrColor")

hdr_var = UsdRender.Var.Define(stage, "/Render/Camera/HdrColor")
hdr_var.GetSourceNameAttr().Set("HdrColor")

camera_product.GetOrderedVarsRel().SetTargets([
    "/Render/Camera/LdrColor",
    "/Render/Camera/HdrColor",
])

Accessing Outputs in Code#

After stepping the renderer with a RenderProduct path, the outputs are available by full RenderVar prim path:

products = renderer.step(
    render_products={"/Render/Camera"},
    delta_time=1.0 / 60,
    ordinal=ordinal,
)

for frame in products["/Render/Camera"].frames:
    # RenderVar outputs are keyed by their full prim paths.
    ldr_var = frame.render_vars["/Render/Camera/LdrColor"]
    hdr_var = frame.render_vars["/Render/Camera/HdrColor"]

    # LdrColor: uint8 sRGB image
    var = ldr_var.map(device=ovrtx.Device.CPU)
    ldr_pixels = np.from_dlpack(var)  # shape: (H, W, 4), dtype: uint8
    assert ldr_pixels.shape == (1080, 1920, 4)
    assert ldr_pixels.dtype == np.uint8
    Image.fromarray(ldr_pixels).save(output_dir / "test_camera_sensors.LdrColor.png")

    # HdrColor: float16 linear image
    var = hdr_var.map(device=ovrtx.Device.CPU)
    hdr_pixels = np.from_dlpack(var)  # shape: (H, W, 4), dtype: float16
    assert hdr_pixels.shape == (1080, 1920, 4)
    assert hdr_pixels.dtype == np.float16
ovrtx_render_var_output_handle_t ldr_handle = OVRTX_INVALID_HANDLE;
ovrtx_render_var_output_handle_t hdr_handle = OVRTX_INVALID_HANDLE;

// This step requested one RenderProduct. Select its first output frame,
// then find RenderVars by their full prim paths.
ovrtx_render_product_frame_output_t const& frame = outputs.outputs[0].output_frames[0];
for (size_t var_index = 0; var_index < frame.render_var_count; ++var_index) {
    ovrtx_render_product_render_var_output_t const& var = frame.output_render_vars[var_index];
    if (!var.render_var_path.ptr) {
        continue;
    }

    std::string_view const path(var.render_var_path.ptr, var.render_var_path.length);
    if (path == "/Render/Camera/LdrColor") {
        ldr_handle = var.output_handle;
    } else if (path == "/Render/Camera/HdrColor") {
        hdr_handle = var.output_handle;
    }
}
ASSERT_NE(ldr_handle, OVRTX_INVALID_HANDLE);
ASSERT_NE(hdr_handle, OVRTX_INVALID_HANDLE);

// Map LdrColor to CPU
ovrtx_map_output_description_t map_desc = {};
map_desc.device_type = OVRTX_MAP_DEVICE_TYPE_CPU;

ovrtx_render_var_output_t ldr_output = {};
result = ovrtx_map_render_var_output(renderer_, ldr_handle, &map_desc,
                                     ovrtx_timeout_infinite, &ldr_output);
ASSERT_API_SUCCESS(result.status);

DLTensor const& ldr_tensor = *ldr_output.tensors[0].dl;
// ldr_tensor.data: RGBA uint8 pixels
// ldr_tensor.shape[0]: height, ldr_tensor.shape[1]: width

save_ldr_png("CameraSensors.LdrColor",
             ldr_tensor.data,
             static_cast<int>(ldr_tensor.shape[1]),
             static_cast<int>(ldr_tensor.shape[0]));

ovrtx_cuda_sync_t no_sync = {};
ovrtx_unmap_render_var_output(renderer_, ldr_output.map_handle, no_sync);