Get the World Space Transforms for a Prim#

If you need to get the transformation of a prim in world space (i.e. taking into account the transformations of any ancestor prims), you can use a convenience function in Kit, omni.usd.get_world_transform_matrix(). Alternatively, you can use UsdGeom.Xformable.ComputeLocalToWorldTransform() or UsdGeom.XformCache.GetLocalToWorldTransform() to get the world transformation matrix. Once you have the matrix, decompose it into individual xform components.

import typing
from pxr import Usd, UsdGeom, Gf

def get_world_transform_xform(prim: Usd.Prim) -> typing.Tuple[Gf.Vec3d, Gf.Rotation, Gf.Vec3d]:
    """
    Get the local transformation of a prim using Xformable.
    See https://openusd.org/release/api/class_usd_geom_xformable.html
    Args:
        prim: The prim to calculate the world transformation.
    Returns:
        A tuple of:
        - Translation vector.
        - Rotation quaternion, i.e. 3d vector plus angle.
        - Scale vector.
    """
    xform = UsdGeom.Xformable(prim)
    time = Usd.TimeCode.Default() # The time at which we compute the bounding box
    world_transform: Gf.Matrix4d = xform.ComputeLocalToWorldTransform(time)
    translation: Gf.Vec3d = world_transform.ExtractTranslation()
    rotation: Gf.Rotation = world_transform.ExtractRotation()
    scale: Gf.Vec3d = Gf.Vec3d(*(v.GetLength() for v in world_transform.ExtractRotationMatrix()))
    return translation, rotation, scale

#############
# Full Usage
#############

from pxr import Sdf

# Create an in-memory Stage with /World Xform prim as the default prim
stage: Usd.Stage = Usd.Stage.CreateInMemory()
default_prim: Usd.Prim = UsdGeom.Xform.Define(stage, Sdf.Path("/World")).GetPrim()
stage.SetDefaultPrim(default_prim)

xform: Usd.Prim = UsdGeom.Xform.Define(stage, default_prim.GetPath().AppendPath("Xform"))
xform.AddTranslateOp().Set(value=(100,10,0))
xform.AddRotateXYZOp().Set(value=(0,50,0))
xform.AddScaleOp().Set(value=(5,5,5))

cube = UsdGeom.Cube.Define(stage, xform.GetPath().AppendPath("Cube"))
cube.AddTranslateOp().Set(value=(4,0,0))
cube.AddRotateXYZOp().Set(value=(100,0,0))
cube.AddScaleOp().Set(value=(2,2,2))

transform = get_world_transform_xform(cube)

usda = stage.GetRootLayer().ExportToString()
print(usda)

Alternatively, if you need to compute the world transform for multiple prims on a stage, UsdGeom.XformCache is more efficient.

import typing
from pxr import Usd, UsdGeom, Gf

def get_world_transform_cache(cache: UsdGeom.XformCache, prim: Usd.Prim) -> typing.Tuple[Gf.Vec3d, Gf.Rotation, Gf.Vec3d]:
    """
    Get the local transformation of a prim using UsdGeom.XformCache.
    See: https://openusd.org/release/api/class_usd_geom_xform_cache.html
    Args:
        cache: A cache, created for example as `UsdGeom.XformCache()`
        prim: The prim to calculate the world transformation.
    Returns:
        A tuple of:
        - Translation vector.
        - Rotation quaternion, i.e. 3d vector plus angle.
        - Scale vector.
    """
    world_transform: Gf.Matrix4d = cache.GetLocalToWorldTransform(prim)
    translation: Gf.Vec3d = world_transform.ExtractTranslation()
    rotation: Gf.Rotation = world_transform.ExtractRotation()
    scale: Gf.Vec3d = Gf.Vec3d(*(v.GetLength() for v in world_transform.ExtractRotationMatrix()))
    return translation, rotation, scale

#############
# Full Usage
#############

from pxr import Sdf

# Create an in-memory Stage with /World Xform prim as the default prim
stage: Usd.Stage = Usd.Stage.CreateInMemory()
default_prim: Usd.Prim = UsdGeom.Xform.Define(stage, Sdf.Path("/World")).GetPrim()
stage.SetDefaultPrim(default_prim)

xform: Usd.Prim = UsdGeom.Xform.Define(stage, default_prim.GetPath().AppendPath("Xform"))
xform.AddTranslateOp().Set(value=(100,10,0))
xform.AddRotateXYZOp().Set(value=(0,50,0))
xform.AddScaleOp().Set(value=(5,5,5))

