Writing Transforms#
Transforms are ordinary runtime stage attributes with a transform semantic.
The canonical transform attribute is omni:xform. The legacy
omni:fabric:localMatrix name is also accepted, but new code should prefer
omni:xform.
ovrtx uses the USD row-vector matrix convention: translation is stored in the
last row of a 4x4 matrix, at matrix[3][0..2] or flat indices 12..14.
4x4 Matrix Writes#
Python uses NumPy-style tensor shapes. A batch of N 4x4 transforms has
shape (N, 4, 4) and dtype float64.
# A per-prim 4x4 transform is a 3-D ndarray with shape=(N, 4, 4).
# Translate /World/Camera to (10, 20, 30) using USD row-vector convention
# (translation lives in matrix[3][0..2]).
xform = np.eye(4, dtype=np.float64)
xform[3, 0:3] = [10.0, 20.0, 30.0]
transforms = xform.reshape(1, 4, 4) # shape=(1, 4, 4)
renderer.write_attribute(
prim_paths=["/World/Camera"],
attribute_name="omni:xform",
tensor=transforms,
semantic=ovrtx.Semantic.XFORM_MAT4x4,
)
tensor = renderer.read_attribute(
attribute_name="omni:xform",
prim_paths=["/World/Camera"],
)
values = np.from_dlpack(tensor).reshape(1, 4, 4)
assert values.shape == (1, 4, 4)
C convenience helpers in <ovrtx/ovrtx_attributes.h> hide the
DLTensor descriptor boilerplate for common transform layouts.
ovx_string_t prim = ovx_str("/World/Plane");
ovrtx_xform_matrix44d_t matrix{};
matrix.v[0] = 1.0;
matrix.v[5] = 1.0;
matrix.v[10] = 1.0;
matrix.v[15] = 1.0;
matrix.v[12] = 5.0;
ovrtx_enqueue_result_t eq = ovrtx_set_xform_mat(renderer_, &prim, 1, &matrix);
ASSERT_API_SUCCESS(eq.status);
docs_wait_no_errors(renderer_, eq.op_index);
C Transform Helpers#
The C API also provides compact helpers for position/rotation/scale layouts and
for authoring omni:resetXformStack.
ovx_string_t prim = ovx_str("/World/Plane");
ovrtx_xform_pos3d_rot4f_scale3f_t transform{};
transform.position[0] = 6.0;
transform.rot_quat_xyzw[0] = 1.0f; // 180 degrees around X.
transform.scale[0] = 2.0f;
transform.scale[1] = 3.0f;
transform.scale[2] = 4.0f;
ovrtx_enqueue_result_t eq = ovrtx_set_xform_pos_rot_scale(renderer_, &prim, 1, &transform);
ASSERT_API_SUCCESS(eq.status);
docs_wait_no_errors(renderer_, eq.op_index);
ovx_string_t prim = ovx_str("/World/Plane");
ovrtx_xform_pos3d_rot3x3f_t transform{};
transform.position[0] = 7.0;
transform.rot_matrix[0] = -1.0f;
transform.rot_matrix[4] = -1.0f;
transform.rot_matrix[8] = 1.0f;
ovrtx_enqueue_result_t eq = ovrtx_set_xform_pos_rot3x3(renderer_, &prim, 1, &transform);
ASSERT_API_SUCCESS(eq.status);
docs_wait_no_errors(renderer_, eq.op_index);
ovx_string_t prim = ovx_str("/World/Plane");
bool reset_stack = true;
ovrtx_enqueue_result_t eq = ovrtx_set_reset_xform_stack(renderer_, &prim, 1, &reset_stack);
ASSERT_API_SUCCESS(eq.status);
docs_wait_no_errors(renderer_, eq.op_index);
Repeated Updates#
For per-frame transform animation, avoid rebuilding descriptors on every update:
Use Attribute Bindings when the application already owns the transform tensors and copying into ovrtx is acceptable.
Use Attribute Mapping when CUDA or CPU code should write directly into ovrtx-owned attribute buffers.
Notes#
Transform matrices are
float64.Semantics are write-side conversion hints. Attribute reads use the raw storage layout.
In C, a 4x4 matrix attribute is represented as
shape=[N]withDLDataType{kDLFloat, 64, 16}.In Python, a 4x4 matrix attribute is represented as
shape=(N, 4, 4).