Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save BigRoy/415669c52de00a0b31e3969ed3fc2417 to your computer and use it in GitHub Desktop.
Save BigRoy/415669c52de00a0b31e3969ed3fc2417 to your computer and use it in GitHub Desktop.
Create Default Assembly Rig Setup as shown in How RISE VFX Reached New Creative Heights with USD in Maya talk
"""Create Default Assembly Rig Setup as shown in How RISE VFX Reached New Creative Heights with USD in Maya talk
See: https://youtu.be/8UIW-g1_heg?t=1902
"""
import pxr
import ufe
import pymel.core as pm
from mayaUsd import lib as mayaUsdLib
USD_SCHEMA = "UsdSchemaBase"
def create_default_assembly_rig_setup(assembly_rig_stage_shape, rig_grp, stage_driver_grp):
"""Create default assembly rig setup.
Args:
assembly_rig_stage_shape (pm.PyNode): Maya USD Proxy Shape to transform.
This should reference a USD file with a default prim defined.
rig_grp (pm.PyNode): Maya group that should act as the rig group
stage_driver_grp (pm.PyNode): Group in which the locator should be
placed that can be moved around.
"""
stage = mayaUsdLib.GetPrim(assembly_rig_stage_shape.name(long=True)).GetStage()
# create default control setup
grp = pm.group(name='root_001_TRN', empty=True)
pm.group(name="root_001_OFFSET")
root_grp = pm.group(name="root_001_GRP")
root_ctrl = pm.circle(c=(0, 0, 0), normal=(0, 1, 0), sweep=360, radius=10, degree=3, ut=0, tol=0.01, s=8, constructionHistory=False, name="root_001_CTRL")[0]
root_ctrl.overrideEnabled.set(True)
root_ctrl.overrideColor.set(17)
pm.parent(root_ctrl, grp)
# create default control setup
grp = pm.group(name='rootOffset_001_TRN', empty=True)
pm.group(name="rootOffset_001_OFFSET")
root_offset_grp = pm.group(name="rootOffset_001_GRP")
root_offset_ctrl = pm.circle(c=(0, 0, 0), normal=(0, 1, 0), sweep=360, radius=10, degree=3, ut=0, tol=0.01, s=8, constructionHistory=False, name="rootOffset_001_CTRL")[0]
pm.parent(root_offset_ctrl, grp)
pm.parent(root_offset_grp, grp)
# parent control setup under rig group
pm.parent(root_grp, rig_grp)
pm.select(clear=True)
# create the stage root driver as an locator and parent under driver group
locator = pm.spaceLocator('root_LOC')
pm.parent(locator, stage_driver_grp)
pm.parentConstraint(root_offset_ctrl, locator, maintainOffset=False)
pm.scaleConstraint(root_offset_ctrl, locator)
# get default prim path, and build selection string to stage default prim
root_prim_path = str(stage.GetDefaultPrim().GetPath())
stage_selection = "{}.{}".format(
assembly_rig_stage_shape.name(long=True), root_prim_path
)
# create connection to default/root prim
pm.select([stage_selection, locator])
def connect_maya_node_to_usd_prim(translate_op=True, rotate_op=True, scale_op=True):
"""Select two objects, one xformable prim in Maya USD Proxy and a maya native transform
Then running this function will connect the maya transform to the xformable prim as
driven transforms.
"""
global_selection = ufe.GlobalSelection.get()
ufe_object = global_selection.front()
if USD_SCHEMA not in ufe_object.ancestorNodeTypes():
return
stage_path, prim_path = mayaUsdLib.proxyAccessor.getDagAndPrimFromUfe(ufe_object)
stage_shape = pm.PyNode(stage_path)
stage = mayaUsdLib.GetPrim(stage_path).GetStage()
prim = stage.GetPrimAtPath(prim_path)
maya_node = pm.ls(selection=True)[0]
x_formable = pxr.UsdGeom.Xformable(prim)
if translate_op and not prim.GetAttribute("xformOp:translate").IsValid():
translate = x_formable.AddTranslateOp()
translate.Set(pxr.Gf.Vec3f([0, 0, 0]))
if rotate_op and not prim.GetAttribute("xformOp:rotateXYZ").IsValid():
rotate = x_formable.AddRotateXYZOp()
rotate.Set(pxr.Gf.Vec3f([0, 0, 0]))
if scale_op and not prim.GetAttribute("xformOp:scale").IsValid():
scale = x_formable.AddScaleOp()
scale.Set(pxr.Gf.Vec3f([1, 1, 1]))
reset_set = ["!resetXformStack!"]
if translate_op:
reset_set.append("xformOp:translate")
if rotate_op:
reset_set.append("xformOp:rotateXYZ")
if scale_op:
reset_set.append("xformOp:scale")
prim.GetAttribute("xformOpOrder").Set(reset_set)
for src_attr, target_attr_name in {
maya_node.translate: "xformOp:translate",
maya_node.rotate: "xformOp:rotateXYZ",
maya_node.scale: "xformOp:scale",
}.items():
accessor = mayaUsdLib.proxyAccessor.getOrCreateAccessPlug(ufeObject=ufe_object, usdAttrName=target_attr_name)
accessor_attr = stage_shape.attr(accessor)
pm.connectAttr(src_attr, accessor_attr, force=True)
@BigRoy
Copy link
Author

