-
Notifications
You must be signed in to change notification settings - Fork 202
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
Initial cache to USD test. #2081
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
# | ||
# Copyright 2022 Autodesk | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
|
||
import mayaUsd | ||
import maya.cmds as cmds | ||
|
||
import re | ||
|
||
def turnOnAnimation(textOptions): | ||
return re.sub(r'animation=.', 'animation=1', textOptions) | ||
|
||
def getDefaultExportOptions(): | ||
# Animation is always on for cache to USD. | ||
return turnOnAnimation(cmds.translator('USD Export', query=True, do=True)) | ||
|
||
def getCacheCreationOptions(exportOptions, cacheFile, cachePrimName, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Utilities to centralize cache option creation in Python. |
||
payloadOrReference, listEditType, | ||
variantSetName = None, variantName = None): | ||
|
||
defineInVariant = 0 if variantSetName is None else 1 | ||
|
||
userArgs = mayaUsd.lib.Util.getDictionaryFromEncodedOptions(exportOptions) | ||
|
||
userArgs['rn_layer'] = cacheFile | ||
userArgs['rn_primName'] = cachePrimName | ||
userArgs['rn_defineInVariant'] = defineInVariant | ||
userArgs['rn_payloadOrReference'] = payloadOrReference | ||
userArgs['rn_listEditType'] = listEditType | ||
|
||
if defineInVariant: | ||
userArgs['rn_variantSetName'] = variantSetName | ||
userArgs['rn_variantName'] = variantName | ||
|
||
return userArgs |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
import maya.mel as mel | ||
|
||
import mayaUsd | ||
from mayaUsd.lib import cacheToUsd | ||
|
||
from mayaUsdLibRegisterStrings import getMayaUsdLibString | ||
import mayaUsdMayaReferenceUtils as mayaRefUtils | ||
|
@@ -32,7 +33,7 @@ | |
kDefaultCachePrimName = 'Cache1' | ||
|
||
# Cache options in string format, for MEL mayaUsdTranslatorExport() consumption. | ||
_cacheOptions = None | ||
_cacheExportOptions = None | ||
|
||
# Dag path corresponding to pulled prim. This is a Maya transform node that is | ||
# not in the Maya reference itself, but is its parent. | ||
|
@@ -181,22 +182,22 @@ def fileOptionsTabPage(tabLayout): | |
# USD file option controls will be parented under this layout. | ||
# resultCallback not called on "post", is therefore an empty string. | ||
fileOptionsScroll = cmds.columnLayout('fileOptionsScroll') | ||
mel.eval('mayaUsdTranslatorExport("fileOptionsScroll", "post=all;!animation-data", "' + getCacheOptions() + '", "")') | ||
mel.eval('mayaUsdTranslatorExport("fileOptionsScroll", "post=all;!animation-data", "' + getCacheExportOptions() + '", "")') | ||
|
||
cacheFileUsdHierarchyOptions(topForm) | ||
|
||
cmds.setUITemplate(popTemplate=True) | ||
|
||
def getCacheOptions(): | ||
global _cacheOptions | ||
# Init on first use from "USD Export" translator. | ||
if _cacheOptions is None: | ||
_cacheOptions = cmds.translator('USD Export', query=True, do=True) | ||
return _cacheOptions | ||
def getCacheExportOptions(): | ||
global _cacheExportOptions | ||
if _cacheExportOptions is None: | ||
_cacheExportOptions = cacheToUsd.getDefaultExportOptions() | ||
return _cacheExportOptions | ||
|
||
def setCacheOptions(newCacheOptions): | ||
global _cacheOptions | ||
_cacheOptions = newCacheOptions | ||
global _cacheExportOptions | ||
# Animation is always on for cache to USD. | ||
_cacheExportOptions = cacheToUsd.turnOnAnimation(newCacheOptions) | ||
|
||
def cacheCreateUi(parent): | ||
cmds.setParent(parent) | ||
|
@@ -239,29 +240,27 @@ def cacheInitUi(parent, filterType): | |
def cacheCommitUi(parent, selectedFile): | ||
# Read data to set up cache. | ||
|
||
# The following call will set _cacheOptions. Initial settings not accessed | ||
# on "query", is therefore an empty string. | ||
# The following call will set _cacheExportOptions. Initial settings not | ||
# accessed on "query", is therefore an empty string. | ||
mel.eval('mayaUsdTranslatorExport("fileOptionsScroll", "query", "", "mayaUsdCacheMayaReference_setCacheOptions")') | ||
|
||
# Regardless of UI, animation is always on. | ||
cacheOptionsText = re.sub(r'animation=.', 'animation=1', getCacheOptions()) | ||
|
||
userArgs = mayaUsd.lib.Util.getDictionaryFromEncodedOptions(cacheOptionsText) | ||
|
||
primName = cmds.textFieldGrp('primNameText', query=True, text=True) | ||
defineInVariant = cmds.radioButtonGrp('variantRadioBtn', query=True, select=True) | ||
userArgs['rn_layer'] = selectedFile | ||
userArgs['rn_primName'] = primName | ||
userArgs['rn_defineInVariant'] = defineInVariant | ||
userArgs['rn_payloadOrReference'] = cmds.optionMenuGrp('compositionArcTypeMenu', query=True, value=True) | ||
userArgs['rn_listEditType'] = cmds.optionMenu('listEditedAsMenu', query=True, value=True) | ||
payloadOrReference = cmds.optionMenuGrp('compositionArcTypeMenu', query=True, value=True) | ||
listEditType = cmds.optionMenu('listEditedAsMenu', query=True, value=True) | ||
|
||
defineInVariant = cmds.radioButtonGrp('variantRadioBtn', query=True, select=True) | ||
if defineInVariant: | ||
userArgs['rn_variantSetName'] = cmds.optionMenu('variantSetMenu', query=True, value=True) | ||
variantSetName = cmds.optionMenu('variantSetMenu', query=True, value=True) | ||
variantName = cmds.optionMenu('variantNameMenu', query=True, value=True) | ||
if variantName == 'Create New': | ||
variantName = cmds.textField('variantNameText', query=True, text=True) | ||
userArgs['rn_variantName'] = variantName | ||
else: | ||
variantName = None | ||
variantSetName = None | ||
|
||
userArgs = cacheToUsd.getCacheCreationOptions( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Use new utility functions. |
||
getCacheExportOptions(), selectedFile, primName, payloadOrReference, | ||
listEditType, variantSetName, variantName) | ||
|
||
# Call push. | ||
if not mayaUsd.lib.PrimUpdaterManager.mergeToUsd(_mayaRefDagPath, userArgs): | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,12 +40,11 @@ class AddMayaReferenceTestCase(unittest.TestCase): | |
|
||
@classmethod | ||
def setUpClass(cls): | ||
fixturesUtils.readOnlySetUpClass(__file__, loadPlugin=False) | ||
if not cls.pluginsLoaded: | ||
cls.pluginsLoaded = mayaUtils.isMayaUsdPluginLoaded() | ||
fixturesUtils.setUpClass(__file__) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No need to create a Maya file in a temporary directory, using the fixture utils sets up a temporary directory for the test, and clears it out before running. Just use setUpClass() instead of readOnlySetUpClass(). Also (have seen this in a few places) why pass in loadPlugin=False to the fixturesUtils, then load the plugin separately? Just use the fixturesUtils service. |
||
|
||
# Create a pure Maya scene to reference in. | ||
cls.mayaSceneStr = cls.createSimpleMayaScene() | ||
import os | ||
cls.mayaSceneStr = mayaUtils.createSingleSphereMayaScene(os.getcwd()) | ||
|
||
@classmethod | ||
def tearDownClass(cls): | ||
|
@@ -58,19 +57,6 @@ def setUp(self): | |
self.proxyShapePathStr = mayaUsd_createStageWithNewLayer.createStageWithNewLayer() | ||
self.stage = mayaUsd.lib.GetPrim(self.proxyShapePathStr).GetStage() | ||
|
||
@staticmethod | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Factored out to mayaUtils.py for re-use. |
||
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 testDefault(self): | ||
'''Test the default options for Add Maya Reference. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
#!/usr/bin/env python | ||
|
||
# | ||
# Copyright 2022 Autodesk | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
# | ||
|
||
import fixturesUtils | ||
|
||
from mayaUtils import setMayaTranslation, setMayaRotation | ||
from usdUtils import createSimpleXformScene, mayaUsd_createStageWithNewLayer | ||
from ufeUtils import createItem, createHierarchy | ||
|
||
import mayaUsd.lib | ||
|
||
from mayaUsd.lib import cacheToUsd | ||
|
||
import mayaUtils | ||
import mayaUsd.ufe | ||
import mayaUsdAddMayaReference | ||
import mayaUsdMayaReferenceUtils as mayaRefUtils | ||
|
||
from pxr import Usd, UsdGeom, Sdf, Pcp | ||
|
||
from maya import cmds | ||
from maya import standalone | ||
from maya.api import OpenMaya as om | ||
|
||
import ufe | ||
|
||
import unittest | ||
|
||
from testUtils import assertVectorAlmostEqual, getTestScene | ||
|
||
import os | ||
|
||
class CacheToUsdTestCase(unittest.TestCase): | ||
'''Test cache to USD: commit edits done to a Maya reference back into USD. | ||
''' | ||
|
||
kDefaultNamespace = 'simpleSphere' | ||
|
||
@classmethod | ||
def setUpClass(cls): | ||
fixturesUtils.setUpClass(__file__) | ||
|
||
# Create a pure Maya scene to reference in. | ||
cls.mayaSceneStr = mayaUtils.createSingleSphereMayaScene() | ||
|
||
@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 testCacheToUsd(self): | ||
'''Cache edits on a pulled Maya reference prim back to USD.''' | ||
|
||
# Create a Maya reference prim using the defaults, under a | ||
# newly-created parent, without any variant sets. | ||
cacheParent = self.stage.DefinePrim('/CacheParent', 'Xform') | ||
cacheParentPathStr = self.proxyShapePathStr + ',/CacheParent' | ||
self.assertFalse(cacheParent.HasVariantSets()) | ||
|
||
mayaRefPrim = mayaUsdAddMayaReference.createMayaReferencePrim( | ||
cacheParentPathStr, self.mayaSceneStr, self.kDefaultNamespace) | ||
|
||
# The Maya reference prim is a child of the cache parent. | ||
cacheParentItem = createItem(cacheParentPathStr) | ||
mayaRefPrimPathStr = cacheParentPathStr + '/' + mayaRefPrim.GetName() | ||
mayaRefPrimItem = createItem(mayaRefPrimPathStr) | ||
cacheParentHier = ufe.Hierarchy.hierarchy(cacheParentItem) | ||
cacheParentChildren = cacheParentHier.children() | ||
|
||
self.assertTrue(len(cacheParentChildren), 1) | ||
self.assertEqual(cacheParentChildren[0], mayaRefPrimItem) | ||
|
||
# At this point no Maya reference node has been created. | ||
self.assertEqual(len(cmds.ls(type='reference')), 0) | ||
|
||
# testAddMayaReference tests Maya reference prim creation, so we do not | ||
# repeat these tests here. Edit the Maya reference prim as Maya, which | ||
# will create and load the corresponding Maya reference node. | ||
with mayaUsd.lib.OpUndoItemList(): | ||
self.assertTrue(mayaUsd.lib.PrimUpdaterManager.editAsMaya( | ||
mayaRefPrimPathStr)) | ||
|
||
# A Maya reference node has been created, and it is loaded. | ||
rns = cmds.ls(type='reference') | ||
rn = rns[0] | ||
self.assertEqual(len(rns), 1) | ||
self.assertTrue(cmds.referenceQuery(rn, isLoaded=True)) | ||
|
||
# The Maya reference prim has been replaced by a Maya transform, which | ||
# is a child of the cache parent. | ||
cacheParentChildren = cacheParentHier.children() | ||
self.assertTrue(len(cacheParentChildren), 1) | ||
mayaTransformItem = cacheParentChildren[0] | ||
self.assertEqual(mayaTransformItem.nodeType(), 'transform') | ||
|
||
# The child of the Maya transform is the top-level transform of the | ||
# referenced Maya scene. | ||
mayaTransformHier = createHierarchy(mayaTransformItem) | ||
mayaTransformChildren = mayaTransformHier.children() | ||
self.assertTrue(len(mayaTransformChildren), 1) | ||
sphereTransformItem = mayaTransformChildren[0] | ||
self.assertEqual(sphereTransformItem.nodeType(), 'transform') | ||
|
||
# As the sphereTransformItem is a pulled node, its path is a pure Maya | ||
# Dag path. Confirm that it is a referenced node. | ||
sphereTransformPath = sphereTransformItem.path() | ||
self.assertEqual(sphereTransformPath.nbSegments(), 1) | ||
self.assertEqual(sphereTransformPath.runTimeId(), 1) | ||
sphereTransformPathStr = ufe.PathString.string(sphereTransformPath) | ||
sphereTransformObj = om.MSelectionList().add(sphereTransformPathStr).getDagPath(0).node() | ||
self.assertTrue(om.MFnDependencyNode(sphereTransformObj).isFromReferencedFile) | ||
|
||
# Make an edit in Maya. | ||
(_, _, _, mayaMatrix) = \ | ||
setMayaTranslation(sphereTransformItem, om.MVector(4, 5, 6)) | ||
|
||
# Cache to USD, using a sibling prim and a payload composition arc. | ||
defaultExportOptions = cacheToUsd.getDefaultExportOptions() | ||
cacheFile = 'testCacheToUsd.usda' | ||
cachePrimName = 'cachePrimName' | ||
payloadOrReference = 'Payload' | ||
listEditType = 'Prepend' | ||
cacheOptions = cacheToUsd.getCacheCreationOptions( | ||
defaultExportOptions, cacheFile, cachePrimName, | ||
payloadOrReference, listEditType) | ||
|
||
# Before caching, the cache file does not exist. | ||
self.assertFalse(os.path.exists(cacheFile)) | ||
|
||
# Cache edits back to USD. | ||
with mayaUsd.lib.OpUndoItemList(): | ||
self.assertTrue(mayaUsd.lib.PrimUpdaterManager.mergeToUsd(ufe.PathString.string(mayaTransformItem.path()), cacheOptions)) | ||
|
||
# The Maya reference node has been unloaded. | ||
self.assertFalse(cmds.referenceQuery(rn, isLoaded=True)) | ||
|
||
# The USD cache file has been saved to the file system. | ||
self.assertTrue(os.path.exists(cacheFile)) | ||
|
||
# There is a new child under the cache parent, with the chosen cache | ||
# prim name. | ||
cacheParentChildren = cacheParentHier.children() | ||
self.assertTrue(len(cacheParentChildren), 2) | ||
cacheItem = next((c for c in cacheParentChildren if c.nodeName() == cachePrimName), None) | ||
self.assertIsNotNone(cacheItem) | ||
|
||
# The Maya transformation has been transferred to the USD cache, in the | ||
# sphere child of the cache item. | ||
cacheHier = createHierarchy(cacheItem) | ||
cacheChildren = cacheHier.children() | ||
sphereItem = next((c for c in cacheChildren if c.nodeType() == 'Mesh'), None) | ||
self.assertIsNotNone(sphereItem) | ||
|
||
sphereItemPathStr = ufe.PathString.string(sphereItem.path()) | ||
spherePrim = mayaUsd.ufe.ufePathToPrim(sphereItemPathStr) | ||
sphereXformOps = UsdGeom.Xformable(spherePrim).GetOrderedXformOps() | ||
self.assertEqual(len(sphereXformOps), 1) | ||
sphereXformOp = sphereXformOps[0] | ||
usdMatrix = sphereXformOp.GetOpTransform(mayaUsd.ufe.getTime(sphereItemPathStr)) | ||
|
||
mayaValues = [v for v in mayaMatrix] | ||
usdValues = [v for row in usdMatrix for v in row] | ||
|
||
assertVectorAlmostEqual(self, mayaValues, usdValues) | ||
|
||
# The cache prim has a payload composition arc. | ||
cachePrim = mayaUsd.ufe.ufePathToPrim(ufe.PathString.string(cacheItem.path())) | ||
query = Usd.PrimCompositionQuery(cachePrim) | ||
foundPayload = False | ||
for arc in query.GetCompositionArcs(): | ||
if arc.GetArcType() == Pcp.ArcTypePayload: | ||
foundPayload = True | ||
break | ||
|
||
self.assertTrue(foundPayload) | ||
|
||
if __name__ == '__main__': | ||
unittest.main(verbosity=2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
USD cache creation options moved out of UI code to separate Python module, under mayaUsd.lib