diff --git a/lib/mayaUsd/resources/scripts/mayaUsdAddMayaReference.mel b/lib/mayaUsd/resources/scripts/mayaUsdAddMayaReference.mel index cedc09fe04..53dbf12d81 100644 --- a/lib/mayaUsd/resources/scripts/mayaUsdAddMayaReference.mel +++ b/lib/mayaUsd/resources/scripts/mayaUsdAddMayaReference.mel @@ -95,6 +95,7 @@ proc fileOptionsTabPage(string $tabLayout) string $action = "Reference"; pushOptionsUITemplate(); + string $lbl; setParent $tabLayout; // Need to keep 'optionsBoxForm' as translator plugins reference this @@ -135,8 +136,19 @@ proc fileOptionsTabPage(string $tabLayout) textFieldGrp -label `getMayaUsdLibString("kMayaRefPrimName")` -cc "usdMayaRef_changeGroupPrimNameText \"#1\"" usdMayaReferenceGroupPrimName; - textFieldGrp -label `getMayaUsdLibString("kMayaRefPrimType")` usdMayaReferenceGroupPrimType; - textFieldGrp -label `getMayaUsdLibString("kMayaRefPrimKind")` usdMayaReferenceGroupPrimKind; + optionMenuGrp -label `getMayaUsdLibString("kMayaRefPrimType")` usdMayaReferenceGroupPrimType; + menuItem -label "Xform"; + menuItem -label "Scope"; + optionMenuGrp -label `getMayaUsdLibString("kMayaRefPrimKind")` usdMayaReferenceGroupPrimKind; + menuItem -label ""; // empty + $lbl = python("from pxr import Kind; Kind.Tokens.group"); + menuItem -label $lbl; + $lbl = python("from pxr import Kind; Kind.Tokens.assembly"); + menuItem -label $lbl; + $lbl = python("from pxr import Kind; Kind.Tokens.component"); + menuItem -label $lbl; + $lbl = python("from pxr import Kind; Kind.Tokens.subcomponent"); + menuItem -label $lbl; checkBoxGrp -numberOfCheckBoxes 1 -label "" -label1 `getMayaUsdLibString("kMayaRefDefineInVariant")` @@ -174,7 +186,7 @@ proc fileOptionsTabPage(string $tabLayout) usdMayaReferenceEditAsMayaDatGrp; setParent $topForm; - string $lbl = getMayaUsdLibString("kMayaRefOptions"); + $lbl = getMayaUsdLibString("kMayaRefOptions"); string $mayaRefForm = `frameLayout -label $lbl`; setParent $mayaRefForm; @@ -371,6 +383,19 @@ proc setOptionVars(int $forceFactorySettings) int $mjv = `about -majorVersion`; if ($mjv <= 2022) { + if ($forceFactorySettings || !`optionVar -exists usdMayaReferenceGroup`) { + optionVar -intValue usdMayaReferenceGroup false; + } + if ($forceFactorySettings || !`optionVar -exists usdMayaReferenceGroupPrimName`) { + optionVar -stringValue usdMayaReferenceGroupPrimName ""; + } + if ($forceFactorySettings || !`optionVar -exists usdMayaReferenceGroupType`) { + optionVar -stringValue usdMayaReferenceGroupPrimType "Xform"; + } + if ($forceFactorySettings || !`optionVar -exists usdMayaReferenceGroupKind`) { + string $def = python("from pxr import Kind; Kind.Tokens.group"); + optionVar -stringValue usdMayaReferenceGroupPrimKind $def; + } string $createNew = getMayaUsdLibString("kMayaRefCreateNew"); if ($forceFactorySettings || !`optionVar -exists usdMayaReferenceDefineInVariant`) { optionVar -intValue usdMayaReferenceDefineInVariant false; @@ -450,10 +475,15 @@ proc setOptionVars(int $forceFactorySettings) else { string $createNew = getMayaUsdLibString("kMayaRefCreateNew"); + string $defGroupKind = python("from pxr import Kind; Kind.Tokens.group"); string $defVariantSetName = defaultVariantSetName(); string $defVariantName = defaultVariantName(); optionVar -init $forceFactorySettings -category "MayaUsd" + -iv usdMayaReferenceGroup false + -sv usdMayaReferenceGroupPrimName "" + -sv usdMayaReferenceGroupPrimType "Xform" + -sv usdMayaReferenceGroupPrimKind $defGroupKind -iv usdMayaReferenceDefineInVariant false -sv usdMayaReferenceVariantSetNameOption $createNew -sv usdMayaReferenceVariantSetNameText $defVariantSetName @@ -600,8 +630,19 @@ proc fileOptionsSetup(string $parent, int $forceFactorySettings, string $chosenF -text $mayaRefPrimName usdMayaReferencePrimName; - // Group is initially unchecked (todo: add optionvar control). - usdMayaRef_changeGroupOption(0); + // Setup the "Group" section. + int $groupVar = `optionVar -q usdMayaReferenceGroup`; + checkBoxGrp -edit -v1 $groupVar usdMayaReferenceGroupGrp; + + textFieldGrp -edit + -text `optionVar -q usdMayaReferenceGroupPrimName` + usdMayaReferenceGroupPrimName; + optionMenuGrp -edit + -value `optionVar -q usdMayaReferenceGroupPrimType` + usdMayaReferenceGroupPrimType; + optionMenuGrp -edit + -value `optionVar -q usdMayaReferenceGroupPrimKind` + usdMayaReferenceGroupPrimKind; // Setup the "Define in Variant" section. int $defineInVar = `optionVar -q usdMayaReferenceDefineInVariant`; @@ -609,6 +650,10 @@ proc fileOptionsSetup(string $parent, int $forceFactorySettings, string $chosenF usdMayaRef_changeDefineInVariantOption($defineInVar); usdMayaRef_setupDefineInVariant(); + // We do this "after" the define in variant stuff since enabling group + // changes parts of the "define in variant" section. + usdMayaRef_changeGroupOption($groupVar); + checkBoxGrp -edit -v1 `optionVar -query usdMayaReferenceEditAsMayaDat` usdMayaReferenceEditAsMayaDatGrp; @@ -690,6 +735,18 @@ global proc addMayaReferenceToUsdInitUi(string $parent, string $filterType) fileOptionsSetup($parent, false, $filterType); } +global proc addMayaReferenceToUsdSelectionChanged(string $parent, string $selection) +{ + global string $gCurrentFileDialogSelection; + + setParent $parent; + $gCurrentFileDialogSelection = $selection; + + // Update the variant preview field. + string $groupPrimName = `textFieldGrp -q -text usdMayaReferenceGroupPrimName`; + usdMayaRef_changeGroupPrimNameText($groupPrimName); +} + // Verbatim copy of performFileAction.mel:makeNamespaceNameFromFileName(), // which is not a global proc. // @@ -754,6 +811,21 @@ global proc addMayaReferenceToUsdUiCb(string $parent, string $selectedFile) // Save the various Usd Maya Reference Options. $gUsdMayaReferencePrimName = `textFieldGrp -query -text usdMayaReferencePrimName`; + int $groupVar = `checkBoxGrp -q -v1 usdMayaReferenceGroupGrp`; + optionVar -iv usdMayaReferenceGroup $groupVar; + + if ($groupVar) + { + string $groupPrimName = `textFieldGrp -q -text usdMayaReferenceGroupPrimName`; + optionVar -sv usdMayaReferenceGroupPrimName $groupPrimName; + + string $groupPrimType = `optionMenuGrp -q -value usdMayaReferenceGroupPrimType`; + optionVar -sv usdMayaReferenceGroupPrimType $groupPrimType; + + string $groupPrimKind = `optionMenuGrp -q -value usdMayaReferenceGroupPrimKind`; + optionVar -sv usdMayaReferenceGroupPrimKind $groupPrimKind; + } + int $defineInVar = `checkBoxGrp -q -v1 usdMayaReferenceDefineInVariantGrp`; optionVar -iv usdMayaReferenceDefineInVariant $defineInVar; @@ -928,11 +1000,6 @@ proc string computeNamespace(string $filePath) return $ns; } -proc string quoteString(string $unquotedStr) -{ - return("\"" + $unquotedStr + "\""); -} - proc string sanitizeName(string $name) { return `python("from pxr import Tf; Tf.MakeValidIdentifier('" + $name + "')")`; @@ -942,6 +1009,8 @@ global proc string addMayaReferenceToUsd(string $ufePath) { global string $gUsdMayaReferenceUfePath; global string $gUsdMayaReferencePrimName; + global string $gCurrentFileDialogSelection; + $gCurrentFileDialogSelection = ""; // Save the Ufe Path string in a global variable so we can use it in the controls. $gUsdMayaReferenceUfePath = $ufePath; @@ -966,6 +1035,7 @@ global proc string addMayaReferenceToUsd(string $ufePath) -okCaption $ok -optionsUICreate addMayaReferenceToUsdCreateUi -optionsUIInit addMayaReferenceToUsdInitUi + -selectionChanged addMayaReferenceToUsdSelectionChanged -optionsUITitle "" -optionsUICommit2 addMayaReferenceToUsdUiCb`; @@ -976,9 +1046,21 @@ global proc string addMayaReferenceToUsd(string $ufePath) return ""; } - string $qVarSetName = quoteString(""); - string $qVarName = quoteString(""); + // If the group checkbox was enabled get the group prim name/type/kind. + int $useGroup = `optionVar -query usdMayaReferenceGroup`; + string $groupName; + string $groupType; + string $groupKind; + if ($useGroup) + { + $groupName = `optionVar -query usdMayaReferenceGroupPrimName`; + $groupType = `optionVar -query usdMayaReferenceGroupPrimType`; + $groupKind = `optionVar -query usdMayaReferenceGroupPrimKind`; + } + // If the define in variant checkbox was enabled get the variant set and variant name. + string $varSetName; + string $varName; if (`optionVar -query usdMayaReferenceDefineInVariant`) { string $createNew = getMayaUsdLibString("kMayaRefCreateNew"); @@ -987,14 +1069,14 @@ global proc string addMayaReferenceToUsd(string $ufePath) { $tmpValue = `optionVar -query usdMayaReferenceVariantSetNameText`; } - $qVarSetName = quoteString($tmpValue); + $varSetName = $tmpValue; $tmpValue = `optionVar -query usdMayaReferenceVariantNameOption`; if ($tmpValue == $createNew) { $tmpValue = `optionVar -query usdMayaReferenceVariantNameText`; } - $qVarName = quoteString($tmpValue); + $varName = $tmpValue; } int $autoEditAsMayaData = `optionVar -query usdMayaReferenceEditAsMayaDat`; @@ -1002,12 +1084,21 @@ global proc string addMayaReferenceToUsd(string $ufePath) // No need to actually create the Maya reference node: pulling on the // Maya reference prim will create the Maya reference node. // Create the Maya reference prim under its parent. - string $qUfePath = quoteString($ufePath); - string $qPrimName = quoteString($gUsdMayaReferencePrimName); string $filePath = fromNativePath($file[0]); - string $qFilePath = quoteString($filePath); - string $qNs = quoteString(`computeNamespace($filePath)`); - python("import mayaUsdAddMayaReference; mayaUsdAddMayaReference.createMayaReferencePrim(" + $qUfePath + ", " + $qFilePath + ", " + $qNs + ", " + $qPrimName + ", " + $qVarSetName + ", " + $qVarName + ", " + $autoEditAsMayaData + ")"); + string $ns = computeNamespace($filePath); + string $pyCmdArgs = `format -s $ufePath -s $filePath -s $ns -s $gUsdMayaReferencePrimName "'^1s', '^2s', '^3s', '^4s'"`; + if ($useGroup) + { + $pyCmdArgs += `format -s $groupName -s $groupType -s $groupKind ", groupPrim=('^1s', '^2s', '^3s')"`; + } + if (($varSetName != "") && ($varName != "")) + { + $pyCmdArgs += `format -s $varSetName -s $varName ", variantSet=('^1s', '^2s')"`; + } + string $autoEditAsMayaDataBool = $autoEditAsMayaData ? "True" : "False"; + $pyCmdArgs += `format -s $autoEditAsMayaDataBool ", mayaAutoEdit=^1s"`; + string $pyCmd = `format -s $pyCmdArgs "import mayaUsdAddMayaReference; mayaUsdAddMayaReference.createMayaReferencePrim(^1s)"`; + python($pyCmd); return $file[0]; } @@ -1035,12 +1126,22 @@ global proc usdMayaRef_changePrimNameText(string $primName) global proc usdMayaRef_changeGroupOption(int $opt) { textFieldGrp -edit -enable $opt usdMayaReferenceGroupPrimName; - textFieldGrp -edit -enable $opt usdMayaReferenceGroupPrimType; - textFieldGrp -edit -enable $opt usdMayaReferenceGroupPrimKind; + optionMenuGrp -edit -enable $opt usdMayaReferenceGroupPrimType; + optionMenuGrp -edit -enable $opt usdMayaReferenceGroupPrimKind; optionMenu -edit -visible (!$opt) usdMayaReferenceVariantSetNameOptionMenu; optionMenu -edit -visible (!$opt) usdMayaReferenceVariantNameOptionMenu; + // If the "Group" option was just enabled, we need to set both the variant + // set and variant name to "Create New". Since when group is enabled we hide + // the optionMenu and only show the fields. + if ($opt && (`optionMenu -q -ni usdMayaReferenceVariantSetNameOptionMenu` > 0)) { + // We know that "Create New" is always the first menu item. + optionMenu -edit -select 1 usdMayaReferenceVariantSetNameOptionMenu; + string $v = `optionMenu -q -value usdMayaReferenceVariantSetNameOptionMenu`; + usdMayaRef_changeVariantSetName($v); + } + usdMayaRef_setupDefineInVariantRows($opt, -1); // Also update the variant preview. @@ -1052,13 +1153,33 @@ global proc usdMayaRef_changeGroupPrimNameText(string $primName) { global string $gUsdMayaReferenceUfePath; + // Validate the user input (note: the group prim name is allowed to empty in which case + // a default name will be created). + string $validatedGroupPrimName; + if ($primName != "") { + $validatedGroupPrimName = sanitizeName($primName); + } + if ($validatedGroupPrimName != $primName) { + textFieldGrp -edit -text $validatedGroupPrimName usdMayaReferenceGroupPrimName; + } + // Fill-in the variant preview field. int $groupChecked = `checkBoxGrp -q -v1 usdMayaReferenceGroupGrp`; string $primPath = `python("import mayaUsdAddMayaReference; mayaUsdAddMayaReference.getPrimPath('" + $gUsdMayaReferenceUfePath + "')")`; if ($groupChecked) { string $variantPreviewPath = $primPath; - if ($primName != "") { - $variantPreviewPath += ($primPath + "/" + $primName); + if ($validatedGroupPrimName == "") { + string $ns; + string $sel = currentFileDialogSelection(); + if ($sel == "") { + $ns = ""; + } else { + string $filePath = fromNativePath($sel); + $ns = computeNamespace($filePath); + } + $variantPreviewPath += ("/" + $ns + "RNgroup"); + } else { + $variantPreviewPath += ("/" + $validatedGroupPrimName); } textField -edit -text $variantPreviewPath usdMayaReferenceVariantPrim; } else { diff --git a/lib/mayaUsd/resources/scripts/mayaUsdAddMayaReference.py b/lib/mayaUsd/resources/scripts/mayaUsdAddMayaReference.py index fba0ce33f6..9de7008066 100644 --- a/lib/mayaUsd/resources/scripts/mayaUsdAddMayaReference.py +++ b/lib/mayaUsd/resources/scripts/mayaUsdAddMayaReference.py @@ -14,11 +14,12 @@ # import maya.api.OpenMaya as om -import maya.cmds as cmds -from pxr import Sdf, Tf +from pxr import Sdf, Tf, Usd import mayaUsd import ufe import re +import maya.cmds as cmds +from mayaUsdLibRegisterStrings import getMayaUsdLibString # These names should not be localized as Usd only accepts [a-z,A-Z] as valid characters. kDefaultMayaReferencePrimName = 'MayaReference1' @@ -36,7 +37,10 @@ def defaultVariantName(): return kDefaultVariantName def createPrimAndAttributes(stage, primPath, mayaReferencePath, mayaNamespace, mayaAutoEdit): - prim = stage.DefinePrim(primPath.path, 'MayaReference') + try: + prim = stage.DefinePrim(primPath.path, 'MayaReference') + except (Tf.ErrorException): + return Usd.Prim() mayaReferenceAttr = prim.CreateAttribute('mayaReference', Sdf.ValueTypeNames.Asset) mayaReferenceAttr.Set(mayaReferencePath) @@ -49,47 +53,158 @@ def createPrimAndAttributes(stage, primPath, mayaReferencePath, mayaNamespace, m return prim +def getDefaultGroupPrimName(parentPrim, mayaNamespace): + # "The name of the reference file" + "RN" + "group" for example 'sphereRNgroup'. + # If a prim with this name already exists, then add a numeric suffix after "RN". + startName = mayaNamespace + "RNgroup" + checkName = mayaUsd.ufe.uniqueChildName(parentPrim, startName) + index = 1 + while (checkName != startName): + startName = "%sRN%dgroup" % (mayaNamespace, index) + checkName = mayaUsd.ufe.uniqueChildName(parentPrim, startName) + index += 1 + return startName + # Adapted from testMayaUsdSchemasMayaReference.py. def createMayaReferencePrim(ufePathStr, mayaReferencePath, mayaNamespace, mayaReferencePrimName = kDefaultMayaReferencePrimName, - variantSetName = kDefaultVariantSetName, - variantName = kDefaultVariantName, + groupPrim = None, variantSet = None, mayaAutoEdit = kDefaultEditAsMayaData): - '''Create a Maya reference prim parented to the argument path.''' + '''Create a Maya reference prim and optional group prim parented to the argument path. + Optionally create a variant set and name and placed the edits inside that variant. + + Naming of Maya Reference prim is supported, otherwise default name is used. + + The group prim is optional. + + The variant set and name are optional + + Parameters: + ----------- + ufePathStr : str : Ufe PathString of parent prim to add Maya Reference + mayaReferencePath : str : File path of Maya Reference (for attribute) + mayaNamespace : str : Namespace (for attribute) + mayaReferencePrimName : str [optional] : Name for the Maya Reference prim + groupPrim : tuple(str,str,str) [optional] : The Group prim Name, Type & Kind to create + Note: the name is optional and will be auto-computed + if empty or not provided. + Note: Type and Kind are both mandatory, but Kind is + allowed to be empty string. + variantSet : tuple(str,str) [optional] : The Variant Set Name and Variant Name to create + + Return: + ------- + The Usd prim of the newly created Maya Reference or an invalid prim if there is an error. + ''' # Make sure the prim name is valid and doesn't already exist. parentPrim = mayaUsd.ufe.ufePathToPrim(ufePathStr) - checkName = mayaUsd.ufe.uniqueChildName(parentPrim, mayaReferencePrimName) + # There are special conditions when we are given the ProxyShape gateway node. + ufePath = ufe.PathString.path(ufePathStr) + isGateway = (ufePath.nbSegments() == 1) + + # Were we given a Group prim to create? + groupPrimName = None + groupPrimType = None + groupPrimKind = None + if groupPrim: + if (len(groupPrim) == 2): + groupPrimType, groupPrimKind = groupPrim + elif (len(groupPrim) == 3): + groupPrimName, groupPrimType, groupPrimKind = groupPrim + + # Make sure the input Group prim name doesn't exist already + # and validate the input name. + # Note: it is allowed to be input as empty in which case a default is used. + if groupPrimName: + checkGroupPrimName = mayaUsd.ufe.uniqueChildName(parentPrim, groupPrimName) + if checkGroupPrimName != groupPrimName: + errorMsgFormat = getMayaUsdLibString('kErrorGroupPrimExists') + errorMsg = cmds.format(errorMsgFormat, stringArg=(groupPrimName, ufePathStr)) + om.MGlobal.displayError(errorMsg) + return Usd.Prim() + groupPrimName = Tf.MakeValidIdentifier(checkGroupPrimName) + + # If the group prim was either not provided or empty we use a default name. + if not groupPrimName: + groupPrimName = getDefaultGroupPrimName(parentPrim, mayaNamespace) + + # When the input is a gateway we cannot have in variant unless group is also given. + if isGateway and variantSet and not groupPrimName: + errorMsg = getMayaUsdLibString('kErrorCannotAddToProxyShape') + om.MGlobal.displayError(errorMsg) + return Usd.Prim() + + # Make sure the input Maya Reference prim name doesn't exist already + # and validate the input name. + # Note: if we are given a group prim to create, then we know that the + # Maya Reference prim name will be unique since it will be the + # only child (of the newly created group prim). + checkName = mayaUsd.ufe.uniqueChildName(parentPrim, mayaReferencePrimName) if groupPrim is None else mayaReferencePrimName if checkName != mayaReferencePrimName: - cmds.error('Maya Reference prim name already exists.') - return + errorMsgFormat = getMayaUsdLibString('kErrorMayaRefPrimExists') + errorMsg = cmds.format(errorMsgFormat, stringArg=(mayaReferencePrimName, ufePathStr)) + om.MGlobal.displayError(errorMsg) + return Usd.Prim() validatedPrimName = Tf.MakeValidIdentifier(checkName) # Extract the USD path segment from the UFE path and append the Maya # reference prim to it. - ufePath = ufe.PathString.path(ufePathStr) parentPath = str(ufePath.segments[1]) if ufePath.nbSegments() > 1 else '' - primPath = Sdf.AssetPath(parentPath + '/' + validatedPrimName) stage = mayaUsd.ufe.getStage(ufePathStr) - variantSetName = Tf.MakeValidIdentifier(variantSetName) - variantName = Tf.MakeValidIdentifier(variantName) + # Optionally insert a Group prim as a parent of the Maya reference prim. + groupPrim = None + if groupPrimName: + groupPath = Sdf.AssetPath(parentPath + '/' + groupPrimName) + try: + groupPrim = stage.DefinePrim(groupPath.path, groupPrimType) + except (Tf.ErrorException): + groupPrim = Usd.Prim() + if not groupPrim.IsValid(): + errorMsgFormat = getMayaUsdLibString('kErrorCreatingGroupPrim') + errorMsg = cmds.format(errorMsgFormat, stringArg=(ufePathStr)) + om.MGlobal.displayError(errorMsg) + return Usd.Prim() + if groupPrimKind: + model = Usd.ModelAPI(groupPrim) + model.SetKind(groupPrimKind) + + if groupPrim: + primPath = Sdf.AssetPath(groupPrim.GetPath().pathString + '/' + validatedPrimName) + else: + primPath = Sdf.AssetPath(parentPath + '/' + validatedPrimName) + + # Were we given a Variant Set to create? + variantSetName = None + variantName = None + if variantSet and (len(variantSet) == 2): + variantSetName, variantName = variantSet if variantSetName and variantName: - ufePathPrim = mayaUsd.ufe.ufePathToPrim(ufePathStr) - vset = ufePathPrim.GetVariantSet(variantSetName) - vset.AddVariant(variantName) - vset.SetVariantSelection(variantName) + validatedVariantSetName = Tf.MakeValidIdentifier(variantSetName) + validatedVariantName = Tf.MakeValidIdentifier(variantName) + + # If we created a group prim add the variant set there, otherwise add it + # to the prim that corresponds to the input ufe path. + variantPrim = groupPrim if groupPrim else mayaUsd.ufe.ufePathToPrim(ufePathStr) + vset = variantPrim.GetVariantSet(validatedVariantSetName) + vset.AddVariant(validatedVariantName) + vset.SetVariantSelection(validatedVariantName) with vset.GetVariantEditContext(): # Now all of our subsequent edits will go "inside" the # 'variantName' variant of 'variantSetName'. prim = createPrimAndAttributes(stage, primPath, mayaReferencePath, mayaNamespace, mayaAutoEdit) else: prim = createPrimAndAttributes(stage, primPath, mayaReferencePath, mayaNamespace, mayaAutoEdit) - if not prim.IsValid(): - om.MGlobal.displayError("Could not create MayaReference prim under %s" % ufePathStr) - return + if prim is None or not prim.IsValid(): + errorMsgFormat = getMayaUsdLibString('kErrorCreatingMayaRefPrim') + errorMsg = cmds.format(errorMsgFormat, stringArg=(ufePathStr)) + om.MGlobal.displayError(errorMsg) + return Usd.Prim() + + return prim def getVariantSetNames(ufePathStr): prim = mayaUsd.ufe.ufePathToPrim(ufePathStr) @@ -107,8 +222,7 @@ def getVariantNames(ufePathStr, variantSetName): def getPrimPath(ufePathStr): ufePath = ufe.PathString.path(ufePathStr) - parentPath = ufePath.segments[1] - return str(parentPath) + return '' if ufePath.nbSegments() == 1 else str(ufePath.segments[1]) def getUniqueMayaReferencePrimName(ufePathStr, startName=None): '''Helper function to get a unique name for the Maya Reference prim.''' diff --git a/lib/mayaUsd/resources/scripts/mayaUsdLibRegisterStrings.py b/lib/mayaUsd/resources/scripts/mayaUsdLibRegisterStrings.py index f1fd1ee840..d1a1bbc5ae 100644 --- a/lib/mayaUsd/resources/scripts/mayaUsdLibRegisterStrings.py +++ b/lib/mayaUsd/resources/scripts/mayaUsdLibRegisterStrings.py @@ -23,8 +23,17 @@ def getMayaUsdLibString(key): return getPluginResource('mayaUsdLib', key) def mayaUsdLibRegisterStrings(): + # This function is called from the equivalent MEL proc + # with the same name. The strings registered here and all the + # ones registered from the MEL proc can be used in either + # MEL or python. + # Any python strings from MayaUsd lib go here. - pass + register('kErrorGroupPrimExists', 'Group prim name "^1s" already exists under "^2s".') + register('kErrorCannotAddToProxyShape', 'Cannot add Maya Reference node to ProxyShape with VariantSet unless Group prim is used.') + register('kErrorMayaRefPrimExists', 'Maya Reference prim name "^1s" already exists under "^2s".') + register('kErrorCreatingGroupPrim', 'Could not create Group prim under "^1s".') + register('kErrorCreatingMayaRefPrim', 'Could not create MayaReference prim under "^1s".') def registerPluginResource(pluginId, stringId, resourceStr): '''See registerPluginResource.mel in Maya. diff --git a/lib/mayaUsd/ufe/Utils.cpp b/lib/mayaUsd/ufe/Utils.cpp index f80922cb94..da4a90641d 100644 --- a/lib/mayaUsd/ufe/Utils.cpp +++ b/lib/mayaUsd/ufe/Utils.cpp @@ -177,24 +177,23 @@ Ufe::Path stripInstanceIndexFromUfePath(const Ufe::Path& path) UsdPrim ufePathToPrim(const Ufe::Path& path) { - const Ufe::Path ufePrimPath = stripInstanceIndexFromUfePath(path); - - // Assume that there are only two segments in the path, the first a Maya - // Dag path segment to the proxy shape, which identifies the stage, and - // the second the USD segment. // When called we do not make any assumption on whether or not the // input path is valid. + + const Ufe::Path ufePrimPath = stripInstanceIndexFromUfePath(path); + const Ufe::Path::Segments& segments = ufePrimPath.getSegments(); - if (!TF_VERIFY(segments.size() == 2u, kIllegalUSDPath, path.string().c_str())) { + auto stage = getStage(Ufe::Path(segments[0])); + if (!TF_VERIFY(stage, kIllegalUSDPath, path.string().c_str())) { return UsdPrim(); } - UsdPrim prim; - if (auto stage = getStage(Ufe::Path(segments[0]))) { - const SdfPath usdPath = SdfPath(segments[1].string()); - prim = stage->GetPrimAtPath(usdPath.GetPrimPath()); - } - return prim; + // If there is only a single segment in the path, it must point to the + // proxy shape, otherwise we would not have retrieved a valid stage. + // The second path segment is the USD path. + return (segments.size() == 1u) + ? stage->GetPseudoRoot() + : stage->GetPrimAtPath(SdfPath(segments[1].string()).GetPrimPath()); } int ufePathToInstanceIndex(const Ufe::Path& path, PXR_NS::UsdPrim* prim) diff --git a/test/lib/mayaUsd/fileio/testAddMayaReference.py b/test/lib/mayaUsd/fileio/testAddMayaReference.py index 6eed59c644..f68da31a1c 100644 --- a/test/lib/mayaUsd/fileio/testAddMayaReference.py +++ b/test/lib/mayaUsd/fileio/testAddMayaReference.py @@ -21,12 +21,11 @@ import mayaUsd import mayaUtils -from pxr import Tf +from pxr import Tf, Usd, Kind from maya import cmds from maya import standalone -from mayaUsdLibRegisterStrings import getMayaUsdLibString -from mayaUSDRegisterStrings import getMayaUsdString +import mayaUsdAddMayaReference import unittest @@ -34,6 +33,9 @@ class AddMayaReferenceTestCase(unittest.TestCase): '''Test Add Maya Reference. ''' pluginsLoaded = False + mayaSceneStr = None + stage = None + kDefaultNamespace = 'simpleSphere' @classmethod def setUpClass(cls): @@ -41,56 +43,95 @@ def setUpClass(cls): if not cls.pluginsLoaded: cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() + # Create a pure Maya scene to reference in. + cls.mayaSceneStr = cls.createSimpleMayaScene() + @classmethod def tearDownClass(cls): standalone.uninitialize() def setUp(self): + # Start each test with a new scene with empty stage. cmds.file(new=True, force=True) + import mayaUsd_createStageWithNewLayer + self.proxyShapePathStr = mayaUsd_createStageWithNewLayer.createStageWithNewLayer() + self.stage = mayaUsd.lib.GetPrim(self.proxyShapePathStr).GetStage() - def createSimpleMayaScene(self): + @staticmethod + def createSimpleMayaScene(): import os import maya.cmds as cmds import tempfile + cmds.file(new=True, force=True) cmds.CreatePolygonSphere() tempMayaFile = os.path.join(tempfile.gettempdir(), 'simpleSphere.ma') cmds.file(rename=tempMayaFile) cmds.file(save=True, force=True, type='mayaAscii') return tempMayaFile - def testDefineInVariant(self): - '''Test the "Define in Variant" options for Add Maya Reference.''' - - # First we need a pure Maya scene to reference in. - mayaSceneStr = self.createSimpleMayaScene() + def testDefault(self): + '''Test the default options for Add Maya Reference. - # Then create an Xform and add the maya reference. - cmds.file(new=True, force=True) - import mayaUsd_createStageWithNewLayer - proxyShapePathStr = mayaUsd_createStageWithNewLayer.createStageWithNewLayer() - stage = mayaUsd.lib.GetPrim(proxyShapePathStr).GetStage() - primA = stage.DefinePrim('/A', 'Xform') - primPathStr = proxyShapePathStr + ',/A' + Add a Maya Reference using the defaults (no group or variant). + ''' + kDefaultPrimName = mayaUsdAddMayaReference.defaultMayaReferencePrimName() # Since this is a brand new prim, it should not have variant sets. - primA = mayaUsd.ufe.ufePathToPrim(primPathStr) - self.assertFalse(primA.HasVariantSets()) + primTestDefault = self.stage.DefinePrim('/Test_Default', 'Xform') + primPathStr = self.proxyShapePathStr + ',/Test_Default' + self.assertFalse(primTestDefault.HasVariantSets()) + + mayaRefPrim = mayaUsdAddMayaReference.createMayaReferencePrim( + primPathStr, + self.mayaSceneStr, + self.kDefaultNamespace) + + # The prim should not have any variant set. + self.assertFalse(primTestDefault.HasVariantSets()) + + # Verify that a Maya Reference prim was created. + self.assertTrue(mayaRefPrim.IsValid()) + self.assertEqual(str(mayaRefPrim.GetName()), kDefaultPrimName) + self.assertEqual(mayaRefPrim, primTestDefault.GetChild(kDefaultPrimName)) + self.assertTrue(mayaRefPrim.GetPrimTypeInfo().GetTypeName(), 'MayaReference') + + # Test an error creating the Maya reference prim by disabling permission to edit on the + # edit target layer. + editTarget = self.stage.GetEditTarget() + editLayer = editTarget.GetLayer() + editLayer.SetPermissionToEdit(False) + badMayaRefPrim = mayaUsdAddMayaReference.createMayaReferencePrim( + primPathStr, + self.mayaSceneStr, + self.kDefaultNamespace, + mayaReferencePrimName='BadMayaReference') + self.assertFalse(badMayaRefPrim.IsValid()) + editLayer.SetPermissionToEdit(True) - # Add a Maya Reference using the default. - import mayaUsdAddMayaReference - kDefaultNamespace = 'simpleSphere' + def testDefineInVariant(self): + '''Test the "Define in Variant" options. + + Add a Maya Reference with a (default) variant set. + ''' kDefaultPrimName = mayaUsdAddMayaReference.defaultMayaReferencePrimName() kDefaultVariantSetName = mayaUsdAddMayaReference.defaultVariantSetName() kDefaultVariantName = mayaUsdAddMayaReference.defaultVariantName() - mayaUsdAddMayaReference.createMayaReferencePrim( + + # Create another prim with default variant set and name. + primTestVariant = self.stage.DefinePrim('/Test_Variant', 'Xform') + primPathStr = self.proxyShapePathStr + ',/Test_Variant' + + mayaRefPrim = mayaUsdAddMayaReference.createMayaReferencePrim( primPathStr, - mayaSceneStr, - kDefaultNamespace, mayaAutoEdit=True) + self.mayaSceneStr, + self.kDefaultNamespace, + variantSet=(kDefaultVariantSetName, kDefaultVariantName), + mayaAutoEdit=True) # Make sure the prim has the variant set and variant. - self.assertTrue(primA.HasVariantSets()) - vset = primA.GetVariantSet(kDefaultVariantSetName) + self.assertTrue(primTestVariant.HasVariantSets()) + vset = primTestVariant.GetVariantSet(kDefaultVariantSetName) self.assertTrue(vset.IsValid()) self.assertEqual(vset.GetName(), kDefaultVariantSetName) self.assertTrue(vset.GetVariantNames()) @@ -98,26 +139,34 @@ def testDefineInVariant(self): self.assertEqual(vset.GetVariantSelection(), kDefaultVariantName) # Verify that a Maya Reference prim was created. - mayaRefPrim = primA.GetChild(kDefaultPrimName) self.assertTrue(mayaRefPrim.IsValid()) + self.assertEqual(str(mayaRefPrim.GetName()), kDefaultPrimName) + self.assertEqual(mayaRefPrim, primTestVariant.GetChild(kDefaultPrimName)) self.assertTrue(mayaRefPrim.GetPrimTypeInfo().GetTypeName(), 'MayaReference') # Verify that the Maya reference prim is inside the variant, # and that it has the expected metadata. attr = mayaRefPrim.GetAttribute('mayaReference') self.assertTrue(attr.IsValid()) - self.assertEqual(attr.Get().resolvedPath, mayaSceneStr) + self.assertEqual(attr.Get().resolvedPath, self.mayaSceneStr) attr = mayaRefPrim.GetAttribute('mayaNamespace') self.assertTrue(attr.IsValid()) - self.assertEqual(attr.Get(), kDefaultNamespace) + self.assertEqual(attr.Get(), self.kDefaultNamespace) attr = mayaRefPrim.GetAttribute('mayaAutoEdit') self.assertTrue(attr.IsValid()) self.assertEqual(attr.Get(),True) - # Create another prim to test sanitizing variant name. - primB = stage.DefinePrim('/B', 'Xform') - primPathStr = proxyShapePathStr + ',/B' - primB = mayaUsd.ufe.ufePathToPrim(primPathStr) + def testBadNames(self): + '''Test using bad prim and variant names. + + Add a Maya Reference using a bad Maya Reference prim name and + bad Variant Set and Variant name. + ''' + kDefaultPrimName = mayaUsdAddMayaReference.defaultMayaReferencePrimName() + + # Create another prim to test sanitizing variant set and name. + primTestSanitizeVariant = self.stage.DefinePrim('/Test_SanitizeVariant', 'Xform') + primPathStr = self.proxyShapePathStr + ',/Test_SanitizeVariant' kBadPrimName = ('3'+kDefaultPrimName+'$') kGoodPrimName = Tf.MakeValidIdentifier(kBadPrimName) @@ -125,16 +174,17 @@ def testDefineInVariant(self): kGoodVariantSetName = Tf.MakeValidIdentifier(kBadVariantSetName) kBadVariantName = '3no start digits' kGoodVariantName = Tf.MakeValidIdentifier(kBadVariantName) - mayaUsdAddMayaReference.createMayaReferencePrim( + mayaRefPrim = mayaUsdAddMayaReference.createMayaReferencePrim( primPathStr, - mayaSceneStr, - kDefaultNamespace, - kBadPrimName, kBadVariantSetName, kBadVariantName) + self.mayaSceneStr, + self.kDefaultNamespace, + mayaReferencePrimName=kBadPrimName, + variantSet=(kBadVariantSetName, kBadVariantName)) # Make sure the prim has the variant set and variant with # the sanitized names. - self.assertTrue(primB.HasVariantSets()) - vset = primB.GetVariantSet(kGoodVariantSetName) + self.assertTrue(primTestSanitizeVariant.HasVariantSets()) + vset = primTestSanitizeVariant.GetVariantSet(kGoodVariantSetName) self.assertTrue(vset.IsValid()) self.assertEqual(vset.GetName(), kGoodVariantSetName) self.assertTrue(vset.GetVariantNames()) @@ -142,9 +192,135 @@ def testDefineInVariant(self): self.assertEqual(vset.GetVariantSelection(), kGoodVariantName) # Verify that the prim was created with the good name. - mayaRefPrim = primB.GetChild(kGoodPrimName) self.assertTrue(mayaRefPrim.IsValid()) + self.assertEqual(str(mayaRefPrim.GetName()), kGoodPrimName) + self.assertEqual(mayaRefPrim, primTestSanitizeVariant.GetChild(kGoodPrimName)) + self.assertTrue(mayaRefPrim.GetPrimTypeInfo().GetTypeName(), 'MayaReference') + + # Adding a Maya Reference with the same name should produce an error. + mayaRefPrim = mayaUsdAddMayaReference.createMayaReferencePrim( + primPathStr, + self.mayaSceneStr, + self.kDefaultNamespace, + mayaReferencePrimName=kGoodPrimName) + self.assertFalse(mayaRefPrim.IsValid()) + + def testGroup(self): + '''Test the "Group" options. + + Add a Maya Reference using a group. + ''' + kDefaultPrimName = mayaUsdAddMayaReference.defaultMayaReferencePrimName() + kDefaultVariantSetName = mayaUsdAddMayaReference.defaultVariantSetName() + kDefaultVariantName = mayaUsdAddMayaReference.defaultVariantName() + + # Create another prim to test adding a group prim (with variant). + primTestGroup = self.stage.DefinePrim('/Test_Group', 'Xform') + primPathStr = self.proxyShapePathStr + ',/Test_Group' + + mayaRefPrim = mayaUsdAddMayaReference.createMayaReferencePrim( + primPathStr, + self.mayaSceneStr, + self.kDefaultNamespace, + groupPrim=('Xform', Kind.Tokens.group), + variantSet=(kDefaultVariantSetName, kDefaultVariantName)) + + # Make sure a group prim was created. + # Since we did not provide a group name, one will have been auto-generated for us. + # "namespace" + "RN" + "group" + primGroup = primTestGroup.GetChild(self.kDefaultNamespace+'RNgroup') + self.assertTrue(primGroup.IsValid()) + self.assertTrue(primGroup.GetPrimTypeInfo().GetTypeName(), 'Xform') + model = Usd.ModelAPI(primGroup) + self.assertEqual(model.GetKind(), Kind.Tokens.group) + + # Make sure the group prim has the variant set and variant. + self.assertTrue(primGroup.HasVariantSets()) + vset = primGroup.GetVariantSet(kDefaultVariantSetName) + self.assertTrue(vset.IsValid()) + self.assertEqual(vset.GetName(), kDefaultVariantSetName) + self.assertTrue(vset.GetVariantNames()) + self.assertTrue(vset.HasAuthoredVariant(kDefaultVariantName)) + self.assertEqual(vset.GetVariantSelection(), kDefaultVariantName) + + # Verify that a Maya Reference prim was created under the new group prim. + self.assertTrue(mayaRefPrim.IsValid()) + self.assertEqual(str(mayaRefPrim.GetName()), kDefaultPrimName) + self.assertEqual(mayaRefPrim, primGroup.GetChild(kDefaultPrimName)) + self.assertTrue(mayaRefPrim.GetPrimTypeInfo().GetTypeName(), 'MayaReference') + + # Add another Maya reference with group, but name the group this time and + # use a 'Scope' prim instead. + kGroupName = 'NewGroup' + mayaRefPrim = mayaUsdAddMayaReference.createMayaReferencePrim( + primPathStr, + self.mayaSceneStr, + self.kDefaultNamespace, + groupPrim=(kGroupName, 'Scope', Kind.Tokens.group)) + + # Make sure a group prim was created and what we named it. + prim2ndGroup = primTestGroup.GetChild(kGroupName) + self.assertTrue(prim2ndGroup.IsValid()) + self.assertTrue(prim2ndGroup.GetPrimTypeInfo().GetTypeName(), 'Scope') + model = Usd.ModelAPI(prim2ndGroup) + self.assertEqual(model.GetKind(), Kind.Tokens.group) + + # Verify that a Maya Reference prim was created under the new group prim. + self.assertTrue(mayaRefPrim.IsValid()) + self.assertEqual(str(mayaRefPrim.GetName()), kDefaultPrimName) + self.assertEqual(mayaRefPrim, prim2ndGroup.GetChild(kDefaultPrimName)) self.assertTrue(mayaRefPrim.GetPrimTypeInfo().GetTypeName(), 'MayaReference') + # Adding a group with the same name should produce an error. + mayaRefPrim = mayaUsdAddMayaReference.createMayaReferencePrim( + primPathStr, + self.mayaSceneStr, + self.kDefaultNamespace, + groupPrim=(kGroupName, 'Scope', Kind.Tokens.group)) + self.assertFalse(mayaRefPrim.IsValid()) + + # Test an error creating the group prim by disabling permission to edit on the edit target layer. + editTarget = self.stage.GetEditTarget() + editLayer = editTarget.GetLayer() + editLayer.SetPermissionToEdit(False) + badMayaRefPrim = mayaUsdAddMayaReference.createMayaReferencePrim( + primPathStr, + self.mayaSceneStr, + self.kDefaultNamespace, + groupPrim=('NoGroup', 'Xform', Kind.Tokens.group)) + self.assertFalse(badMayaRefPrim.IsValid()) + invalidGroupPrim = primTestGroup.GetChild('NoGroup') + self.assertFalse(invalidGroupPrim.IsValid()) + editLayer.SetPermissionToEdit(True) + + def testProxyShape(self): + '''Test adding a Maya Reference directly undereath the proxy shape. + + Add a Maya Reference using the defaults (no group or variant). + ''' + kDefaultPrimName = mayaUsdAddMayaReference.defaultMayaReferencePrimName() + + mayaRefPrim = mayaUsdAddMayaReference.createMayaReferencePrim( + self.proxyShapePathStr, + self.mayaSceneStr, + self.kDefaultNamespace) + + # Verify that a Maya Reference prim was created. + self.assertTrue(mayaRefPrim.IsValid()) + self.assertEqual(str(mayaRefPrim.GetName()), kDefaultPrimName) + self.assertTrue(mayaRefPrim.GetPrimTypeInfo().GetTypeName(), 'MayaReference') + + # We should get an error (invalid prim) when adding a Maya reference under + # the proxy shape when we also add a variant set. + kDefaultVariantSetName = mayaUsdAddMayaReference.defaultVariantSetName() + kDefaultVariantName = mayaUsdAddMayaReference.defaultVariantName() + mayaRefPrim = mayaUsdAddMayaReference.createMayaReferencePrim( + self.proxyShapePathStr, + self.mayaSceneStr, + self.kDefaultNamespace, + variantSet=(kDefaultVariantSetName, kDefaultVariantName)) + self.assertFalse(mayaRefPrim.IsValid()) + + if __name__ == '__main__': unittest.main(verbosity=2)