Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EMSUSD-943 handle up-axis and units when staging a USD file #3945

Merged
merged 2 commits into from
Oct 10, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/mayaUsd/resources/scripts/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ list(APPEND scripts_src
mayaUsdMergeToUSDOptions.py
mayaUsdMergeToUsd.py
mayaUsdOptions.py
mayaUsdStageConversion.py
mayaUsdUtils.py
mayaUsdMayaReferenceUtils.py
)
Expand Down
5 changes: 5 additions & 0 deletions lib/mayaUsd/resources/scripts/mayaUsdLibRegisterStrings.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ def mayaUsdLibRegisterStrings():
register('kMenuCacheToUsd', 'Cache to USD...')
register('kMenuMergeMayaEdits', 'Merge Maya Edits to USD');

# mayaUsdStageConversion.py
register("kStageConversionUnknownMethod", "Unknown stage conversion method: %s")
register("kStageConversionSuccessful", "Mismatching axis/unit have been converted for accurate scale.")


def registerPluginResource(pluginId, stringId, resourceStr):
'''See registerPluginResource.mel in Maya.
Expand Down
135 changes: 135 additions & 0 deletions lib/mayaUsd/resources/scripts/mayaUsdStageConversion.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import maya.cmds as _cmds
import maya.api.OpenMaya as _om
import mayaUsd.ufe as _ufe

from mayaUsdLibRegisterStrings import getMayaUsdLibString as _getMayaUsdLibString

from pxr import UsdGeom as _UsdGeom


def convertUpAxisAndUnit(shapeNode, convertUpAxis, convertUnit, conversionMethod):
'''
Edit the USD stage associated with the given Maya stage proxy node to
convert the up-axis or the units used to match what is in the USD file
with what Maya is using.
'''
# If neither up-axis nor unit are requested to be modified, return immediately.
conversionInfo = StageConversionInfo(shapeNode, convertUpAxis, convertUnit)
if not conversionInfo.needUnitsConversion and not conversionInfo.needUpAxisConversion:
return

resultMsg = _getMayaUsdLibString("kStageConversionSuccessful")

if conversionMethod.lower() == 'rotatescale':
convertUpAxisAndUnitByModifyingStage(conversionInfo)
elif conversionMethod.lower() == 'overwriteprefs':
convertUpAxisAndUnitByModifyingPrefs(conversionInfo)
else:
resultMsg = _getMayaUsdLibString("kStageConversionUnknownMethod") % conversionMethod

print(resultMsg)


class StageConversionInfo:
'''
Analyze the contents of the USD file and compare it to the Maya settings
to determine what actions need to be done to match them.
'''

@staticmethod
def _isMayaUpAxisZ():
return _cmds.upAxis(query=True, axis=True).lower() == 'z'

@staticmethod
def _isUsdUpAxisZ(stage):
return _UsdGeom.GetStageUpAxis(stage).lower() == 'z'

_mayaToMetersPerUnit = {
_om.MDistance.kInches : _UsdGeom.LinearUnits.inches,
_om.MDistance.kFeet : _UsdGeom.LinearUnits.feet,
_om.MDistance.kYards : _UsdGeom.LinearUnits.yards,
_om.MDistance.kMiles : _UsdGeom.LinearUnits.miles,
_om.MDistance.kMillimeters : _UsdGeom.LinearUnits.millimeters,
_om.MDistance.kCentimeters : _UsdGeom.LinearUnits.centimeters,
_om.MDistance.kKilometers : _UsdGeom.LinearUnits.kilometers,
_om.MDistance.kMeters : _UsdGeom.LinearUnits.meters,
}

@staticmethod
def _convertMayaUnitToMetersPerUnit(mayaUnits):
if mayaUnits not in StageConversionInfo._mayaToMetersPerUnit:
return _UsdGeom.LinearUnits.centimeters
return StageConversionInfo._mayaToMetersPerUnit[mayaUnits]

_metersPerUnitToMayaUnitName = {
_UsdGeom.LinearUnits.inches : "inch",
_UsdGeom.LinearUnits.feet : "foot",
_UsdGeom.LinearUnits.yards : "yard",
_UsdGeom.LinearUnits.miles : "mile",
_UsdGeom.LinearUnits.millimeters : "mm",
_UsdGeom.LinearUnits.centimeters : "cn",
pierrebai-adsk marked this conversation as resolved.
Show resolved Hide resolved
_UsdGeom.LinearUnits.kilometers : "km",
_UsdGeom.LinearUnits.meters : "m",
}

@staticmethod
def _convertMetersPerUnitToMayaUnitName(metersPerUnit):
if metersPerUnit not in StageConversionInfo._metersPerUnitToMayaUnitName:
return "cm"
return StageConversionInfo._metersPerUnitToMayaUnitName[metersPerUnit]

@staticmethod
def _getMayaMetersPerUnit():
mayaUnits = _om.MDistance.internalUnit()
return StageConversionInfo._convertMayaUnitToMetersPerUnit(mayaUnits)

@staticmethod
def _getUsdMetersPerUnit(stage):
return _UsdGeom.GetStageMetersPerUnit(stage)

@staticmethod
def _getStageFromShapeNode(shapeNode):
res = _cmds.ls(shapeNode, l=True)
fullStageName = res[0]
return _ufe.getStage(fullStageName)

def __init__(self, shapeNode, convertUpAxis, convertUnit):
self.shapeNode = shapeNode
self.stage = self._getStageFromShapeNode(shapeNode)

self.isMayaUpAxisZ = self._isMayaUpAxisZ()
self.isUsdUpAxisZ = self._isUsdUpAxisZ(self.stage)
self.needUpAxisConversion = convertUpAxis and (self.isMayaUpAxisZ != self.isUsdUpAxisZ)

self.mayaMetersPerUnit = self._getMayaMetersPerUnit()
self.usdMetersPerUnit = self._getUsdMetersPerUnit(self.stage)
self.needUnitsConversion = convertUnit and (self.mayaMetersPerUnit != self.usdMetersPerUnit)


def convertUpAxisAndUnitByModifyingStage(conversionInfo):
'''
Handle the differences of up-axis and units from the USD file by modifying
the Maya proxy shape node transform to compensate for the differences.
'''
if conversionInfo.needUpAxisConversion:
angle = 90 if conversionInfo.isMayaUpAxisZ else -90
_cmds.rotate(angle, 0, 0, conversionInfo.shapeNode, relative=True, euler=True, pivot=(0, 0, 0), forceOrderXYZ=True)

if conversionInfo.needUnitsConversion:
factor = conversionInfo.usdMetersPerUnit / conversionInfo.mayaMetersPerUnit
_cmds.scale(factor, factor, factor, conversionInfo.shapeNode, relative=True, pivot=(0, 0, 0), scaleXYZ=True)


def convertUpAxisAndUnitByModifyingPrefs(conversionInfo):
'''
Handle the differences of up-axis and units from the USD file by modifying
the Maya preferences to match the USD file.
'''
if conversionInfo.needUpAxisConversion:
newAxis = 'z' if conversionInfo.isUsdUpAxisZ else 'y'
_cmds.upAxis(axis=newAxis)

if conversionInfo.needUnitsConversion:
newUnit = conversionInfo._convertMetersPerUnitToMayaUnitName(conversionInfo.usdMetersPerUnit)
_cmds.currentUnit(linear=newUnit)

2 changes: 1 addition & 1 deletion lib/mayaUsd/utils/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ double ConvertMDistanceUnitToUsdGeomLinearUnit(const MDistance::Unit mdistanceUn
MAYAUSD_CORE_PUBLIC
MDistance::Unit ConvertUsdGeomLinearUnitToMDistanceUnit(const double linearUnit);

/// Convert the given \p mdistanceYnit into its text representation suitable
/// Convert the given \p mdistanceUnit into its text representation suitable
/// to be used with the currentUnit MEL command. Invalid units return "cm".
MAYAUSD_CORE_PUBLIC
MString ConvertMDistanceUnitToText(const MDistance::Unit mdistanceUnit);
Expand Down
18 changes: 18 additions & 0 deletions plugin/adsk/scripts/mayaUSDRegisterStrings.mel
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,24 @@ global proc mayaUSDRegisterStrings()
register("kLabelStage", "Stage");
register("kLabelStageSource", "Stage Source");
register("kLabelStageDisplay", "Stage Display");
register("kStageAdvancedLabel", "Advanced");
register("kStageAxisUnitConversionLabel", "Axis & Unit Conversion");
register("kStageUpAxisLabel", "Up Axis");
register("kStageUpAxisAnn", "If selected, when an up axis mismatch is detected\n" +
"between the imported data and your scene preferences,\n" +
"an automatic correction will be performed.");
register("kStageUnitLabel", "Unit");
register("kStageUnitAnn", "If selected, when a unit mismatch is detected\n" +
"between the imported data and your scene preferences,\n" +
"an automatic correction will be performed.");
register("kStageAxisAndUnitMethod", "Method");
// Note: initial <b> is used to force Qt to render the text as HTML.
register("kStageAxisAndUnitMethodAnn", "<b></b>Select the method for axis/unit conversions.<br/>" +
"<br/>" +
"<b>Rotate/Scale</b>: Rotate/Scale the stage.<br/>" +
"<b>Overwrite Maya Preferences</b>: Update Maya's axis/unit preferences based on the imported data.");
register("kStageAxisAndUnitRotateScale", "Rotate/Scale");
register("kStageAxisAndUnitOverwritePrefs", "Overwrite Maya Preferences");
register("kLoad", "Load");
register("kLoadPayloads", "Load Payloads:");
register("kLoadPayloadsAnn", "When on, loads all prims marked as payloads. When off, all prims marked as payloads and their children are not loaded.");
Expand Down
3 changes: 1 addition & 2 deletions plugin/adsk/scripts/mayaUsdTranslatorExport.mel
Original file line number Diff line number Diff line change
Expand Up @@ -1333,8 +1333,7 @@ global proc int mayaUsdTranslatorExport (string $parent,
}

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

optionMenuGrp -l `getMayaUsdString("kExportUpAxisLbl")` -annotation `getMayaUsdString("kExportUpAxisAnn")` upAxisPopup;
Expand Down
31 changes: 25 additions & 6 deletions plugin/adsk/scripts/mayaUsdTranslatorImport.mel
Original file line number Diff line number Diff line change
Expand Up @@ -410,8 +410,10 @@ global proc mayaUsdTranslatorImport_SetFromOptions(string $currentOptions, int $
intFieldGrp -e -value2 $endTime -en2 $enable mayaUsdTranslator_CustomFrameRange;
} else if ($optionBreakDown[0] == "upAxis") {
mayaUsdTranslatorImport_SetCheckBoxGrp($optionBreakDown[1], $enable, "mayaUsdTranslator_ImportUpAxisCheckBox");
mayaUsdTranslatorImport_upAxisUnitCB();
} else if ($optionBreakDown[0] == "unit") {
mayaUsdTranslatorImport_SetCheckBoxGrp($optionBreakDown[1], $enable, "mayaUsdTranslator_ImportUnitCheckBox");
mayaUsdTranslatorImport_upAxisUnitCB();
} else if ($optionBreakDown[0] == "axisAndUnitMethod") {
mayaUsdTranslatorImport_SetOptionMenuByAnnotation($optionBreakDown[1], $enable, "mayaUsdTranslator_ImportkImportAxisAndUnitMethodMenu");
} else if ($optionBreakDown[0] == "useCustomFrameRange") {
Expand Down Expand Up @@ -519,7 +521,7 @@ global proc int mayaUsdTranslatorImport (string $parent,
// menuItem -label "Object space";
// menuItem -label "World space";
// optionMenuGrp -e -sl 1 mayaUsdTranslator_CoordSystemOptionMenu;
frameLayout -label `getMayaUsdString("kImportMaterialsLbl")` materialsFrameLayout;
frameLayout -label `getMayaUsdString("kImportMaterialsLbl")` -collapsable true -collapse false materialsFrameLayout;
separator -style "none";
checkBoxGrp -label "" -label1 `getMayaUsdString("kImportMaterialsLbl")` -cw 1 $cw1 -value1 1 -ann `getMayaUsdString("kImportMaterialsAnn")` -cc ("mayaUsdTranslatorImport_MaterialsCB") mayaUsdTranslator_MaterialsCheckBox;

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

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

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

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

frameLayout -label `getMayaUsdString("kImportAxisAndUnit")` axisAndUnitFrameLayout;
checkBoxGrp -label "" -label1 `getMayaUsdString("kImportUpAxis")` -cw 1 $cw1 -value1 1 -ann `getMayaUsdString("kImportUpAxisAnn")` mayaUsdTranslator_ImportUpAxisCheckBox;
checkBoxGrp -label "" -label1 `getMayaUsdString("kImportUnit")` -cw 1 $cw1 -value1 1 -ann `getMayaUsdString("kImportUnitAnn")` mayaUsdTranslator_ImportUnitCheckBox;
frameLayout -label `getMayaUsdString("kImportAxisAndUnit")` -collapsable true -collapse false axisAndUnitFrameLayout;
separator -style "none";
checkBoxGrp -label "" -label1 `getMayaUsdString("kImportUpAxis")` -ann `getMayaUsdString("kImportUpAxisAnn")`
-cw 1 $cw1 -value1 1
-cc ("mayaUsdTranslatorImport_upAxisUnitCB")
mayaUsdTranslator_ImportUpAxisCheckBox;
checkBoxGrp -label "" -label1 `getMayaUsdString("kImportUnit")` -ann `getMayaUsdString("kImportUnitAnn")`
-cw 1 $cw1 -value1 1
-cc ("mayaUsdTranslatorImport_upAxisUnitCB")
mayaUsdTranslator_ImportUnitCheckBox;
optionMenuGrp -l `getMayaUsdString("kImportAxisAndUnitMethod")` -cw 1 $cw1 -ann `getMayaUsdString("kImportAxisAndUnitMethodAnn")` mayaUsdTranslator_ImportkImportAxisAndUnitMethodMenu;
menuItem -l `getMayaUsdString("kImportAxisAndUnitRotateScale")` -ann "rotateScale";
menuItem -l `getMayaUsdString("kImportAxisAndUnitAddTransform")` -ann "addTransform";
menuItem -l `getMayaUsdString("kImportAxisAndUnitOverwritePrefs")` -ann "overwritePrefs";
separator -style "none";
setParent ..;
setParent ..;

Expand Down Expand Up @@ -677,6 +687,7 @@ global proc int mayaUsdTranslatorImport (string $parent,
}

mayaUsdTranslatorImport_AnimationCB();
mayaUsdTranslatorImport_upAxisUnitCB();
return $bResult;
}

Expand Down Expand Up @@ -717,6 +728,14 @@ global proc mayaUsdTranslatorImport_AnimationCB()
}
}

// Call when the up-axis or unit checkbox are modified bythe user.
global proc mayaUsdTranslatorImport_upAxisUnitCB()
{
int $upAxisEnabled = `checkBoxGrp -q -value1 mayaUsdTranslator_ImportUpAxisCheckBox`;
int $unitEnabled = `checkBoxGrp -q -value1 mayaUsdTranslator_ImportUnitCheckBox`;
optionMenuGrp -e -en ($unitEnabled + $upAxisEnabled) mayaUsdTranslator_ImportkImportAxisAndUnitMethodMenu;
}

global proc mayaUsdTranslatorImport_MaterialsCB()
{
if (`checkBoxGrp -q -value1 mayaUsdTranslator_MaterialsCheckBox` == 1) {
Expand Down
Loading