def setUp(self): if not hasattr(self, 'setupComplete'): self.layerFileNames = [ 'src/Particles_Splash.101.usd', 'src/Particles_Splash.102.usd', 'src/Particles_Splash.103.usd', 'src/Particles_Splash.104.usd', 'src/Particles_Splash.105.usd', 'src/Particles_Splash.106.usd', 'src/Particles_Splash.107.usd', 'src/Particles_Splash.108.usd', 'src/PTS_dev.1.usd', 'src/PTS_dev.2.usd', 'src/PTS_dev.3.usd', 'src/PTS_dev.4.usd', 'src/PTS_dev.5.usd', 'src/PTS_dev.6.usd', 'src/PTS_dev.7.usd', 'src/PTS_dev.8.usd', 'src/PTS_dev.9.usd', 'src/PTS_dev.10.usd', 'src/PTS_dev.11.usd', 'src/PTS_dev.12.usd', 'src/PTS_dev.13.usd', 'src/PTS_dev.14.usd', 'src/PTS_dev.15.usd', 'src/PTS_dev.16.usd', 'src/PTS_dev.17.usd', 'src/PTS_dev.18.usd', 'src/PTS_dev.19.usd', 'src/PTS_dev.20.usd', 'src/PTS_dev.21.usd', 'src/PTS_dev.22.usd', 'src/PTS_dev.23.usd', 'src/PTS_dev.24.usd' ] self.clipPath = Sdf.Path('/World/fx/Particles_Splash') self.baseName = 'testModelClips.usd' self.startTimeCode = 101 self.endTimeCode = 108 rootLayer = Sdf.Layer.FindOrOpen(self.baseName) self.rootLayer = rootLayer if rootLayer else Sdf.Layer.CreateNew( self.baseName) UsdUtils.StitchClips(self.rootLayer, self.layerFileNames[0:7], self.clipPath, self.startTimeCode, self.endTimeCode) self.setupComplete = True
def test_ExplicitEndCodes(self): start = 104 end = 105 resultLayer = Sdf.Layer.CreateNew('explicitEndCodes.usd') UsdUtils.StitchClips(resultLayer, self.layerFileNames[:7], self.clipPath, start, end) self.assertEqual(resultLayer.startTimeCode, start) self.assertEqual(resultLayer.endTimeCode, end)
def test_NumericalPrecisionLoss(self): rootLayerFile = 'numericalPrecision.usd' clipPath = Sdf.Path("/World/fx/points") rootLayer = Sdf.Layer.CreateNew(rootLayerFile) UsdUtils.StitchClips(rootLayer, self.layerFileNames[8:], clipPath) self.assertTrue(rootLayer) self.assertEqual(rootLayer.startTimeCode, 1.00000) # previously, the precision error was causing # us to end up with an end frame of 24.0006 self.assertEqual(rootLayer.endTimeCode, 24.000000)
def test_TopologySublayerAuthoring(self): resultLayer = Sdf.Layer.CreateNew('sublayerTopology.usd') UsdUtils.StitchClips(resultLayer, self.layerFileNames[:7], self.clipPath) self.assertEqual(list(resultLayer.subLayerPaths), ['./sublayerTopology.topology.usd']) resultLayer = Sdf.Layer.CreateNew('foo.usd') topLayer = Sdf.Layer.CreateNew('foo.topology.usd') UsdUtils.StitchClipsTemplate(resultLayer, topLayer, self.clipPath, 'asset.#.usd', 101, 120, 1) self.assertEqual(list(resultLayer.subLayerPaths), ['./foo.topology.usd'])
def test_FilePermissions(self): import os from pxr import Tf rootLayerFile = 'permissions.usd' clipPath = Sdf.Path('/World/fx/points') rootLayer = Sdf.Layer.CreateNew(rootLayerFile) os.system('chmod -w ' + rootLayerFile) try: UsdUtils.StitchClips(rootLayer, self.layerFileNames, clipPath) except Tf.ErrorException as tfError: print "Caught expected exception %s" % tfError else: self.assertTrue( False, "Failed to raise runtime error on unwritable file.") finally: os.system('chmod +w ' + rootLayerFile)
def test_FilePermissions(self): import os, stat from pxr import Tf rootLayerFile = 'permissions.usd' clipPath = Sdf.Path('/World/fx/points') rootLayer = Sdf.Layer.CreateNew(rootLayerFile) mode = stat.S_IMODE(os.stat(rootLayerFile).st_mode) os.chmod(rootLayerFile, mode & ~(stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH)) try: UsdUtils.StitchClips(rootLayer, self.layerFileNames, clipPath) except Tf.ErrorException as tfError: print "Caught expected exception %s" %tfError else: self.assertTrue(False, "Failed to raise runtime error on unwritable file." ) finally: os.chmod(rootLayerFile, mode)
def test_RelativeAssetPaths(self): import os rootLayerFile = 'relativePaths.usd' if os.path.isfile(rootLayerFile): os.remove(rootLayerFile) rootLayer = Sdf.Layer.CreateNew(rootLayerFile) self.assertTrue(rootLayer) localLayerNames = [os.path.relpath(i, os.getcwd()) for i in self.layerFileNames] UsdUtils.StitchClips(rootLayer, localLayerNames, self.clipPath) assetPaths = ( rootLayer.GetPrimAtPath(self.clipPath).GetInfo('clipAssetPaths')) # ensure all paths are relative import itertools self.assertTrue(not any([os.path.isabs(i.path) for i in assetPaths]))
def _checkMissingTemplateArg(argName, argValue): if not argValue: raise Tf.ErrorException('Error: %s must be specified ' 'when --templateMetadata is' % argName) _checkMissingTemplateArg('templatePath', results.templatePath) _checkMissingTemplateArg('endTimeCode', results.endTimeCode) _checkMissingTemplateArg('startTimeCode', results.startTimeCode) _checkMissingTemplateArg('stride', results.stride) UsdUtils.StitchClipsTopology(topologyLayer, results.usdFiles) UsdUtils.StitchClipsTemplate(outLayer, topologyLayer, results.clipPath, results.templatePath, results.startTimeCode, results.endTimeCode, results.stride) else: UsdUtils.StitchClips(outLayer, results.usdFiles, results.clipPath, results.startTimeCode, results.endTimeCode) if not results.noComment: outLayer.comment = 'Generated with ' + ' '.join(sys.argv) outLayer.Save() except Tf.ErrorException as e: # if something in the authoring fails, remove the output file if outLayerGenerated and os.path.isfile(results.out): os.remove(results.out) if topologyLayerGenerated and os.path.isfile(topologyLayerName): os.remove(topologyLayerName) sys.exit(e)
def test_CustomSetName(self): """ Test authoring with a custom set name 'bob' """ # template case resultLayer = Sdf.Layer.CreateNew('customSetName.usd') topLayer = Sdf.Layer.CreateNew('customSetName.topology.usd') UsdUtils.StitchClipsTemplate(resultLayer, topLayer, self.clipPath, 'asset.#.usd', 101, 120, 1, 0.3, 'bob') self.assertEqual(list(resultLayer.subLayerPaths), ['./customSetName.topology.usd']) self.assertEqual(resultLayer.endTimeCode, 120) self.assertEqual(resultLayer.startTimeCode, 101) prim = resultLayer.GetPrimAtPath('/World/fx/Particles_Splash') self.assertTrue('clips' in prim.GetMetaDataInfoKeys()) expectedValues = { 'templateStartTime': 101.0, 'templateStride': 1.0, 'templateActiveOffset': 0.3, 'primPath': '/World/fx/Particles_Splash', 'templateAssetPath': 'asset.#.usd', 'templateEndTime': 120.0 } # Ensure that our custom set name applied actualValues = prim.GetInfo('clips')['bob'] self.assertTrue(actualValues is not None) # Ensure all of our values were written out for k in [ 'templateStartTime', 'templateStride', 'templateEndTime', 'primPath', 'templateAssetPath' ]: self.assertEqual(expectedValues[k], actualValues[k]) # non template case resultLayer = Sdf.Layer.CreateNew('customSetNameNonTemplate.usd') UsdUtils.StitchClips(resultLayer, self.layerFileNames[:7], self.clipPath, clipSet='bob') self.assertEqual(resultLayer.startTimeCode, 101) self.assertEqual(resultLayer.endTimeCode, 107) self.assertEqual(list(resultLayer.subLayerPaths), ['./customSetNameNonTemplate.topology.usd']) prim = resultLayer.GetPrimAtPath('/World/fx/Particles_Splash') expectedValues = { 'active': Vt.Vec2dArray([(101.0, 0.0), (102.0, 1.0), (103.0, 2.0), (104.0, 3.0), (105.0, 4.0), (106.0, 5.0), (107.0, 6.0)]), 'times': Vt.Vec2dArray([(101.0, 101.0), (102.0, 102.0), (103.0, 103.0), (104.0, 104.0), (105.0, 105.0), (106.0, 106.0), (107.0, 107.0)]), 'manifestAssetPath': Sdf.AssetPath('./customSetNameNonTemplate.topology.usd'), 'assetPaths': Sdf.AssetPathArray([ Sdf.AssetPath('./src/Particles_Splash.101.usd'), Sdf.AssetPath('./src/Particles_Splash.102.usd'), Sdf.AssetPath('./src/Particles_Splash.103.usd'), Sdf.AssetPath('./src/Particles_Splash.104.usd'), Sdf.AssetPath('./src/Particles_Splash.105.usd'), Sdf.AssetPath('./src/Particles_Splash.106.usd'), Sdf.AssetPath('./src/Particles_Splash.107.usd') ]), 'primPath': '/World/fx/Particles_Splash' } # Ensure that our custom set name applied actualValues = prim.GetInfo('clips')['bob'] self.assertTrue(actualValues is not None) # Ensure all of our values were written out for k in [ 'active', 'times', 'manifestAssetPath', 'primPath', 'assetPaths' ]: self.assertEqual(expectedValues[k], actualValues[k])
results.startTimeCode, results.endTimeCode, results.stride, results.activeOffset, results.interpolateMissingClipValues, results.clipSet) else: if results.templatePath: raise Tf.ErrorException('Error: templatePath cannot be specified ' 'without --templateMetadata') if results.activeOffset: raise Tf.ErrorException('Error: activeOffset cannot be specified ' 'without --templateMetadata') if results.stride: raise Tf.ErrorException('Error: stride cannot be specified ' 'without --templateMetadata') UsdUtils.StitchClips(outLayer, results.usdFiles, results.clipPath, results.startTimeCode, results.endTimeCode, results.interpolateMissingClipValues, results.clipSet) if not results.noComment: outLayer.comment = 'Generated with ' + ' '.join(sys.argv) outLayer.Save() except Tf.ErrorException as e: # if something in the authoring fails, remove the output file if outLayerGenerated and os.path.isfile(results.out): os.remove(results.out) if topologyLayerGenerated and os.path.isfile(topologyLayerName): os.remove(topologyLayerName) sys.exit(e)
def testExportAsClip(self): """ Test that a maya scene exports to usd the same way if it is exported all at once, or in 5 frame clips and then stitched back together. """ # generate clip files and validate num samples on points attribute clipFiles = [] # first 5 frames have no animation usdFile = os.path.abspath('UsdExportAsClip_cube.001.usda') clipFiles.append(usdFile) cmds.usdExport(mergeTransformAndShape=True, file=usdFile, frameRange=(1, 5)) stage = Usd.Stage.Open(usdFile) self._ValidateNumSamples(stage, '/world/pCube1', 'points', 1) # next 5 frames have no animation usdFile = os.path.abspath('UsdExportAsClip_cube.005.usda') clipFiles.append(usdFile) cmds.usdExport(mergeTransformAndShape=True, file=usdFile, frameRange=(5, 10)) stage = Usd.Stage.Open(usdFile) self._ValidateNumSamples(stage, '/world/pCube1', 'points', 1) # next 5 frames have deformation animation usdFile = os.path.abspath('UsdExportAsClip_cube.010.usda') clipFiles.append(usdFile) frames = (10, 15) cmds.usdExport(mergeTransformAndShape=True, file=usdFile, frameRange=frames) stage = Usd.Stage.Open(usdFile) self._ValidateNumSamples(stage, '/world/pCube1', 'points', frames[1] + 1 - frames[0]) # next 5 frames have no animation usdFile = os.path.abspath('UsdExportAsClip_cube.015.usda') clipFiles.append(usdFile) cmds.usdExport(mergeTransformAndShape=True, file=usdFile, frameRange=(15, 20)) stage = Usd.Stage.Open(usdFile) self._ValidateNumSamples(stage, '/world/pCube1', 'points', 1) stitchedPath = os.path.abspath('result.usda') stitchedLayer = Sdf.Layer.CreateNew(stitchedPath) UsdUtils.StitchClips(stitchedLayer, clipFiles, '/world', 1, 20, 'default') # export a non clip version for comparison canonicalUsdFile = os.path.abspath('canonical.usda') cmds.usdExport(mergeTransformAndShape=True, file=canonicalUsdFile, frameRange=(1, 20)) print 'comparing: \nnormal: {}\nstitched: {}'.format( canonicalUsdFile, stitchedPath) canonicalStage = Usd.Stage.Open(canonicalUsdFile) clipsStage = Usd.Stage.Open(stitchedPath) # visible self._ValidateSamples(canonicalStage, clipsStage, '/world/pCube1', 'visibility', (0, 21)) # animated visibility self._ValidateSamples(canonicalStage, clipsStage, '/world/pCube2', 'visibility', (0, 21)) # hidden, non animated: self._ValidateSamples(canonicalStage, clipsStage, '/world/pCube4', 'visibility', (0, 21)) # constant points: self._ValidateSamples(canonicalStage, clipsStage, '/world/pCube2', 'points', (0, 21)) # blend shape driven animated points: self._ValidateSamples(canonicalStage, clipsStage, '/world/pCube3', 'points', (0, 21)) # animated points: self._ValidateSamples(canonicalStage, clipsStage, '/world/pCube1', 'points', (0, 21))
usd file was generated''') results = parser.parse_args() # verify the integrity of the inputs assert results.out is not None, "must specify output file(--out)" assert results.clipPath is not None, "must specify a clip path(--clipPath)" assert results.usdFiles is not None, "must specify clip files" if os.path.isfile(results.out): print "Warning: merging with current result layer" try: outLayer = Sdf.Layer.FindOrOpen(results.out) if not outLayer: outLayer = Sdf.Layer.CreateNew(results.out) if results.startTimeCode: results.startTimeCode = float(results.startTimeCode) UsdUtils.StitchClips(outLayer, results.usdFiles, results.clipPath, results.reuseExistingTopology, results.startTimeCode) if not results.noComment: outLayer.comment = 'Generated with ' + ' '.join(sys.argv) outLayer.Save() # if something in the authoring fails, remove the output file except Tf.ErrorException as e: print e sys.exit(1)
def testExportAsClip(self): """ Test that a maya scene exports to usd the same way if it is exported all at once, or in 5 frame clips and then stitched back together. """ # generate clip files and validate num samples on points attribute clipFiles = [] # first 5 frames have no animation usdFile = os.path.abspath('UsdExportAsClip_cube.001.usda') clipFiles.append(usdFile) cmds.usdExport(mergeTransformAndShape=True, file=usdFile, frameRange=(1, 5), sss=False) stage = Usd.Stage.Open(usdFile) self._ValidateNumSamples(stage, '/world/pCube1', 'points', 1) # next 5 frames have no animation usdFile = os.path.abspath('UsdExportAsClip_cube.005.usda') clipFiles.append(usdFile) cmds.usdExport(mergeTransformAndShape=True, file=usdFile, frameRange=(5, 10), sss=False) stage = Usd.Stage.Open(usdFile) self._ValidateNumSamples(stage, '/world/pCube1', 'points', 1) # next 5 frames have deformation animation usdFile = os.path.abspath('UsdExportAsClip_cube.010.usda') clipFiles.append(usdFile) frames = (10, 15) cmds.usdExport(mergeTransformAndShape=True, file=usdFile, frameRange=frames, sss=False) stage = Usd.Stage.Open(usdFile) self._ValidateNumSamples(stage, '/world/pCube1', 'points', frames[1] + 1 - frames[0]) # next 5 frames have no animation usdFile = os.path.abspath('UsdExportAsClip_cube.015.usda') clipFiles.append(usdFile) cmds.usdExport(mergeTransformAndShape=True, file=usdFile, frameRange=(15, 20), sss=False) stage = Usd.Stage.Open(usdFile) self._ValidateNumSamples(stage, '/world/pCube1', 'points', 1) stitchedPath = os.path.abspath('result.usda') stitchedLayer = Sdf.Layer.CreateNew(stitchedPath) # Clip stitching behavior changed significantly between core USD 20.05 # and 20.08. Beginning with 20.08, we need to pass an additional option # to ensure that authored time samples are held across gaps in value # clips. if Usd.GetVersion() > (0, 20, 5): self.assertTrue( UsdUtils.StitchClips(stitchedLayer, clipFiles, '/world', startFrame=1, endFrame=20, interpolateMissingClipValues=True, clipSet='default')) else: self.assertTrue( UsdUtils.StitchClips(stitchedLayer, clipFiles, '/world', startFrame=1, endFrame=20, clipSet='default')) # export a non clip version for comparison canonicalUsdFile = os.path.abspath('canonical.usda') cmds.usdExport(mergeTransformAndShape=True, file=canonicalUsdFile, frameRange=(1, 20), sss=False) print('comparing: \nnormal: {}\nstitched: {}'.format( canonicalUsdFile, stitchedPath)) canonicalStage = Usd.Stage.Open(canonicalUsdFile) clipsStage = Usd.Stage.Open(stitchedPath) # visible self._ValidateSamples(canonicalStage, clipsStage, '/world/pCube1', 'visibility', (0, 21)) # animated visibility self._ValidateSamples(canonicalStage, clipsStage, '/world/pCube2', 'visibility', (0, 21)) # hidden, non animated: self._ValidateSamples(canonicalStage, clipsStage, '/world/pCube4', 'visibility', (0, 21)) # constant points: self._ValidateSamples(canonicalStage, clipsStage, '/world/pCube2', 'points', (0, 21)) # blend shape driven animated points: self._ValidateSamples(canonicalStage, clipsStage, '/world/pCube3', 'points', (0, 21)) # animated points: self._ValidateSamples(canonicalStage, clipsStage, '/world/pCube1', 'points', (0, 21))