Attribute Bindings#

Attribute bindings are persistent descriptors for writing the same attribute on the same set of prims repeatedly. They are useful for animation loops and other hot paths where rebuilding the prim list, attribute name, dtype, and semantic on every write would add overhead.

Use regular writes from Attribute Reads and Writes for one-shot edits. Use Attribute Mapping when the hot path needs zero-copy writes into ovrtx-owned buffers.

Create and Write#

binding = renderer.bind_attribute(
    prim_paths=["/World/Plane"],
    attribute_name="omni:xform",
    dtype="float64",
    shape=(4, 4),
    prim_mode=ovrtx.PrimMode.MUST_EXIST,
    flags=ovrtx.BindingFlag.OPTIMIZE,
)
binding.write(matrix)
binding.unbind()
ovrtx_attribute_binding_handle_t binding_handle = 0;
ovrtx_enqueue_result_t eq =
    ovrtx_create_attribute_binding(renderer_, &binding_desc.binding_desc, &binding_handle);
ASSERT_API_SUCCESS(eq.status);
docs_wait_no_errors(renderer_, eq.op_index);
ovrtx_binding_desc_or_handle_t binding_ref{};
binding_ref.binding_handle = binding_handle;

double matrix[16];
make_xform(14.0, matrix);
size_t count = 1;
DLTensor tensor = ovrtx_make_write_cpu_tensor(matrix, &count, mat_type);
ovrtx_input_buffer_t buffer{};
buffer.tensors = &tensor;
buffer.tensor_count = 1;

eq = ovrtx_write_attribute(renderer_, &binding_ref, &buffer, OVRTX_DATA_ACCESS_SYNC);
ASSERT_API_SUCCESS(eq.status);
docs_wait_no_errors(renderer_, eq.op_index);
eq = ovrtx_destroy_attribute_binding(renderer_, binding_handle);
ASSERT_API_SUCCESS(eq.status);
docs_wait_no_errors(renderer_, eq.op_index);

Async Creation and Writes#

Python exposes async binding creation and async writes for non-blocking update pipelines.

op = renderer.bind_attribute_async(
    ["/World/Plane"], "omni:xform", dtype="float64", shape=(4, 4)
)
binding = op.wait()
assert binding is not None
write_op = binding.write_async(matrix)
assert write_op.wait() is True

Array Attributes#

Use array bindings for variable-length USD array attributes such as mesh points. Array writes take one tensor per prim.

binding = renderer.bind_array_attribute(
    ["/World/Plane"], "points", dtype="float32", shape=(3,)
)
binding.write([points])

Mapping Through a Binding#

Persistent bindings can also be mapped, which avoids recreating the descriptor before each map/unmap cycle.

binding = renderer.bind_attribute(["/World/Plane"], "omni:xform", dtype="float64", shape=(4, 4))
with binding.map(device=ovrtx.Device.CPU) as mapping:
    matrices = np.from_dlpack(mapping.tensor).reshape(1, 4, 4)
    matrices[0, 3, 0] = 8.0

Lifetime Rules#

  • Explicitly unbind or destroy bindings when the hot path is done.

  • A binding fixes the prim list, attribute name, dtype, shape, and semantic.

  • In C, keep strings and descriptor arrays alive until binding creation has completed.

  • OVRTX_BINDING_FLAG_OPTIMIZE is intended for frequent high-volume writes. In Python, the equivalent is BindingFlag.OPTIMIZE.