BigRoy commented Oct 23, 2024

Just connect a maya native object to control transform of an object inside Maya USD Proxy shape, without pymel:

"""Create Default Assembly Rig Setup as shown in How RISE VFX Reached New Creative Heights with USD in Maya talk

See: https://youtu.be/8UIW-g1_heg?t=1902
"""
import pxr
import ufe
from maya import cmds
from mayaUsd import lib as mayaUsdLib
from mayaUsd.lib import proxyAccessor as pa

USD_SCHEMA = "UsdSchemaBase"


def connect_maya_node_to_usd_prim(
        maya_node,
        translate_op=True,
        rotate_op=True,
        scale_op=True):
    """Select two objects, one xformable prim in Maya USD Proxy and a maya native transform

    Then running this function will connect the maya transform to the xformable prim as
    driven transforms.
    """
    global_selection = ufe.GlobalSelection.get()

    ufe_object = global_selection.front()
    if USD_SCHEMA not in ufe_object.ancestorNodeTypes():
        return
    stage_path, prim_path = mayaUsdLib.proxyAccessor.getDagAndPrimFromUfe(
        ufe_object)
    stage = mayaUsdLib.GetPrim(stage_path).GetStage()
    prim = stage.GetPrimAtPath(prim_path)

    x_formable = pxr.UsdGeom.Xformable(prim)
    if translate_op and not prim.GetAttribute("xformOp:translate").IsValid():
        translate = x_formable.AddTranslateOp()
        translate.Set(pxr.Gf.Vec3f([0, 0, 0]))
    if rotate_op and not prim.GetAttribute("xformOp:rotateXYZ").IsValid():
        rotate = x_formable.AddRotateXYZOp()
        rotate.Set(pxr.Gf.Vec3f([0, 0, 0]))
    if scale_op and not prim.GetAttribute("xformOp:scale").IsValid():
        scale = x_formable.AddScaleOp()
        scale.Set(pxr.Gf.Vec3f([1, 1, 1]))

    reset_set = ["!resetXformStack!"]
    if translate_op:
        reset_set.append("xformOp:translate")
    if rotate_op:
        reset_set.append("xformOp:rotateXYZ")
    if scale_op:
        reset_set.append("xformOp:scale")
    prim.GetAttribute("xformOpOrder").Set(reset_set)

    for src_attr, target_attr_name in {
        f"{maya_node}.translate": "xformOp:translate",
        f"{maya_node}.rotate": "xformOp:rotateXYZ",
        f"{maya_node}.scale": "xformOp:scale",
    }.items():
        accessor = pa.getOrCreateAccessPlug(ufeObject=ufe_object,
                                            usdAttrName=target_attr_name)
        accessor_attr = f"{stage_path}.{accessor}"
        cmds.connectAttr(src_attr, accessor_attr, force=True)



node = cmds.ls(selection=True)[0]
connect_maya_node_to_usd_prim(node)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment