Skip to content

Commit fcc05dc

Browse files
EMSUSD-943 handle up-axis and units when staging a USD file
Up-axis and units UI when staging a USD file: - Add up-axis, unit and conversion method UI to the staging UI. - Add that the conversion method menu is disabled in the import UI. - Make import sections collapsable. - Fix typo in a header file. Up-axis and units conversion for stages: - Add Python helpers to do the conversion since MEL cannot manipulate USD. - Call the helpers from the MEL script that creates the stage. - Change prefs or modify stage shape based on necessary conversion. Add unit tests - Move helper functions to verify transforms to their own file. - Update some existing tests to use the new functions. - Add unit tests when stage USD file for up-axis and units conversion.
1 parent 0668bf5 commit fcc05dc

19 files changed

+719
-155
lines changed

lib/mayaUsd/resources/scripts/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ list(APPEND scripts_src
1414
mayaUsdMergeToUSDOptions.py
1515
mayaUsdMergeToUsd.py
1616
mayaUsdOptions.py
17+
mayaUsdStageConversion.py
1718
mayaUsdUtils.py
1819
mayaUsdMayaReferenceUtils.py
1920
)

lib/mayaUsd/resources/scripts/mayaUsdLibRegisterStrings.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,11 @@ def mayaUsdLibRegisterStrings():
129129
register('kMenuCacheToUsd', 'Cache to USD...')
130130
register('kMenuMergeMayaEdits', 'Merge Maya Edits to USD');
131131

132+
# mayaUsdStageConversion.py
133+
register("kStageConversionUnknownMethod", "Unknown stage conversion method: %s")
134+
register("kStageConversionSuccessful", "Mismatching axis/unit have been converted for accurate scale.")
135+
136+
132137
def registerPluginResource(pluginId, stringId, resourceStr):
133138
'''See registerPluginResource.mel in Maya.
134139
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import maya.cmds as _cmds
2+
import maya.api.OpenMaya as _om
3+
import mayaUsd.ufe as _ufe
4+
5+
from mayaUsdLibRegisterStrings import getMayaUsdLibString as _getMayaUsdLibString
6+
7+
from pxr import UsdGeom as _UsdGeom
8+
9+
10+
def convertUpAxisAndUnit(shapeNode, convertUpAxis, convertUnit, conversionMethod):
11+
'''
12+
Edit the USD stage associated with the given Maya stage proxy node to
13+
convert the up-axis or the units used to match what is in the USD file
14+
with what Maya is using.
15+
'''
16+
# If neither up-axis nor unit are requested to be modified, return immediately.
17+
conversionInfo = StageConversionInfo(shapeNode, convertUpAxis, convertUnit)
18+
if not conversionInfo.needUnitsConversion and not conversionInfo.needUpAxisConversion:
19+
return
20+
21+
resultMsg = _getMayaUsdLibString("kStageConversionSuccessful")
22+
23+
if conversionMethod.lower() == 'rotatescale':
24+
convertUpAxisAndUnitByModifyingStage(conversionInfo)
25+
elif conversionMethod.lower() == 'overwriteprefs':
26+
convertUpAxisAndUnitByModifyingPrefs(conversionInfo)
27+
else:
28+
resultMsg = _getMayaUsdLibString("kStageConversionUnknownMethod") % conversionMethod
29+
30+
print(resultMsg)
31+
32+
33+
class StageConversionInfo:
34+
'''
35+
Analyze the contents of the USD file and compare it to the Maya settings
36+
to determine what actions need to be done to match them.
37+
'''
38+
39+
@staticmethod
40+
def _isMayaUpAxisZ():
41+
return _cmds.upAxis(query=True, axis=True).lower() == 'z'
42+
43+
@staticmethod
44+
def _isUsdUpAxisZ(stage):
45+
return _UsdGeom.GetStageUpAxis(stage).lower() == 'z'
46+
47+
_mayaToMetersPerUnit = {
48+
_om.MDistance.kInches : _UsdGeom.LinearUnits.inches,
49+
_om.MDistance.kFeet : _UsdGeom.LinearUnits.feet,
50+
_om.MDistance.kYards : _UsdGeom.LinearUnits.yards,
51+
_om.MDistance.kMiles : _UsdGeom.LinearUnits.miles,
52+
_om.MDistance.kMillimeters : _UsdGeom.LinearUnits.millimeters,
53+
_om.MDistance.kCentimeters : _UsdGeom.LinearUnits.centimeters,
54+
_om.MDistance.kKilometers : _UsdGeom.LinearUnits.kilometers,
55+
_om.MDistance.kMeters : _UsdGeom.LinearUnits.meters,
56+
}
57+
58+
@staticmethod
59+
def _convertMayaUnitToMetersPerUnit(mayaUnits):
60+
if mayaUnits not in StageConversionInfo._mayaToMetersPerUnit:
61+
return _UsdGeom.LinearUnits.centimeters
62+
return StageConversionInfo._mayaToMetersPerUnit[mayaUnits]
63+
64+
_metersPerUnitToMayaUnitName = {
65+
_UsdGeom.LinearUnits.inches : "inch",
66+
_UsdGeom.LinearUnits.feet : "foot",
67+
_UsdGeom.LinearUnits.yards : "yard",
68+
_UsdGeom.LinearUnits.miles : "mile",
69+
_UsdGeom.LinearUnits.millimeters : "mm",
70+
_UsdGeom.LinearUnits.centimeters : "cn",
71+
_UsdGeom.LinearUnits.kilometers : "km",
72+
_UsdGeom.LinearUnits.meters : "m",
73+
}
74+
75+
@staticmethod
76+
def _convertMetersPerUnitToMayaUnitName(metersPerUnit):
77+
if metersPerUnit not in StageConversionInfo._metersPerUnitToMayaUnitName:
78+
return "cm"
79+
return StageConversionInfo._metersPerUnitToMayaUnitName[metersPerUnit]
80+
81+
@staticmethod
82+
def _getMayaMetersPerUnit():
83+
mayaUnits = _om.MDistance.internalUnit()
84+
return StageConversionInfo._convertMayaUnitToMetersPerUnit(mayaUnits)
85+
86+
@staticmethod
87+
def _getUsdMetersPerUnit(stage):
88+
return _UsdGeom.GetStageMetersPerUnit(stage)
89+
90+
@staticmethod
91+
def _getStageFromShapeNode(shapeNode):
92+
res = _cmds.ls(shapeNode, l=True)
93+
fullStageName = res[0]
94+
return _ufe.getStage(fullStageName)
95+
96+
def __init__(self, shapeNode, convertUpAxis, convertUnit):
97+
self.shapeNode = shapeNode
98+
self.stage = self._getStageFromShapeNode(shapeNode)
99+
100+
self.isMayaUpAxisZ = self._isMayaUpAxisZ()
101+
self.isUsdUpAxisZ = self._isUsdUpAxisZ(self.stage)
102+
self.needUpAxisConversion = convertUpAxis and (self.isMayaUpAxisZ != self.isUsdUpAxisZ)
103+
104+
self.mayaMetersPerUnit = self._getMayaMetersPerUnit()
105+
self.usdMetersPerUnit = self._getUsdMetersPerUnit(self.stage)
106+
self.needUnitsConversion = convertUnit and (self.mayaMetersPerUnit != self.usdMetersPerUnit)
107+
108+
109+
def convertUpAxisAndUnitByModifyingStage(conversionInfo):
110+
'''
111+
Handle the differences of up-axis and units from the USD file by modifying
112+
the Maya proxy shape node transform to compensate for the differences.
113+
'''
114+
if conversionInfo.needUpAxisConversion:
115+
angle = 90 if conversionInfo.isMayaUpAxisZ else -90
116+
_cmds.rotate(angle, 0, 0, conversionInfo.shapeNode, relative=True, euler=True, pivot=(0, 0, 0), forceOrderXYZ=True)
117+
118+
if conversionInfo.needUnitsConversion:
119+
factor = conversionInfo.usdMetersPerUnit / conversionInfo.mayaMetersPerUnit
120+
_cmds.scale(factor, factor, factor, conversionInfo.shapeNode, relative=True, pivot=(0, 0, 0), scaleXYZ=True)
121+
122+
123+
def convertUpAxisAndUnitByModifyingPrefs(conversionInfo):
124+
'''
125+
Handle the differences of up-axis and units from the USD file by modifying
126+
the Maya preferences to match the USD file.
127+
'''
128+
if conversionInfo.needUpAxisConversion:
129+
newAxis = 'z' if conversionInfo.isUsdUpAxisZ else 'y'
130+
_cmds.upAxis(axis=newAxis)
131+
132+
if conversionInfo.needUnitsConversion:
133+
newUnit = conversionInfo._convertMetersPerUnitToMayaUnitName(conversionInfo.usdMetersPerUnit)
134+
_cmds.currentUnit(linear=newUnit)
135+

lib/mayaUsd/utils/util.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ double ConvertMDistanceUnitToUsdGeomLinearUnit(const MDistance::Unit mdistanceUn
152152
MAYAUSD_CORE_PUBLIC
153153
MDistance::Unit ConvertUsdGeomLinearUnitToMDistanceUnit(const double linearUnit);
154154

155-
/// Convert the given \p mdistanceYnit into its text representation suitable
155+
/// Convert the given \p mdistanceUnit into its text representation suitable
156156
/// to be used with the currentUnit MEL command. Invalid units return "cm".
157157
MAYAUSD_CORE_PUBLIC
158158
MString ConvertMDistanceUnitToText(const MDistance::Unit mdistanceUnit);

plugin/adsk/scripts/mayaUSDRegisterStrings.mel

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,24 @@ global proc mayaUSDRegisterStrings()
4646
register("kLabelStage", "Stage");
4747
register("kLabelStageSource", "Stage Source");
4848
register("kLabelStageDisplay", "Stage Display");
49+
register("kStageAdvancedLabel", "Advanced");
50+
register("kStageAxisUnitConversionLabel", "Axis & Unit Conversion");
51+
register("kStageUpAxisLabel", "Up Axis");
52+
register("kStageUpAxisAnn", "If selected, when an up axis mismatch is detected\n" +
53+
"between the imported data and your scene preferences,\n" +
54+
"an automatic correction will be performed.");
55+
register("kStageUnitLabel", "Unit");
56+
register("kStageUnitAnn", "If selected, when a unit mismatch is detected\n" +
57+
"between the imported data and your scene preferences,\n" +
58+
"an automatic correction will be performed.");
59+
register("kStageAxisAndUnitMethod", "Method");
60+
// Note: initial <b> is used to force Qt to render the text as HTML.
61+
register("kStageAxisAndUnitMethodAnn", "<b></b>Select the method for axis/unit conversions.<br/>" +
62+
"<br/>" +
63+
"<b>Rotate/Scale</b>: Rotate/Scale the stage.<br/>" +
64+
"<b>Overwrite Maya Preferences</b>: Update Maya's axis/unit preferences based on the imported data.");
65+
register("kStageAxisAndUnitRotateScale", "Rotate/Scale");
66+
register("kStageAxisAndUnitOverwritePrefs", "Overwrite Maya Preferences");
4967
register("kLoad", "Load");
5068
register("kLoadPayloads", "Load Payloads:");
5169
register("kLoadPayloadsAnn", "When on, loads all prims marked as payloads. When off, all prims marked as payloads and their children are not loaded.");

plugin/adsk/scripts/mayaUsdTranslatorExport.mel

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1333,8 +1333,7 @@ global proc int mayaUsdTranslatorExport (string $parent,
13331333
}
13341334

13351335
if ($canControlUpAxisAndUnit) {
1336-
int $collapse = stringArrayContains("axisAndUnit", $expandedSections) ? false : true;
1337-
frameLayout -label `getMayaUsdString("kExportAxisAndUnitLbl")` -collapsable true -collapse $collapse axisAndUnitFrameLayout;
1336+
frameLayout -label `getMayaUsdString("kExportAxisAndUnitLbl")` -collapsable true -collapse false axisAndUnitFrameLayout;
13381337
separator -style "none";
13391338

13401339
optionMenuGrp -l `getMayaUsdString("kExportUpAxisLbl")` -annotation `getMayaUsdString("kExportUpAxisAnn")` upAxisPopup;

plugin/adsk/scripts/mayaUsdTranslatorImport.mel

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,10 @@ global proc mayaUsdTranslatorImport_SetFromOptions(string $currentOptions, int $
410410
intFieldGrp -e -value2 $endTime -en2 $enable mayaUsdTranslator_CustomFrameRange;
411411
} else if ($optionBreakDown[0] == "upAxis") {
412412
mayaUsdTranslatorImport_SetCheckBoxGrp($optionBreakDown[1], $enable, "mayaUsdTranslator_ImportUpAxisCheckBox");
413+
mayaUsdTranslatorImport_upAxisUnitCB();
413414
} else if ($optionBreakDown[0] == "unit") {
414415
mayaUsdTranslatorImport_SetCheckBoxGrp($optionBreakDown[1], $enable, "mayaUsdTranslator_ImportUnitCheckBox");
416+
mayaUsdTranslatorImport_upAxisUnitCB();
415417
} else if ($optionBreakDown[0] == "axisAndUnitMethod") {
416418
mayaUsdTranslatorImport_SetOptionMenuByAnnotation($optionBreakDown[1], $enable, "mayaUsdTranslator_ImportkImportAxisAndUnitMethodMenu");
417419
} else if ($optionBreakDown[0] == "useCustomFrameRange") {
@@ -519,7 +521,7 @@ global proc int mayaUsdTranslatorImport (string $parent,
519521
// menuItem -label "Object space";
520522
// menuItem -label "World space";
521523
// optionMenuGrp -e -sl 1 mayaUsdTranslator_CoordSystemOptionMenu;
522-
frameLayout -label `getMayaUsdString("kImportMaterialsLbl")` materialsFrameLayout;
524+
frameLayout -label `getMayaUsdString("kImportMaterialsLbl")` -collapsable true -collapse false materialsFrameLayout;
523525
separator -style "none";
524526
checkBoxGrp -label "" -label1 `getMayaUsdString("kImportMaterialsLbl")` -cw 1 $cw1 -value1 1 -ann `getMayaUsdString("kImportMaterialsAnn")` -cc ("mayaUsdTranslatorImport_MaterialsCB") mayaUsdTranslator_MaterialsCheckBox;
525527

@@ -565,7 +567,7 @@ global proc int mayaUsdTranslatorImport (string $parent,
565567
// menuItem "Custom";
566568
// optionMenuGrp -e -sl 2 mayaUsdTranslator_IncludeCustomAttribOptionMenu;
567569

568-
frameLayout -label "Animation" animationFrameLayout;
570+
frameLayout -label "Animation" -collapsable true -collapse false animationFrameLayout;
569571
separator -style "none";
570572
checkBoxGrp -label "" -label1 `getMayaUsdString("kImportAnimationDataLbl")` -cw 1 $cw1 -cc ("mayaUsdTranslatorImport_AnimationCB") mayaUsdTranslator_AnimDataCheckBox;
571573

@@ -580,18 +582,26 @@ global proc int mayaUsdTranslatorImport (string $parent,
580582
separator -style "none";
581583
setParent ..;
582584

583-
frameLayout -label "Advanced" advancedFrameLayout;
585+
frameLayout -label "Advanced" -collapsable true -collapse true advancedFrameLayout;
584586
separator -style "none";
585587
checkBoxGrp -label "" -label1 `getMayaUsdString("kImportToInstanceOpt")` -cw 1 $cw1 -value1 1 -ann `getMayaUsdString("kImportToInstanceAnn")` mayaUsdTranslator_ImportInstancesCheckBox;
586588
separator -style "none";
587589

588-
frameLayout -label `getMayaUsdString("kImportAxisAndUnit")` axisAndUnitFrameLayout;
589-
checkBoxGrp -label "" -label1 `getMayaUsdString("kImportUpAxis")` -cw 1 $cw1 -value1 1 -ann `getMayaUsdString("kImportUpAxisAnn")` mayaUsdTranslator_ImportUpAxisCheckBox;
590-
checkBoxGrp -label "" -label1 `getMayaUsdString("kImportUnit")` -cw 1 $cw1 -value1 1 -ann `getMayaUsdString("kImportUnitAnn")` mayaUsdTranslator_ImportUnitCheckBox;
590+
frameLayout -label `getMayaUsdString("kImportAxisAndUnit")` -collapsable true -collapse false axisAndUnitFrameLayout;
591+
separator -style "none";
592+
checkBoxGrp -label "" -label1 `getMayaUsdString("kImportUpAxis")` -ann `getMayaUsdString("kImportUpAxisAnn")`
593+
-cw 1 $cw1 -value1 1
594+
-cc ("mayaUsdTranslatorImport_upAxisUnitCB")
595+
mayaUsdTranslator_ImportUpAxisCheckBox;
596+
checkBoxGrp -label "" -label1 `getMayaUsdString("kImportUnit")` -ann `getMayaUsdString("kImportUnitAnn")`
597+
-cw 1 $cw1 -value1 1
598+
-cc ("mayaUsdTranslatorImport_upAxisUnitCB")
599+
mayaUsdTranslator_ImportUnitCheckBox;
591600
optionMenuGrp -l `getMayaUsdString("kImportAxisAndUnitMethod")` -cw 1 $cw1 -ann `getMayaUsdString("kImportAxisAndUnitMethodAnn")` mayaUsdTranslator_ImportkImportAxisAndUnitMethodMenu;
592601
menuItem -l `getMayaUsdString("kImportAxisAndUnitRotateScale")` -ann "rotateScale";
593602
menuItem -l `getMayaUsdString("kImportAxisAndUnitAddTransform")` -ann "addTransform";
594603
menuItem -l `getMayaUsdString("kImportAxisAndUnitOverwritePrefs")` -ann "overwritePrefs";
604+
separator -style "none";
595605
setParent ..;
596606
setParent ..;
597607

@@ -677,6 +687,7 @@ global proc int mayaUsdTranslatorImport (string $parent,
677687
}
678688

679689
mayaUsdTranslatorImport_AnimationCB();
690+
mayaUsdTranslatorImport_upAxisUnitCB();
680691
return $bResult;
681692
}
682693

@@ -717,6 +728,14 @@ global proc mayaUsdTranslatorImport_AnimationCB()
717728
}
718729
}
719730

731+
// Call when the up-axis or unit checkbox are modified bythe user.
732+
global proc mayaUsdTranslatorImport_upAxisUnitCB()
733+
{
734+
int $upAxisEnabled = `checkBoxGrp -q -value1 mayaUsdTranslator_ImportUpAxisCheckBox`;
735+
int $unitEnabled = `checkBoxGrp -q -value1 mayaUsdTranslator_ImportUnitCheckBox`;
736+
optionMenuGrp -e -en ($unitEnabled + $upAxisEnabled) mayaUsdTranslator_ImportkImportAxisAndUnitMethodMenu;
737+
}
738+
720739
global proc mayaUsdTranslatorImport_MaterialsCB()
721740
{
722741
if (`checkBoxGrp -q -value1 mayaUsdTranslator_MaterialsCheckBox` == 1) {

0 commit comments

Comments
 (0)