def _modifyPrimItems(self, methodName, refresh=True): ''' Perform the same modification action on an iterable of primItems as a single stage transaction. Parameters ---------- methodName : str modifying method of VariablePrimHelper Returns ------- List[VariablePrimHelper] modified items ''' # TODO: include, exclude updatedItems = [] with Sdf.ChangeBlock(): for item in self.primHelpers: if getattr(item, methodName)(refresh=False): updatedItems.append(item) if refresh: for item in updatedItems: item.refresh() return updatedItems
def commitData(self, editor): # TODO: Add an UndoBlock editor_index = None if self.indexWidget(self.currentIndex()) == editor: editor_index = self.currentIndex() if not editor_index: super(SelectionEditTreeView, self).commitData(editor) return selection = None if self._selection_edit_mode == SelectionEditTreeView.SelectedEditColumnsOnly: selection = [i for i in self.selectionModel().selectedIndexes() if i.column() == editor_index.column() and i != editor_index] # It's important to put all edits inside of an Sdf Change Block so they happen in a single pass and # no signals are emitted that may change state with Sdf.ChangeBlock(): super(SelectionEditTreeView, self).commitData(editor) if selection: value = editor.value for index in selection: # This try / except is covering for a very ugly and hard to isolate bug. It appears that when # commitData raises an exception, Qt holds onto some indices that should safely expire, triggering # a deferred but hard crash. I haven't found a reliable repro case, but this seems to make it # go away. A better solution likely involves better detection on the model side. try: self.model().setData(index, value, Qt.EditRole) except Exception: LOGGER.exception('Exception during multi-edit: {}'.format(traceback.format_exc()))
def _ChangeAndVerify(newValDict, expectSignificantChange, expectedTcps): # Just verify we have a tcps value and/or fps value to set self.assertTrue('tcps' in newValDict or 'fps' in newValDict) with Pcp._TestChangeProcessor(pcpCache) as cp: # Change block for when we're setting both fps and tcps with Sdf.ChangeBlock(): # Set the tcps value if present (None -> Clear) if 'tcps' in newValDict: val = newValDict['tcps'] if val is None: layer.ClearTimeCodesPerSecond() self.assertFalse(layer.HasTimeCodesPerSecond()) else: layer.timeCodesPerSecond = val self.assertTrue(layer.HasTimeCodesPerSecond()) # Set the fps value if present (None -> Clear) if 'fps' in newValDict: val = newValDict['fps'] if val is None: layer.ClearFramesPerSecond() self.assertFalse(layer.HasFramesPerSecond()) else: layer.framesPerSecond = val self.assertTrue(layer.HasFramesPerSecond()) # Verify whether the change processor logged a significant # change for the expected affected paths or not based on # whether we expect a significant change. if expectSignificantChange: self.assertEqual(cp.GetSignificantChanges(), affectedPaths) # A significant change will have invalidated our # prim's prim index. self.assertFalse(pcpCache.FindPrimIndex('/A')) # Recompute the new prim index (pi, err) = pcpCache.ComputePrimIndex('/A') else: # No significant should leave our prim's prim index # valid. self.assertEqual(cp.GetSignificantChanges(), []) pi = pcpCache.FindPrimIndex('/A') self.assertTrue(pi) refNode = pi.rootNode.children[0] ref2Node = refNode.children[0] # Verify the layer has the expected computed TCPS self.assertEqual(layer.timeCodesPerSecond, expectedTcps) # Verify the ref node offesets match the expected offsets # for the layer's expected computed TCPS. expectedOffsets = tcpsToExpecteOffsetsMap[expectedTcps] self.assertEqual(refNode.mapToRoot.timeOffset, expectedOffsets[0]) self.assertEqual(ref2Node.mapToRoot.timeOffset, expectedOffsets[1])
def create_using_sdf(): """Run the main execution of the current script.""" layer = Sdf.Layer.CreateAnonymous() # TODO : Adding / Removing this ChangeBlock doesn't change the time # much. Is a change block only useful when authoring opinions? # with Sdf.ChangeBlock(): _prepare_prim_specs_with_sdf(layer, PATHS) return layer.ExportToString()
def makeVisible(self): if self.canChangeVis(): # It is in general not kosher to use an Sdf.ChangeBlock around # operations at the Usd API level. We have carefully arranged # (with insider knowledge) to have only "safe" mutations # happening inside the ChangeBlock. We do this because # UsdImaging updates itself independently for each # Usd.Notice.ObjectsChanged it receives. We hope to eliminate # the performance need for this by addressing bug #121992 from pxr import Sdf with Sdf.ChangeBlock(): UsdGeom.Imageable(self.prim).MakeVisible() self.visChanged()
def testObservation(self): '''Test Transform3d observation interface. As of 11-Apr-2018 only implemented for USD objects. ''' # Select Ball_35 to move it. ball35Path = ufe.Path([ mayaUtils.createUfePathSegment("|transform1|proxyShape1"), usdUtils.createUfePathSegment("/Room_set/Props/Ball_35")]) ball35Item = ufe.Hierarchy.createItem(ball35Path) # Create a Transform3d interface for it. transform3d = ufe.Transform3d.transform3d(ball35Item) t3dObs = TestObserver() # We start off with no observers for Ball_35. self.assertFalse(ufe.Transform3d.hasObservers(ball35Path)) self.assertFalse(ufe.Transform3d.hasObserver(ball35Item, t3dObs)) self.assertEqual(ufe.Transform3d.nbObservers(ball35Item), 0) # Set the observer to observe Ball_35. ufe.Transform3d.addObserver(ball35Item, t3dObs) self.assertTrue(ufe.Transform3d.hasObservers(ball35Path)) self.assertTrue(ufe.Transform3d.hasObserver(ball35Item, t3dObs)) self.assertEqual(ufe.Transform3d.nbObservers(ball35Item), 1) # No notifications yet. self.assertEqual(t3dObs.notifications(), 0) # We only select the ball AFTER doing our initial tests because # the MayaUSD plugin creates a transform3d observer on selection # change to update the bounding box. ufe.GlobalSelection.get().append(ball35Item) # Move the prim. Use a change block to condense USD notifications into # one. Otherwise, as of 15-Jul-2021, the implementation of # UsdStage::_SetValue() notifies once for creation of the # 'xformOp:translate' attrSpec, at the end of an SdfChangeBlock, and # once for setting the 'xformOp:translate' field (in Sdf terminology), # again at the end of a separate SdfChangeBlock. ball35Prim = usdUtils.getPrimFromSceneItem(ball35Item) with Sdf.ChangeBlock(): ball35Prim.GetAttribute('xformOp:translate').Set( Gf.Vec3d(10, 20, 30)) # Notified. self.assertEqual(t3dObs.notifications(), 1)
def test_156222(self): from pxr import Sdf, Usd # Test that removing all instances for a prototype prim and adding a new # instance with the same instancing key as the prototype causes the new # instance to be assigned to the prototype. l = Sdf.Layer.CreateAnonymous('.usda') Sdf.CreatePrimInLayer(l, '/Ref') # The bug is non-deterministic because of threaded composition, # but it's easier to reproduce with more instance prims. numInstancePrims = 50 instancePrimPaths = [Sdf.Path('/Instance_{}'.format(i)) for i in range(numInstancePrims)] for path in instancePrimPaths: instancePrim = Sdf.CreatePrimInLayer(l, path) instancePrim.instanceable = True instancePrim.referenceList.Add(Sdf.Reference(primPath = '/Ref')) nonInstancePrim = Sdf.CreatePrimInLayer(l, '/NonInstance') nonInstancePrim.referenceList.Add(Sdf.Reference(primPath = '/Ref')) s = Usd.Stage.Open(l) self.assertEqual(len(s.GetPrototypes()), 1) # Check that the prototype prim is using one of the instanceable prim # index for its source. prototype = s.GetPrototypes()[0] prototypePath = prototype.GetPath() self.assertIn(prototype._GetSourcePrimIndex().rootNode.path, instancePrimPaths) # In a single change block, uninstance all of the instanceable prims, # but mark the non-instance prim as instanceable. with Sdf.ChangeBlock(): for path in instancePrimPaths: l.GetPrimAtPath(path).instanceable = False nonInstancePrim.instanceable = True # This should not cause a new prototype prim to be generated; instead, # the prototype prim should now be using the newly-instanced prim index # as its source. prototype = s.GetPrototypes()[0] self.assertEqual(prototype.GetPath(), prototypePath) self.assertEqual(prototype._GetSourcePrimIndex().rootNode.path, nonInstancePrim.path)
def commitData(self, editor): """override commit of data to allow us to edit multiple selected indexes """ # TODO: Add an UndoBlock if self.indexWidget(self.currentIndex()) == editor: editorIndex = self.currentIndex() else: editorIndex = None if not editorIndex: super(TreeView, self).commitData(editor) return if self.__selectionEditMode == TreeView.SelectedEditColumnsOnly: selection = [ i for i in self.selectionModel().selectedIndexes() if i.column() == editorIndex.column() and i != editorIndex ] else: selection = None # It's important to put all edits inside of an Sdf Change Block so # they happen in a single pass and no signals are emitted that may # change state with Sdf.ChangeBlock(): super(TreeView, self).commitData(editor) if selection: value = editor.value for index in selection: # This try / except is covering for a very ugly and hard # to isolate bug. It appears that when commitData # raises an exception, Qt holds onto some indices that # should safely expire, trigging a deferred but hard # crash. I haven't found a reliable repro case, but # this seems to make it go away. A better solution # likely involves better detection on the model side. try: self.model().setData(index, value, QtCore.Qt.EditRole) except Exception, e: # TODO: We should do something better than printing to # stderr print("Exception during multi-edit:", e, file=sys.stderr)
def main(): """Run the main execution of the current script.""" layer = Sdf.Layer.CreateAnonymous() paths = { Sdf.Path("/AndMore"), Sdf.Path("/AnotherOne"), Sdf.Path("/AnotherOne/AndAnother"), Sdf.Path("/More"), Sdf.Path("/OkayNoMore"), Sdf.Path("/SomeSphere"), Sdf.Path("/SomeSphere/InnerPrim"), Sdf.Path("/SomeSphere/InnerPrim/LastOne"), } prefixes = set(prefix for path in paths for prefix in path.GetPrefixes()) with Sdf.ChangeBlock(): for path in prefixes: prim_spec = Sdf.CreatePrimInLayer(layer, path) prim_spec.specifier = Sdf.SpecifierDef prim_spec.typeName = UsdGeom.Xform.__name__ print(layer.ExportToString())
def Do(self, context): with Sdf.ChangeBlock(): for prim in context.selectedPrims: prim.SetActive(False)
def ResetSessionVisibility(stage): session = stage.GetSessionLayer() from pxr import Sdf with Sdf.ChangeBlock(): _RemoveVisibilityRecursive(session.pseudoRoot)
def deactivate_selection(self): with Sdf.ChangeBlock(): prims = self._get_selected_prims() for prim in prims: prim.SetActive(False)
def clear_active_for_selection(self): with Sdf.ChangeBlock(): prims = self._get_selected_prims() for prim in prims: prim.ClearActive()
def Do(self): context = self.GetCurrentContext() with Sdf.ChangeBlock(): for prim in context.selectedPrims: prim.SetActive(False)
def _parseInstanceJSONFile(self, jsonFilename, subInstanceStageFilePath): # type: (str, str) -> None """ Create USD Prim instances from the given Element JSON file. """ with open(jsonFilename, 'r') as f: jsonData = json.load(f) layer = Sdf.Layer.CreateAnonymous(self.USDFileExtension) # Leverage the SDF API instead of the USD API in order to batch-create # Prims. This avoids fanning out change notifications, which results in # O(n2) performance and becomes *slow* when creating a large number of # instances -- which is the case here (sometimes upwards of a million # instances). with Sdf.ChangeBlock(): instancersPrimSpecPath = '/Instancers' instancersPrimSpec = Sdf.CreatePrimInLayer(layer, instancersPrimSpecPath) instancersPrimSpec.specifier = Sdf.SpecifierDef layer.defaultPrim = 'Instancers' for name, instances in jsonData.items(): pointInstancerPrimSpecPath = instancersPrimSpecPath + '/' + self._getFileBasename( name) pointInstancerPrimSpec = Sdf.CreatePrimInLayer( layer, pointInstancerPrimSpecPath) pointInstancerPrimSpec.specifier = Sdf.SpecifierDef pointInstancerPrimSpec.typeName = 'PointInstancer' positionsBuffer = [] orientationsBuffer = [] for instanceName, instanceTransform in instances.items(): transformMatrix = Gf.Matrix4d(*instanceTransform) positionsBuffer.append( transformMatrix.ExtractTranslation()) quaternion = transformMatrix.ExtractRotation( ).GetQuaternion().GetNormalized() imaginaryComponents = quaternion.GetImaginary() orientationsBuffer.append( Gf.Quath( quaternion.GetReal(), Gf.Vec3h(imaginaryComponents[0], imaginaryComponents[1], imaginaryComponents[2]))) positionsAttribute = Sdf.AttributeSpec( pointInstancerPrimSpec, 'positions', Sdf.ValueTypeNames.Vector3fArray) positionsAttribute.default = positionsBuffer orientationsAttribute = Sdf.AttributeSpec( pointInstancerPrimSpec, 'orientations', Sdf.ValueTypeNames.QuathArray) orientationsAttribute.default = orientationsBuffer protoIndicesAttribute = Sdf.AttributeSpec( pointInstancerPrimSpec, 'protoIndices', Sdf.ValueTypeNames.IntArray) protoIndicesAttribute.default = [0] * len(instances.items()) meshReferencePrimSpecPath = pointInstancerPrimSpecPath + '/mesh' meshReferencePrimSpec = Sdf.CreatePrimInLayer( layer, meshReferencePrimSpecPath) meshReferencePrimSpec.specifier = Sdf.SpecifierDef meshReferencePrimSpec.typeName = 'Mesh' relativeAssetFilePath = './' + os.path.relpath( self._getAssetFilePathFromOBJFilePath(name), self.PrimitivesDirectory).replace('\\', '/') meshReferencePrimSpec.referenceList.Prepend( Sdf.Reference(relativeAssetFilePath)) relationshipSpec = Sdf.RelationshipSpec(pointInstancerPrimSpec, 'prototypes', custom=False) relationshipSpec.targetPathList.explicitItems.append( meshReferencePrimSpecPath) layer.Export(subInstanceStageFilePath, comment='')
def ClearActiveForSelection(self): with Sdf.ChangeBlock(): prims = self._GetSelectedPrims() for prim in prims: prim.ClearActive()
def DeactivateSelection(self): with Sdf.ChangeBlock(): prims = self._GetSelectedPrims() for prim in prims: prim.SetActive(False)
def do(self): context = self.get_current_context() with Sdf.ChangeBlock(): for prim in context.selected_prims: prim.SetActive(False)