cube = UsdGeom.Cube.Define(stage, xform.GetPath().AppendPath("Cube"))
cube.AddTranslateOp().Set(value=(4,0,0))
cube.AddRotateXYZOp().Set(value=(100,0,0))
cube.AddScaleOp().Set(value=(2,2,2))

time = Usd.TimeCode.Default() # The time at which we compute the bounding box
cache = UsdGeom.XformCache(time)
transform = get_world_transform_cache(cache, cube.GetPrim())

usda = stage.GetRootLayer().ExportToString()
print(usda)
import omni.usd
from pxr import Usd, Gf
import typing

def get_world_transform_xform(prim: Usd.Prim) -> typing.Tuple[Gf.Vec3d, Gf.Rotation, Gf.Vec3d]:
    """
    Get the local transformation of a prim using omni.usd.get_world_transform_matrix().
    See https://docs.omniverse.nvidia.com/kit/docs/omni.usd/latest/omni.usd/omni.usd.get_world_transform_matrix.html
    Args:
        prim: The prim to calculate the world transformation.
    Returns:
        A tuple of:
        - Translation vector.
        - Rotation quaternion, i.e. 3d vector plus angle.
        - Scale vector.
    """
    world_transform: Gf.Matrix4d = omni.usd.get_world_transform_matrix(prim)
    translation: Gf.Vec3d = world_transform.ExtractTranslation()
    rotation: Gf.Rotation = world_transform.ExtractRotation()
    scale: Gf.Vec3d = Gf.Vec3d(*(v.GetLength() for v in world_transform.ExtractRotationMatrix()))
    return translation, rotation, scale
    
#############
# Full Usage
#############

import omni.kit.commands

# Create an Xform with a Cube Prim as it's Child
omni.kit.commands.execute('CreatePrimWithDefaultXform',
	prim_type='Xform',
	attributes={},
	select_new_prim=True)

omni.kit.commands.execute('TransformMultiPrimsSRTCpp',
	count=1,
	paths=['/World/Xform'],
	new_translations=[100, 0, 0],
	new_rotation_eulers=[0, 50 ,0],
	new_rotation_orders=[0, 1, 2],
	new_scales=[5, 5, 5],
	old_translations=[0.0, 0.0, 0.0],
	old_rotation_eulers=[0.0, 0.0, 0.0],
	old_rotation_orders=[0, 1, 2],
	old_scales=[1.0, 1.0, 1.0],
	usd_context_name='',
	time_code=0.0)

omni.kit.commands.execute('CreateMeshPrimWithDefaultXform',
	prim_type='Cube',
	prim_path='/World/Xform/Cube',
	select_new_prim=True,
	prepend_default_prim=False)

omni.kit.commands.execute('TransformMultiPrimsSRTCpp',
	count=1,
	paths=['/World/Xform/Cube'],
	new_translations=[4, 0, 0],
	new_rotation_eulers=[100, 0 ,0],
	new_rotation_orders=[0, 1, 2],
	new_scales=[2, 2, 2],
	old_translations=[0.0, 0.0, 0.0],
	old_rotation_eulers=[0.0, 0.0, 0.0],
	old_rotation_orders=[0, 1, 2],
	old_scales=[1.0, 1.0, 1.0],
	usd_context_name='',
	time_code=0.0)

stage = omni.usd.get_context().get_stage()
cube_prim = stage.GetPrimAtPath("/World/Xform/Cube")
transform = get_world_transform_xform(cube_prim)

This is an example USDA result from creating a Xform with a Cube as a child.

[py stdout]: #usda 1.0
(
    defaultPrim = "World"
)

def Xform "World"
{
    def Xform "Xform"
    {
        float3 xformOp:rotateXYZ = (0, 50, 0)
        float3 xformOp:scale = (5, 5, 5)
        double3 xformOp:translate = (100, 10, 0)
        uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"]

        def Cube "Cube"
        {
            float3 xformOp:rotateXYZ = (100, 0, 0)
            float3 xformOp:scale = (2, 2, 2)
            double3 xformOp:translate = (4, 0, 0)
            uniform token[] xformOpOrder = ["xformOp:translate", "xformOp:rotateXYZ", "xformOp:scale"]
        }
    }
}