def AddAlembicGeometry(importomaticNode, assetId, locationExpression=None): assetPlugin = AssetAPI.GetDefaultAssetPlugin() rootInstanceName = assetPlugin.getAssetDisplayName(assetId) node = NodegraphAPI.CreateNode('Group') node.setName(rootInstanceName) # This seems a bit odd to set the name and then retrieve it but Katana # will change the name to a unique name which we can then extract uniqueRootName = node.getName() node.setName(uniqueRootName) node.setType('Alembic') node.addOutputPort('out') alembicInNode = NodegraphAPI.CreateNode('Alembic_In', node) alembicInNode.getOutputPortByIndex(0).connect(node.getReturnPort('out')) # If the location parameter isn't # given try to intelligently guess one # if locationExpression: alembicInNode.getParameter('name').setExpression(locationExpression, True) else: baseLocation = "/root/world/geo" location = baseLocation + "/" + uniqueRootName alembicInNode.getParameter('name').setValue(location, 0) alembicInNode.getParameter('abcAsset').setValue(assetId, 0) assetInfoParam = node.getParameters().createChildGroup('assetInfo') findInstances(uniqueRootName, assetInfoParam, "") BuildScenegraph(node) return node
def __popupVersions(self, item, local_pos, global_pos): currentColumnId = self.tree.columnAt(local_pos.x()) currentColumnName = self.__headerLabels[currentColumnId] if currentColumnName == 'Version': itemData = item.getItemData() itemType = itemData['type'] if itemType == 'assetTree': assetItem = itemData['assetItem'] assetId = assetItem.getAssetId() if assetId != None: assetPlugin = AssetAPI.GetDefaultAssetPlugin() if assetPlugin.isAssetId(assetId): versions = [] customTags = assetItem.getCustomVersionTagNames() if customTags: versions = customTags versions.extend(assetPlugin.getAssetVersions(assetId)) if versions: self.__versionPopup.clear() for version in versions: self.__versionPopup.addItem(version) self.__versionPopup.popup(global_pos) self.__versionPopup.show() return True return False
def __findAssetIdFromTreeItem(self, item): itemData = item.getItemData() itemType = itemData['type'] if itemType == 'assetTree': assetItem = itemData['assetItem'] assetId = assetItem.getAssetId() assetPlugin = AssetAPI.GetDefaultAssetPlugin() if assetPlugin.isAssetId(assetId): return assetId return
def setValue(self, value): """Given an asset id. Set the Show, Shot, Asset and version in the UI.""" assetPlugin = AssetAPI.GetDefaultAssetPlugin() if not assetPlugin.isAssetId(value): return assetFields = assetPlugin.getAssetFields(value, True) self.__showEdit.setText(assetFields["show"]) self.__shotEdit.setText(assetFields["shot"]) self.__assetEdit.setText(assetFields[AssetAPI.kAssetFieldName]) self.__versionEdit.setText(assetFields.get(AssetAPI.kAssetFieldVersion, ""))
def setAssetId(self, assetId): """ Given an asset id decomposes in to a show, shot, name and version fields and updates the UI to reflect that """ assetPlugin = AssetAPI.GetDefaultAssetPlugin() if not assetPlugin.isAssetId(assetId): return assetFields = assetPlugin.getAssetFields(assetId, True) for k in ("show", "shot", "name", "version"): self.__selectItem(k, assetFields[k])
def setAssetId(self, assetId): """Given an asset ID, decompose in to a show, shot, asset name and asset version and update the UI to reflect that. """ assetPlugin = AssetAPI.GetDefaultAssetPlugin() if not assetPlugin.isAssetId(assetId): return assetFields = assetPlugin.getAssetFields(assetId, True) self.__showCombobox.setEditText(assetFields["show"]) self.__shotCombobox.setEditText(assetFields["shot"]) self.__assetCombobox.setEditText(assetFields[AssetAPI.kAssetFieldName]) self.__versionCombobox.setEditText(assetFields.get(AssetAPI.kAssetFieldVersion,""))
def isLockable(self): """ An asset is not lockable if there is no version information for it. """ # An asset is lockable if it has # multiple versions assetId = self.__handler.getAssetId() assetPlugin = AssetAPI.GetDefaultAssetPlugin() versions = assetPlugin.getAssetVersions(assetId) lockable = len(versions) != 0 return lockable
def getValue(self): """Get the asset ID from this browser window""" show = str(self.__showEdit.text()) shot = str(self.__shotEdit.text()) asset = str(self.__assetEdit.text()) version = str(self.__versionEdit.text()) assetFields = {"show" : show, "shot" : shot, AssetAPI.kAssetFieldName : asset, AssetAPI.kAssetFieldVersion : version} assetPlugin = AssetAPI.GetDefaultAssetPlugin() assetId = assetPlugin.buildAssetId(assetFields) return assetId
def __popupVersionsItemChosen(self, chosenVersion, meta): item = self.tree.itemAt(self.__lastTreePos) if item != None: itemData = item.getItemData() if itemData['type'] == 'assetTree': assetPlugin = AssetAPI.GetDefaultAssetPlugin() assetItem = itemData['assetItem'] assetId = assetItem.getAssetId() if assetPlugin.isAssetId(assetId): fields = assetPlugin.getAssetFields(assetId, False) fields['version'] = str(chosenVersion) assetIdWithVersion = assetPlugin.buildAssetId(fields) assetItem.setAssetId(assetIdWithVersion) self.__versionPopup.clearFilterField() self.__versionPopup.clear() return
def setAssetId(self, assetId): """Given an asset ID, decompose in to a show, shot, asset name and asset version and update the UI to reflect that. """ assetPlugin = AssetAPI.GetDefaultAssetPlugin() if not assetPlugin.isAssetId(assetId): return assetFields = assetPlugin.getAssetFields(assetId, True) self.__showCombobox.setEditText(assetFields["show"]) self.__shotCombobox.setEditText(assetFields["shot"]) self.__assetCombobox.setEditText(assetFields[AssetAPI.kAssetFieldName]) self.__versionCombobox.setEditText(assetFields[AssetAPI.kAssetFieldVersion]) if assetId.startswith("sandbox://"): self.__sandboxCheckBox.setCheckState(QtCore.Qt.Checked)
def FindPluginFromAssetIdType(assetId): """ Given an asset id, find the type of the asset and look for a plugin that can open that type. """ # Get hold of the primary asset plugin # assetPlugin = AssetAPI.GetDefaultAssetPlugin() # Get hold of the asset type name # so that we can match it up with a plug-in # for loading that particular type # attrs = assetPlugin.getAssetAttributes(assetId, "version") if not attrs: log.error( "No attributes for asset '%s'. Ensure you are using the correct asset management plug-in for this asset id." % assetId) return None assetType = attrs["type"] # Look for the right importomatic plugin # for this type # plugin_name = CastingSheetConstants.TYPE_MAPPING.get(assetType, None) # Check that there is a plugin for this type # if not plugin_name: log.error( "Unable to find a plugin mapping to load the given asset type '%s'" % assetType) return None # Check that there is a plugin for this type # if not AssetModule.HasBatchCreateCallback(plugin_name): log.error( "Unable to find a plugin registered to load the given asset type '%s'" % assetType) return None # Load it # return plugin_name
def setAssetId(self, assetId): """ Given an asset id decomposes in to a show, shot, name and version fields and updates the UI to reflect that """ assetPlugin = AssetAPI.GetDefaultAssetPlugin() if not assetPlugin.isAssetId(assetId): return assetFields = assetPlugin.getAssetFields(assetId, True) for k in ("show", "shot", "name", "version"): self.__selectItem(k, assetFields[k]) currIndex = 0 if assetFields.get("protocol", "") == "sandbox": currIndex = 1 self.__tabWidget.setCurrentIndex(currIndex)
def _ReplaceTagsWithNumbers(assetId): """ Given an asset id that looks like this: mock://foo/bar/latest replace the tag with the latest version mock://foo/bar/3 """ assetPlugin = AssetAPI.GetDefaultAssetPlugin() version = assetPlugin.resolveAssetVersion(assetId) fields = assetPlugin.getAssetFields(assetId, False) fields["version"] = version assetId = assetPlugin.buildAssetId(fields) return assetId
def setValue(self, value): """ Given an asset ID. Set the Show, Shot, Asset and version in the UI. """ assetPlugin = AssetAPI.GetDefaultAssetPlugin() if not assetPlugin.isAssetId(value): return assetFields = assetPlugin.getAssetFields(value, True) self.__showEdit.setText(assetFields["show"]) self.__shotEdit.setText(assetFields["shot"]) self.__assetEdit.setText(assetFields[AssetAPI.kAssetFieldName]) self.__versionEdit.setText(assetFields[AssetAPI.kAssetFieldVersion]) if assetFields.get("protocol", "") == "sandbox": self.__protocolLabel.setText("sandbox://") else: self.__protocolLabel.setText("mock://")
def getValue(self): """Get the asset ID from this browser window""" show = str(self.__showEdit.text()) shot = str(self.__shotEdit.text()) asset = str(self.__assetEdit.text()) version = str(self.__versionEdit.text()) protocol = "asset" if self.__protocolLabel.text() == "sandbox://": protocol = "sandbox" assetFields = {"protocol" : protocol, "show" : show, "shot" : shot, AssetAPI.kAssetFieldName : asset, AssetAPI.kAssetFieldVersion : version} assetPlugin = AssetAPI.GetDefaultAssetPlugin() assetId = assetPlugin.buildAssetId(assetFields) return assetId
def SyncCastingSheet(node, assetId): """ Sync the casting sheet node to the given asset. ------------------------------------------------------------------- Syncing steps Delete the merge node. Iterate over all of child nodes and ... - If they are locked: - Move the current node to the 'graveyard' group node. We are guaranteed that there will not be a node with the same casting name in this group node because if there had been it would have been in the casting sheet. - If they are not locked - Delete them For every node in the 'graveyard' node create an entry in a graveyard map. Create a new merge node. Iterate over all of the entries in the casting sheet: - If an asset of the given instance name exists in the graveyard map then: - re-parent the node under the casting sheet and use it - Otherwise: - Create a new node with the plug-in callback system Then connect the node to the merge node. Save the casting sheet asset id in to the parameter castingInfo.asset """ # Type check # nodeType = node.getType() if nodeType != "CastingSheet": log.error( "You are trying to delete a node that is not a casting sheet node") return # For the casting sheet we always # resolve the asset version in the asset id # immediately. # assetPlugin = AssetAPI.GetDefaultAssetPlugin() assetId = _ReplaceTagsWithNumbers(assetId) filepath = assetPlugin.resolveAsset(assetId) if not filepath: log.error( "Unable to resolve the casting sheet asset ID for '%s' in the casting sheet node '%s'" % (assetId, node.getName())) return # Check if we will be able to load # the asset ids casting sheet on file # if not _PopulatePreCondition(filepath): return # Ensure that the casting sheet node has a valid internal state # children = list(node.getChildren()) if not children: log.error( "Casting sheet node '%s' is in an invalid state it has no merge node or graveyard node, remove it and create a new one" % node.getName()) return # The graveyard node is always first, then the merge node. # graveyardNode = _GetGraveyardNode(node) mergeNode = _GetMergeNode(node) # This is done to support an assertion only. # It does not contribute to the functionality of this code. # takenGraveyardNames = set( (GetCastingName(child) for child in graveyardNode.getChildren())) # Get hold of the children before the # merge node is deleted # entries = _GetInputNodes(mergeNode) # In case the merge node doesn't exist # if mergeNode.getType() == "Merge": mergeNode.delete() # Everything else is a casting sheet entry # for child in entries: if IsLocked(child): assert GetCastingName(child) not in takenGraveyardNames child.setParent(graveyardNode) else: child.delete() # Create a casting name to node mapping # graveyard = [(GetCastingName(n), n) for n in graveyardNode.getChildren()] graveyard = dict(graveyard) # Populate the node with casting sheet entries # _Populate(filepath, node, graveyard) # Now store the asset id so that we know where this all came from # setCastingParam(node, "asset", assetId, hintsDict={'widget': 'assetIdInput'}) # Finally rebuild the layout # _LayoutContents(node)
def AddScenegraphXmlGeometry(importomaticNode, assetId, locationExpression=None): filename = '' assetPlugin = AssetAPI.GetDefaultAssetPlugin() if assetPlugin.isAssetId(assetId): filename = assetPlugin.resolveAsset(assetId) else: return fileBase = os.path.basename(filename) rootParamName = os.path.splitext(fileBase)[0] # Parse XML to extract relevant information xmlTree = ET.parse(filename) xmlRoot = xmlTree.getroot() node = None # Find all instances of type reference rootInstanceList = xmlRoot.find("instanceList") if rootInstanceList is not None: rootInstance = rootInstanceList.find("instance") rootInstanceName = rootInstance.attrib["name"] rootInstanceType = rootInstance.attrib["type"] node = NodegraphAPI.CreateNode('Group') node.setName(rootParamName) # This seems a bit odd to set the name and then retrieve it but Katana # will change the name to a unique name which we can then extract uniqueRootName = node.getName() node.setType('ScenegraphXml') node.addOutputPort('out') xmlInNode = NodegraphAPI.CreateNode('ScenegraphXml_In', node) xmlInNode.getOutputPortByIndex(0).connect(node.getReturnPort('out')) # If the location parameter isn't # given try to intelligently guess one # if locationExpression: xmlInNode.getParameter('name').setExpression( locationExpression, True) else: baseLocation = xmlInNode.getParameter("name").getValue(0) location = baseLocation + '/' + uniqueRootName xmlInNode.getParameter('name').setValue(location, 0) xmlInNode.getParameter('asset').setValue(assetId, 0) basePath = os.path.dirname(filename) + os.sep assetInfoParam = node.getParameters().createChildGroup('assetInfo') assetInfoParam.createChildString('_ignore', 'False') assetInfoParam.createChildString('_sgPath', '/' + uniqueRootName) findInstances(rootInstanceList, assetInfoParam, node, basePath, "") BuildScenegraph(node) return node
def buildBgeoInOpChain(node, interface): """ Defines the callback function used to create the Ops chain for the node type being registered. @type node: C{Nodes3DAPI.NodeTypeBuilder.BgeoIn} @type interface: C{Nodes3DAPI.NodeTypeBuilder.BuildChainInterface} @param node: The node for which to define the Ops chain @param interface: The interface providing the functions needed to set up the Ops chain for the given node. """ # Get the current frame time frameTime = interface.getGraphState().getTime() # Set the minimum number of input ports interface.setMinRequiredInputs(0) argsGb = FnAttribute.GroupBuilder() # Parse node parameters locationParam = node.getParameter('location') fileNameParam = node.getParameter('fileName') makeFacesetsParam = node.getParameter('makeFacesets') reportEmptyParam = node.getParameter('reportEmpty') computeBoundParam = node.getParameter('computePointCloudBound') createSubdParam = node.getParameter('createSubd') checkVersionParam = node.getParameter('checkVersion') # resolve file path so that it can include frame number replacement # i.e. %04d filePath = fileNameParam.getValue(frameTime) fileSequencePlugin = AssetAPI.GetDefaultFileSequencePlugin() if fileSequencePlugin and fileSequencePlugin.isFileSequence(filePath): fileSequence = fileSequencePlugin.getFileSequence(filePath) resolvedPath = fileSequence.getResolvedPath(int(frameTime)) else: resolvedPath = filePath argsGb.set('fileName', FnAttribute.StringAttribute(resolvedPath)) argsGb.set( 'makeFacesets', FnAttribute.IntAttribute(makeFacesetsParam.getValue(frameTime))) argsGb.set( 'reportEmpty', FnAttribute.IntAttribute(reportEmptyParam.getValue(frameTime))) argsGb.set( 'computePointCloudBound', FnAttribute.IntAttribute(computeBoundParam.getValue(frameTime))) argsGb.set( 'createSubd', FnAttribute.IntAttribute(createSubdParam.getValue(frameTime))) argsGb.set( 'checkVersion', FnAttribute.IntAttribute(checkVersionParam.getValue(frameTime))) # We want to use the StaticSceneCreate Op to build the parent # hierarchy, so that our op only has to worry about generating its # children. Its args are somewhat complex, but fortunately, there # is a helper class that makes it all much easier. rootLocation = locationParam.getValue(frameTime) sscb = FnGeolibServices.OpArgsBuilders.StaticSceneCreate() sscb.addSubOpAtLocation(rootLocation, 'BgeoIn', argsGb.build()) interface.appendOp('StaticSceneCreate', sscb.build())
def __traverseItemTree(self, assetItem, treeParent, selectedKeys, openState, node=None): item = AssetListViewItem(treeParent, '') key = node selectable = True if not node: try: key = assetItem.getItemKey() selectable = assetItem.isSelectable() except Exception as exception: log.exception('Error accessing asset item %s: %s' % (assetItem, str(exception))) item.setItemData({ 'type': 'assetTree', 'assetItem': assetItem, 'key': key }) if selectable: item.setSelected(key in selectedKeys) item.setFlags( QtCore.Qt.ItemFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled)) else: item.setFlags(QtCore.Qt.ItemFlags(QtCore.Qt.ItemIsEnabled)) defaultState = assetItem.getDefaultOpenState() expanded = openState.get(key, defaultState) item.setExpanded(expanded) try: assetId = assetItem.getAssetId() if assetId: assetPlugin = AssetAPI.GetDefaultAssetPlugin() if assetPlugin.isAssetId(assetId): fields = assetPlugin.getAssetFields(assetId, True) version = fields.get('version', None) resolvedVersion = assetPlugin.resolveAssetVersion( assetId, throwOnError=True) if version: item.setText(VERSION_COLUMN, version) item.setIcon( VERSION_COLUMN, UI4.Util.IconManager.GetIcon( 'Icons/heightAdjustDownHilite16.png')) if resolvedVersion: item.setText(RESOLVED_VERSION_COLUMN, resolvedVersion) except Exception as exception: log.exception('Error getting version of asset item %s: %s' % (assetItem, str(exception))) try: assetItem.setItemState(item) except Exception as exception: log.exception('Error setting state of asset item %s: %s' % (assetItem, str(exception))) if assetItem.isIgnorable() and assetItem.isIgnored(): item.setIcon(NAME_COLUMN, UI4.Util.IconManager.GetIcon('Icons/ignore16.png')) try: children = assetItem.getChildren() if children: for child in children: self.__traverseItemTree(child, item, selectedKeys, openState) except Exception as exception: log.exception('Error traversing children of asset item %s: %s' % (assetItem, str(exception))) try: assetItem.addNodeObservers(self.__addObserverNode) except Exception as exception: log.exception('Error adding node observer to asset item %s: %s' % (assetItem, str(exception))) return item
def getResult(self): assetFields = self.__widget.getAssetFields() assetPlugin = AssetAPI.GetDefaultAssetPlugin() return assetPlugin.buildAssetId(assetFields)
def AddCastingSheet(importomaticNode, assetId, locationExpression=None): """ Load the chosen casting sheet specified by assetId to the location specified by locationExpression. """ # We can't do anything without a casting sheet asset id if assetId == None: log.error("No asset id given for new casting sheet") return # Resolve the asset file path # # Get hold of the primary asset plugin # so that we can resolve the casting sheet asset. assetPlugin = AssetAPI.GetDefaultAssetPlugin() filepath = assetPlugin.resolveAsset(assetId) if not filepath: log.error("Unable to resolve the casting sheet asset ID for '%s'" % assetId) return # Check if we will be able to load # the asset ids in the casting sheet on file if not _PopulatePreCondition(filepath): return # Store everything inside of the casting sheet group node = NodegraphAPI.CreateNode('Group') node.setName('CastingSheet') node.setType(CASTINGSHEET_TYPE) node.addOutputPort('out') returnOut = node.getReturnPort("out") # CastingSheet parameters - Scene graph location if locationExpression: setCastingStringParamExpression( node, "name", locationExpression, hintsDict={'widget': 'scenegraphLocation'}) # If a locationExpression wasn't given # default to a sensible place else: location = '/root/world/geo/%s' % node.getName() setCastingParam(node, "name", location, hintsDict={'widget': 'scenegraphLocation'}) # Create our graveyard node # This should be created first because it # never gets deleted graveyard = NodegraphAPI.CreateNode('Group') graveyard.setName('Graveyard') graveyard.setParent(node) # Read the casting sheet and populate # the casting sheet node. _Populate(filepath, node) # Now store the asset id so that we know where this all came from setCastingParam(node, "asset", assetId, hintsDict={'widget': 'assetIdInput'}) # Finally adjust the layout in the nodegraph ui _LayoutContents(node) return node
def _Populate(filepath, node, graveyard={}): """ Populate the casting sheet node with the contents of the casting sheet file pointed to by 'filepath'. Use the graveyard parameter to bring back locked nodes that were not part of the last set casting sheet version. """ # Create a new merge node # merge = NodegraphAPI.CreateNode('Merge') merge.setName('MergeCastingSheet') merge.setParent(node) mergeOut = merge.getOutputPort("out") # Connect the merge node # to this nodes output port # returnOut = node.getReturnPort("out") mergeOut.connect(returnOut) # Resolve the asset file path # assetPlugin = AssetAPI.GetDefaultAssetPlugin() # Iterate over all the entries # in the casting sheet loading # their respective nodes # GRID_WIDTH = 200 GRID_Y_OFFSET = 200 FIRST = 0 ID, NAME = (0, 1) for index, asset in enumerate(CastingSheetIO.Iterator(filepath)): assetId = asset[ID] assetName = asset[NAME] # If it exists in the 'graveyard'. # bring it back to life # child = graveyard.get(assetName, None) if not child: # Get hold of a plug-in that can load this asset # plugin_name = FindPluginFromAssetIdType(assetId) # Ensure that a matching plug-in was found # for the asset type # if plugin_name == None: log.error( "We were unable to find a plug-in to load the the asset '%s'." % (assetId)) else: # The location of the casting sheet asset in the scene graph # locationExpression = 'getParam("%s.castingInfo.name") + "/" + getNode(nodeName).getParent().castingInfo.name' % ( node.getName()) # Load it in # child = AssetModule.TriggerBatchCreateCallback( plugin_name, node, assetId, locationExpression) # We can try to set the name of the casting sheet item # but if there is already an item that exists in the scene # with that same name then we will be given a different name. # child.setName(assetName) # So store the casting sheet name on the node as a parameter. # We will use this later for synching. # setCastingParam(child, "name", assetName) setCastingParam(child, "locked", UNLOCK, NodegraphAPI.Parameter.createChildNumber) if child: # Re-parent the node # child.setParent(node) # Merge this input in # entry = merge.addInputPort(assetName) main = child.getOutputPortByIndex(FIRST) main.connect(entry) else: log.warning( "We were unable to create a new casting node for the casting sheet entry '%s' at '%s'." % (assetName, assetId))