def __init__(self, mainUI): """ Instantiate the class, getting the QSettings, and building the interface. :param mainUI: The instance of the Rig Creator UI from which this class was called. """ # get the directory path of the tools settings = QtCore.QSettings("Epic Games", "ARTv2") self.toolsPath = settings.value("toolsPath") self.iconsPath = settings.value("iconPath") self.projectPath = settings.value("projectPath") self.mainUI = mainUI # images self.imageBkgrd = utils.returnFriendlyPath( os.path.join(self.iconsPath, "System/toolbar_background.png")) self.imageBtnBkrd = utils.returnFriendlyPath( os.path.join(self.iconsPath, "System/blue_field_background.png")) self.frameBackground = utils.returnFriendlyPath( os.path.join(self.iconsPath, "System/field_background.png")) # build the UI if cmds.window("ART_DebugRigsWin", exists=True): cmds.deleteUI("ART_DebugRigsWin", wnd=True) self.buildUI()
def __init__(self, mainUI): #get the directory path of the tools settings = QtCore.QSettings("Epic Games", "ARTv2") self.toolsPath = settings.value("toolsPath") self.iconsPath = settings.value("iconPath") self.scriptPath = settings.value("scriptPath") self.projectPath = settings.value("projectPath") self.mainUI = mainUI self.rigData = [] self.warnings = 0 self.errors = 0 #images self.imageBkgrd = utils.returnFriendlyPath( os.path.join(self.iconsPath, "System/toolbar_background.png")) self.imageBtnBkrd = utils.returnFriendlyPath( os.path.join(self.iconsPath, "System/blue_field_background.png")) self.frameBackground = utils.returnFriendlyPath( os.path.join(self.iconsPath, "System/field_background.png")) #build the UI if cmds.window("ART_RigHistWin", exists=True): cmds.deleteUI("ART_RigHistWin", wnd=True) self.buildUI()
def __init__(self, mainUI): """ Instantiates the class, getting the QSettings and then calling on the function to build the UI for the tool. :param mainUI: The instance of the Rig Creator UI that this class was called from. .. seealso:: ART_BuildProgressUI.buildUI """ # get the directory path of the tools settings = QtCore.QSettings("Epic Games", "ARTv2") self.toolsPath = settings.value("toolsPath") self.projectPath = settings.value("projectPath") self.iconsPath = settings.value("iconPath") self.mainUI = mainUI self.rigData = [] self.warnings = 0 self.errors = 0 # images self.imageBkgrd = utils.returnFriendlyPath(os.path.join(self.iconsPath, "System/toolbar_background.png")) self.imageBtnBkrd = utils.returnFriendlyPath(os.path.join(self.iconsPath, "System/blue_field_background.png")) self.frameBackground = utils.returnFriendlyPath(os.path.join(self.iconsPath, "System/field_background.png")) # build the UI if cmds.window("ART_BuildProgressWin", exists=True): cmds.deleteUI("ART_BuildProgressWin", wnd=True) self.buildUI()
def checkForCustomMeshes(self): #check for custom geometry skinnableGeo = self.findCustomGeo() meshes = list(skinnableGeo) if len(skinnableGeo) > 0: matches = [] #check to see if weight files exist for this geo on disk for i in range(len(meshes)): filePath = utils.returnFriendlyPath( os.path.join(cmds.internalVar(utd=True), meshes[i] + ".WEIGHTS")) if os.path.exists(filePath): matches.append(meshes[i]) if len(matches) > 0: for match in matches: listWidgetItem = QtWidgets.QListWidgetItem(match) self.page5MeshList.addItem(listWidgetItem) listWidgetItem.setSelected(True) #go to page 5 self.stackWidget.setCurrentIndex(4) else: #go to page 3 self.stackWidget.setCurrentIndex(2) else: #go to page 2 self.stackWidget.setCurrentIndex(1)
def browse(self, lineEdit): try: newPath = cmds.fileDialog2(dir=self.toolsPath, fm=3)[0] newPath = utils.returnFriendlyPath(newPath) lineEdit.setText(newPath) except: pass #in case user cancels on Maya's browse dialog
def createContextMenu(self, point): self.contextMenu = QtWidgets.QMenu() selectIcon = QtGui.QIcon((utils.returnFriendlyPath( os.path.join(self.iconsPath, "System/select.png")))) self.contextMenu.addAction(selectIcon, "Select All", self.selectAllInList) self.contextMenu.addAction("Clear Selection", self.clearListSelection) self.contextMenu.exec_(self.moduleList.mapToGlobal(point))
def __init__(self, mainUI, moviePath): #Original Author: Jeremy Ernst #get the directory path of the tools settings = QtCore.QSettings("Epic Games", "ARTv2") self.toolsPath = settings.value("toolsPath") self.projectPath = settings.value("projectPath") self.iconsPath = settings.value("iconPath") self.mainUI = mainUI #images self.imageBkgrd = utils.returnFriendlyPath( os.path.join(self.iconsPath, "System/toolbar_background.png")) self.imageBtnBkrd = utils.returnFriendlyPath( os.path.join(self.iconsPath, "System/blue_field_background.png")) self.frameBackground = utils.returnFriendlyPath( os.path.join(self.iconsPath, "System/field_background.png")) #build the UI if cmds.window("ART_HelpMovieWin", exists=True): cmds.deleteUI("ART_HelpMovieWin", wnd=True) self.buildHelpMovieUI(moviePath)
def exportSkinWeights_fileBrowse(self): """ Open a file dialog that the user can use to browse to the output directory of their choice for saving the .weight files to. """ # Need support for defaulting to current project character was last published to and creating character skin # weights folder try: path = cmds.fileDialog2(fm=3, dir=self.toolsPath)[0] nicePath = utils.returnFriendlyPath(path) self.exportSkinWeights_lineEdit.setText(nicePath) except: pass
def importSkinWeights_fileBrowse(self, lineEdit): """ Open a file dialog that the user can use to browse to the .weight file, then set the text of the passed-in line edit to be the path to the .weights file. :param lineEdit: QLineEdit to set path text to. """ # Need support for defaulting to current project character was last published to and creating character # skin weights folder try: path = cmds.fileDialog2(fm=1, dir=self.toolsPath)[0] nicePath = utils.returnFriendlyPath(path) lineEdit.setText(nicePath) except: pass
def importWeights(self): #get the selected items in the mesh list selected = self.page5MeshList.selectedItems() #get the import method method = self.page5ImportOptions.currentText() meshes = [] for each in selected: meshes.append(each.text()) for mesh in meshes: filePath = utils.returnFriendlyPath( os.path.join(cmds.internalVar(utd=True), mesh + ".WEIGHTS")) if os.path.exists(filePath): riggingUtils.import_skin_weights(filePath, mesh, True) self.closeWizard()
def fbxFileBrowse(self): settings = QtCore.QSettings("Epic Games", "ARTv2") path = settings.value("ImportPath") if path == None: path = self.projectPath #see if export node exists, and if it does, see if there is an existing export path try: path = cmds.fileDialog2(fm=1, okc="Import FBX", dir=path, ff="*.fbx") nicePath = utils.returnFriendlyPath(path[0]) self.fbxFilePath.setText(nicePath) settings.setValue("ImportPath", nicePath) except: pass
def importSkinWeights_populate(self): """ Populate the interface with an entry for each piece of selected geometry. Each entry will have the geometry name and allow the user to point to the geometry's .weight file. """ # get current selection selection = cmds.ls(sl=True) if len(selection) > 0: # Create headers font = QtGui.QFont() font.setPointSize(12) font.setBold(True) headerLayout = QtWidgets.QHBoxLayout() self.importSkinWeights_VLayout.addLayout(headerLayout) headerExport = QtWidgets.QLabel(" ") headerExport.setStyleSheet("background: transparent;") headerLayout.addWidget(headerExport) headerGeo = QtWidgets.QLabel("Mesh") headerGeo.setStyleSheet("background: transparent;") headerGeo.setMinimumSize(QtCore.QSize(180, 20)) headerGeo.setMaximumSize(QtCore.QSize(180, 20)) headerLayout.addWidget(headerGeo) headerGeo.setFont(font) headerFileName = QtWidgets.QLabel("Weight File") headerFileName.setStyleSheet("background: transparent;") headerLayout.addWidget(headerFileName) headerFileName.setMinimumSize(QtCore.QSize(180, 20)) headerFileName.setMaximumSize(QtCore.QSize(180, 20)) headerFileName.setFont(font) # get a list of weight files weightFiles = [] for root, subFolders, files in os.walk(self.toolsPath): for file in files: if file.rpartition(".")[2] == "weights": fullPath = utils.returnFriendlyPath(os.path.join(root, file)) weightFiles.append(fullPath) print weightFiles # loop through selection, checking selection is valid and has skinCluster for each in selection: try: # get dagPath and shape and create a nice display name dagPath = cmds.ls(each, long=True)[0] shapeNode = cmds.listRelatives(dagPath, children=True) nicename = each.rpartition("|")[2] except Exception, e: traceback.format_exc() try: if cmds.nodeType(dagPath + "|" + shapeNode[0]) == "mesh": # create HBoxLayout layout = QtWidgets.QHBoxLayout() layout.setSpacing(10) self.importSkinWeights_VLayout.addLayout(layout) # create checkbox checkBox = QtWidgets.QCheckBox() layout.addWidget(checkBox) checkBox.setChecked(True) # create non editable line edit geoName = QtWidgets.QLabel(nicename + " : ") geoName.setStyleSheet("background: transparent;") geoName.setProperty("dag", dagPath) layout.addWidget(geoName) geoName.setMinimumSize(QtCore.QSize(100, 30)) geoName.setMaximumSize(QtCore.QSize(100, 30)) # create editable line edit skinFileName = QtWidgets.QLineEdit() layout.addWidget(skinFileName) skinFileName.setMinimumSize(QtCore.QSize(205, 30)) skinFileName.setMaximumSize(QtCore.QSize(205, 30)) # try to find a matching weight file for file in weightFiles: compareString = file.rpartition("/")[2].partition(".")[0] if nicename.lower() == compareString.lower(): skinFileName.setText(file) # check if geometry has weights file associated already if cmds.objExists(dagPath + ".weightFile"): path = cmds.getAttr(dagPath + ".weightFile") path = utils.returnFriendlyPath(path) if os.path.exists(path): skinFileName.setText(path) # browse button browseBtn = QtWidgets.QPushButton() layout.addWidget(browseBtn) browseBtn.setMinimumSize(35, 35) browseBtn.setMaximumSize(35, 35) icon = QtGui.QIcon(os.path.join(self.iconsPath, "System/fileBrowse.png")) browseBtn.setIconSize(QtCore.QSize(30, 30)) browseBtn.setIcon(icon) browseBtn.clicked.connect(partial(self.importSkinWeights_fileBrowse, skinFileName)) except Exception, e: print traceback.format_exc()
def buildExportWeightsUI(self): """ Build the interface for exporting the skin weights. An entry is added for each piece of selected geometry. The user then has the ability to specify a .weight file name for the associated geometry. The user also specifies where they would like the weight files saved to. .. image:: /images/exportWeights.png """ if cmds.window("ART_exportSkinWeightsUI", exists=True): cmds.deleteUI("ART_exportSkinWeightsUI", wnd=True) # launch a UI to get the name information self.exportSkinWeights_Win = QtWidgets.QMainWindow(self.mainUI) # size policies mainSizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) # load stylesheet styleSheetFile = utils.returnNicePath( self.toolsPath, "Core/Scripts/Interfaces/StyleSheets/mainScheme.qss") f = open(styleSheetFile, "r") self.style = f.read() f.close() # create the main widget self.exportSkinWeights_mainWidget = QtWidgets.QWidget() self.exportSkinWeights_Win.setCentralWidget( self.exportSkinWeights_mainWidget) # set qt object name self.exportSkinWeights_Win.setObjectName("ART_exportSkinWeightsUI") self.exportSkinWeights_Win.setWindowTitle("Export Skin Weights") # create the mainLayout for the ui self.exportSkinWeights_mainLayout = QtWidgets.QVBoxLayout( self.exportSkinWeights_mainWidget) self.exportSkinWeights_mainLayout.setContentsMargins(5, 5, 5, 5) self.exportSkinWeights_Win.resize(450, 600) self.exportSkinWeights_Win.setSizePolicy(mainSizePolicy) self.exportSkinWeights_Win.setMinimumSize(QtCore.QSize(450, 600)) self.exportSkinWeights_Win.setMaximumSize(QtCore.QSize(450, 600)) # create the background image self.exportSkinWeights_frame = QtWidgets.QFrame() self.exportSkinWeights_mainLayout.addWidget( self.exportSkinWeights_frame) self.exportSkinWeights_frame.setObjectName("dark") # create widgetLayout self.exportSkinWeights_widgetLayout = QtWidgets.QVBoxLayout( self.exportSkinWeights_frame) # create the hboxLayout for lineEdit and browser button self.exportSkinWeights_browseLayout = QtWidgets.QHBoxLayout() self.exportSkinWeights_widgetLayout.addLayout( self.exportSkinWeights_browseLayout) # create the line edit for the export path self.exportSkinWeights_lineEdit = QtWidgets.QLineEdit( utils.returnFriendlyPath(self.toolsPath)) self.exportSkinWeights_browseLayout.addWidget( self.exportSkinWeights_lineEdit) self.exportSkinWeights_browseBtn = QtWidgets.QPushButton() self.exportSkinWeights_browseLayout.addWidget( self.exportSkinWeights_browseBtn) self.exportSkinWeights_browseBtn.setMinimumSize(35, 35) self.exportSkinWeights_browseBtn.setMaximumSize(35, 35) icon = QtGui.QIcon( os.path.join(self.iconsPath, "System/fileBrowse.png")) self.exportSkinWeights_browseBtn.setIconSize(QtCore.QSize(30, 30)) self.exportSkinWeights_browseBtn.setIcon(icon) self.exportSkinWeights_browseBtn.clicked.connect( partial(self.exportSkinWeights_fileBrowse)) # scroll area contents self.exportSkinWeights_scrollContents = QtWidgets.QFrame() self.exportSkinWeights_scrollContents.setObjectName("light") # Layout of Container Widget self.exportSkinWeights_VLayout = QtWidgets.QVBoxLayout() # find selected geometry and populate scroll area self.exportSkinWeights_populate() # add scrollArea for selected geo, skinFileName, and checkbox for exporting self.exportSkinWeights_scrollLayout = QtWidgets.QScrollArea() self.exportSkinWeights_widgetLayout.addWidget( self.exportSkinWeights_scrollLayout) self.exportSkinWeights_scrollLayout.setHorizontalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOff) self.exportSkinWeights_scrollLayout.setVerticalScrollBarPolicy( QtCore.Qt.ScrollBarAlwaysOn) self.exportSkinWeights_scrollLayout.setWidgetResizable(False) self.exportSkinWeights_scrollLayout.setWidget( self.exportSkinWeights_scrollContents) # lastly, export button font = QtGui.QFont() font.setPointSize(8) font.setBold(True) self.exportSkinWeights_exportBtnLayout = QtWidgets.QHBoxLayout() self.exportSkinWeights_widgetLayout.addLayout( self.exportSkinWeights_exportBtnLayout) self.exportSkinWeights_RefreshBtn = QtWidgets.QPushButton("Refresh") self.exportSkinWeights_exportBtnLayout.addWidget( self.exportSkinWeights_RefreshBtn) self.exportSkinWeights_RefreshBtn.setMinimumSize(QtCore.QSize(70, 50)) self.exportSkinWeights_RefreshBtn.setMaximumSize(QtCore.QSize(70, 50)) self.exportSkinWeights_RefreshBtn.setFont(font) self.exportSkinWeights_RefreshBtn.clicked.connect( partial(self.buildExportWeightsUI)) self.exportSkinWeights_RefreshBtn.setObjectName("blueButton") self.exportSkinWeights_ExportBtn = QtWidgets.QPushButton( "EXPORT WEIGHTS") self.exportSkinWeights_exportBtnLayout.addWidget( self.exportSkinWeights_ExportBtn) self.exportSkinWeights_ExportBtn.setMinimumSize(QtCore.QSize(350, 50)) self.exportSkinWeights_ExportBtn.setMaximumSize(QtCore.QSize(350, 50)) self.exportSkinWeights_ExportBtn.setFont(font) self.exportSkinWeights_ExportBtn.clicked.connect( partial(self.exportSkinWeights_doExport)) self.exportSkinWeights_ExportBtn.setObjectName("blueButton") # show window self.exportSkinWeights_Win.show()
def exportSkinWeights_populate(self): """ Populate the interface with an entry for each mesh the user has selected. This entry includes the mesh name, an QLineEdit to specify a file name for the .weight file, and a checkbox as to whether or not the user wants to export weights for that mesh. """ # get current selection selection = cmds.ls(sl=True) if len(selection) > 0: # Create headers font = QtGui.QFont() font.setPointSize(12) font.setBold(True) headerLayout = QtWidgets.QHBoxLayout() self.exportSkinWeights_VLayout.addLayout(headerLayout) headerExport = QtWidgets.QLabel(" ") headerLayout.addWidget(headerExport) headerExport.setStyleSheet("background: transparent;") headerGeo = QtWidgets.QLabel("Mesh") headerGeo.setMinimumSize(QtCore.QSize(180, 20)) headerGeo.setMaximumSize(QtCore.QSize(180, 20)) headerLayout.addWidget(headerGeo) headerGeo.setFont(font) headerGeo.setStyleSheet("background: transparent;") headerFileName = QtWidgets.QLabel("FileName") headerLayout.addWidget(headerFileName) headerFileName.setMinimumSize(QtCore.QSize(180, 20)) headerFileName.setMaximumSize(QtCore.QSize(180, 20)) headerFileName.setFont(font) headerFileName.setStyleSheet("background: transparent;") # loop through selection, checking selection is valid and has skinCluster for each in selection: # get dagPath of each dagPath = cmds.ls(each, long=True)[0] skinCluster = riggingUtils.findRelatedSkinCluster(dagPath) if skinCluster is not None: # create HBoxLayout layout = QtWidgets.QHBoxLayout() layout.setSpacing(10) self.exportSkinWeights_VLayout.addLayout(layout) # create checkbox checkBox = QtWidgets.QCheckBox() layout.addWidget(checkBox) checkBox.setChecked(True) # create non editable line edit niceName = each.rpartition("|")[2] geoName = QtWidgets.QLabel(niceName + " : ") geoName.setProperty("dag", dagPath) layout.addWidget(geoName) geoName.setMinimumSize(QtCore.QSize(180, 30)) geoName.setMaximumSize(QtCore.QSize(180, 30)) # create editable line edit if cmds.objExists(dagPath + ".weightFile"): path = cmds.getAttr(dagPath + ".weightFile") niceName = path.rpartition("/")[2].partition(".")[0] dirPath = path.rpartition("/")[0] dirPath = utils.returnFriendlyPath(dirPath) self.exportSkinWeights_lineEdit.setText(dirPath) skinFileName = QtWidgets.QLineEdit(niceName) layout.addWidget(skinFileName) skinFileName.setMinimumSize(QtCore.QSize(170, 30)) skinFileName.setMaximumSize(QtCore.QSize(170, 30)) # add spacer self.exportSkinWeights_scrollContents.setLayout( self.exportSkinWeights_VLayout) else: label = QtWidgets.QLabel( "No Geometry Selected For Export. Select Geometry and Relaunch." ) label.setAlignment(QtCore.Qt.AlignCenter) self.exportSkinWeights_VLayout.addWidget(label)
def buildSettingsUi(self): #fonts font = QtGui.QFont() font.setPointSize(10) font.setBold(True) fontSmall = QtGui.QFont() fontSmall.setPointSize(9) fontSmall.setBold(True) #images frameBackground = os.path.normcase( os.path.join(self.iconsPath, "System/field_background.png")) if frameBackground.partition("\\")[2] != "": frameBackground = frameBackground.replace("\\", "/") imageBkgrd = os.path.normcase( os.path.join(self.iconsPath, "System/toolbar_background.png")) if imageBkgrd.partition("\\")[2] != "": imageBkgrd = imageBkgrd.replace("\\", "/") imageBtnBkrd = os.path.normcase( os.path.join(self.iconsPath, "System/blue_field_background.png")) if imageBtnBkrd.partition("\\")[2] != "": imageBtnBkrd = imageBtnBkrd.replace("\\", "/") #size policies mainSizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) #create the main widget self.mainWidget = QtWidgets.QWidget() self.mainWidget.setStyleSheet( "background-color: rgb(0, 0, 0);, color: rgb(0,0,0);") self.setCentralWidget(self.mainWidget) #set qt object name self.setObjectName(windowObject) self.setWindowTitle(windowTitle) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) #create the mainLayout for the rig creator UI self.layout = QtWidgets.QVBoxLayout(self.mainWidget) self.resize(600, 260) self.setSizePolicy(mainSizePolicy) self.setMinimumSize(QtCore.QSize(600, 260)) self.setMaximumSize(QtCore.QSize(600, 260)) #create the QFrame self.frame = QtWidgets.QFrame() self.layout.addWidget(self.frame) self.widgetLayout = QtWidgets.QVBoxLayout(self.frame) #info page styling self.frame.setStyleSheet("background-image: url(" + imageBkgrd + ");") #MayaTools/Core : Sccipts, icons, jointmover, etc #MayaTools/Projects: actual project files (animation rigs, thumbnails, poses, etc) #location self.locationLayout = QtWidgets.QHBoxLayout() self.widgetLayout.addLayout(self.locationLayout) #location -> label label = QtWidgets.QLabel("Tools Location: ") self.locationLayout.addWidget(label) label.setFont(font) label.setMinimumWidth(150) #location -> line edit path = utils.returnFriendlyPath(self.toolsPath) self.locationPath = QtWidgets.QLineEdit(path) self.locationLayout.addWidget(self.locationPath) self.locationPath.setStyleSheet( "background-image: url(" + frameBackground + "); background-color: rgb(25,175,255);") self.locationPath.setMinimumHeight(35) #location -> browse button self.locationBrowse = QtWidgets.QPushButton() self.locationLayout.addWidget(self.locationBrowse) self.locationBrowse.setMinimumSize(35, 35) self.locationBrowse.setMaximumSize(35, 35) btnBackground = utils.returnNicePath(self.iconsPath, "System/fileBrowse.png") self.locationBrowse.setStyleSheet("background-image: url(" + btnBackground + ");") self.locationBrowse.clicked.connect( partial(self.browse, self.locationPath)) #scripts folder self.scriptsLayout = QtWidgets.QHBoxLayout() self.widgetLayout.addLayout(self.scriptsLayout) #scripts -> label label = QtWidgets.QLabel("Scripts: ") self.scriptsLayout.addWidget(label) label.setFont(fontSmall) label.setMinimumWidth(150) #scripts -> line edit path = utils.returnFriendlyPath(self.scriptPath) self.scriptsPath = QtWidgets.QLineEdit(path) self.scriptsLayout.addWidget(self.scriptsPath) self.scriptsPath.setStyleSheet("background-image: url(" + frameBackground + "); background-color: rgb(25,175,255);") self.scriptsPath.setMinimumHeight(35) #scripts -> browse button self.scriptsBrowse = QtWidgets.QPushButton() self.scriptsLayout.addWidget(self.scriptsBrowse) self.scriptsBrowse.setMinimumSize(35, 35) self.scriptsBrowse.setMaximumSize(35, 35) self.scriptsBrowse.setStyleSheet("background-image: url(" + btnBackground + ");") self.scriptsBrowse.clicked.connect( partial(self.browse, self.scriptsPath)) #icons folder self.iconsLayout = QtWidgets.QHBoxLayout() self.widgetLayout.addLayout(self.iconsLayout) #icons -> label label = QtWidgets.QLabel("Icons: ") self.iconsLayout.addWidget(label) label.setFont(fontSmall) label.setMinimumWidth(150) #icons -> line edit path = utils.returnFriendlyPath(self.iconsPath) self.iconPath = QtWidgets.QLineEdit(path) self.iconsLayout.addWidget(self.iconPath) self.iconPath.setStyleSheet("background-image: url(" + frameBackground + "); background-color: rgb(25,175,255);") self.iconPath.setMinimumHeight(35) #icons -> browse button self.iconsBrowse = QtWidgets.QPushButton() self.iconsLayout.addWidget(self.iconsBrowse) self.iconsBrowse.setMinimumSize(35, 35) self.iconsBrowse.setMaximumSize(35, 35) self.iconsBrowse.setStyleSheet("background-image: url(" + btnBackground + ");") self.iconsBrowse.clicked.connect(partial(self.browse, self.iconsPath)) #projects folder self.projectsLayout = QtWidgets.QHBoxLayout() self.widgetLayout.addLayout(self.projectsLayout) #projects -> label label = QtWidgets.QLabel("Projects: ") self.projectsLayout.addWidget(label) label.setFont(fontSmall) label.setMinimumWidth(150) #projects -> line edit path = utils.returnFriendlyPath(self.projPath) self.projectsPath = QtWidgets.QLineEdit(path) self.projectsLayout.addWidget(self.projectsPath) self.projectsPath.setStyleSheet( "background-image: url(" + frameBackground + "); background-color: rgb(25,175,255);") self.projectsPath.setMinimumHeight(35) #projects -> browse button self.projectsBrowse = QtWidgets.QPushButton() self.projectsLayout.addWidget(self.projectsBrowse) self.projectsBrowse.setMinimumSize(35, 35) self.projectsBrowse.setMaximumSize(35, 35) self.projectsBrowse.setStyleSheet("background-image: url(" + btnBackground + ");") self.projectsBrowse.clicked.connect( partial(self.browse, self.projectsPath)) #Save button self.saveChangesBtn = QtWidgets.QPushButton("Save Changes") self.widgetLayout.addWidget(self.saveChangesBtn) self.saveChangesBtn.setFont(font) self.saveChangesBtn.setMinimumHeight(35) self.saveChangesBtn.setStyleSheet( "background-image: url(" + imageBtnBkrd + ");background-color: rgb(25, 175, 255);") self.saveChangesBtn.clicked.connect(partial(self.saveSettings))
def fbxImport(self): try: #Maya 2015 has one click dependency on FBX. super annoying cmds.loadPlugin("OneClick.mll") except: pass #get the file path from the UI filePath = self.fbxFilePath.text() if not os.path.exists(filePath): cmds.warning("No such file exists") return #stripping namespace if self.stripNamespace.isChecked(): #open maya standalone mayaPath = None for path in sys.path: if path.find("bin") != -1: if path.find("bin" + os.sep) == -1: mayaPath = utils.returnFriendlyPath( os.path.join(path, "mayapy.exe")) #error checking if mayaPath == None: try: msg = interfaceUtils.DialogMessage( "Error", "Unable to locate mayapy.exe", [], 0) msg.show() except: cmds.warning("Unable to locate mayapy.exe.") return scriptPath = utils.returnNicePath( self.scriptPath, "System/ART_StripFbxNamespace.py") #run a subprocess, opening mayapy/mayastandlone, running our stripNameSpace script maya = subprocess.Popen(mayaPath + ' ' + scriptPath + ' ' + filePath, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out = maya.stdout.read() err = maya.stderr.read() print out #get the current character character = self.fbxCharacterCombo.currentText() #duplicate the character's root if cmds.objExists("root"): cmds.warning( "There is already a skeleton in the scene with the name \"root\". Aborting" ) return newSkeleton = cmds.duplicate(character + ":root") cmds.select(newSkeleton) cmds.delete(constraints=True) #go through each module in list, find import method, and setup constraints accordingly moduleItems = [] for i in range(self.fbxModuleList.count()): item = self.fbxModuleList.item(i) itemWidget = self.fbxModuleList.itemWidget(item) itemModule = itemWidget.property("module") children = itemWidget.children() for child in children: if type(child) == QtWidgets.QComboBox: importMethod = child.currentText() moduleItems.append([itemModule, importMethod]) controls = [] postModules = [] #setup the constraints for each in moduleItems: #get inst modType = cmds.getAttr(each[0] + ".moduleType") modName = cmds.getAttr(each[0] + ".moduleName") mod = __import__("RigModules." + modType, {}, {}, [modType]) reload(mod) #list of modules that have post bake operations needed specialModules = ["ART_Leg_Standard"] #get the class name from that module file (returns Modules.ART_Root.ART_Root for example) moduleClass = getattr(mod, mod.className) #find the instance of that module moduleInst = moduleClass(self, modName) #set namespace for instance moduleInst.namespace = character + ":" #run the module's pre import function moduleInst.importFBX_pre(each[1], character) if modType in specialModules: postModules.append([each[1], character, moduleInst]) returnControls = moduleInst.importFBX(each[1], character) if returnControls != None: controls.extend(returnControls) #ensure that the scene is in 30fps cmds.currentUnit(time='ntsc') cmds.playbackOptions(min=0, max=100, animationStartTime=0, animationEndTime=100) cmds.currentTime(0) #import the FBX file string = "FBXImportMode -v \"exmerge\";" string += "FBXImport -file \"" + filePath + "\"" string += "FBXImportFillTimeline -v true" mel.eval(string) #ensure we're on the base layer animLayers = cmds.ls(type="animLayer") if animLayers != []: for layer in animLayers: cmds.animLayer(layer, edit=True, selected=False) cmds.animLayer("BaseAnimation", edit=True, selected=True, preferred=True) #snap timeline to length of imported animation cmds.select("root", hi=True) firstFrame = cmds.findKeyframe(cmds.ls(sl=True), which='first') lastFrame = cmds.findKeyframe(cmds.ls(sl=True), which='last') if lastFrame == firstFrame: lastFrame = lastFrame + 1 cmds.playbackOptions(min=firstFrame, max=lastFrame, animationStartTime=firstFrame, animationEndTime=lastFrame) #BAKE! cmds.select(controls) cmds.bakeResults(simulation=True, t=(firstFrame, lastFrame)) #Post Modules: Modules that have post-bake operations needing to be done for each in postModules: method = each[0] character = each[1] inst = each[2] inst.importFBX_post(method, character) #Clean up (delete duplicate skeleton) cmds.delete("root") #Look at frame offset, and offset animation based on that frameOffset = self.frameOffsetField.value() cmds.select(controls) cmds.keyframe(timeChange=frameOffset, r=True) firstFrame = cmds.findKeyframe(which='first') lastFrame = cmds.findKeyframe(which='last') cmds.playbackOptions(min=firstFrame, max=lastFrame, animationStartTime=firstFrame, animationEndTime=lastFrame)
def importWeights(self): """ Imports skin weights back onto the asset geometry after having rebuilt the skeleton in rig pose. Then calls on ART_BuildProgressUI.preScript(). .. seealso:: ART_BuildProgressUI.preScript() """ meshes = utils.findAllSkinnableGeo() self.currentTask.setRange(0, len(meshes)) self.currentTask.setValue(0) self.infoText.append("\n") self.infoText.append("|| IMPORTING SKIN WEIGHTS ||") for mesh in meshes: filePath = utils.returnFriendlyPath(os.path.join(cmds.internalVar(utd=True), mesh + ".WEIGHTS")) if os.path.exists(filePath): riggingUtils.import_skin_weights(filePath, mesh, True) # update progress and info self.infoText.append(" Imported Skin Weights for " + mesh) curVal = self.currentTask.value() self.currentTask.setValue(curVal + 1) # remove skin file os.remove(filePath) else: # update progress and info self.infoText.setTextColor(QtGui.QColor(236, 217, 0)) self.infoText.append(" Could not import weights for " + mesh) self.infoText.setTextColor(QtGui.QColor(255, 255, 255)) self.warnings += 1 curVal = self.currentTask.value() self.currentTask.setValue(curVal + 1) # update main progress bar self.totalProgress.setValue(5) # call on the prescript self.preScript() # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # def exportMeshes(self): # # lodAttrs = utils.getLodData() # exportData = utils.findExportMeshData() # # self.currentTask.setRange(0, len(lodAttrs)) # self.currentTask.setValue(0) # # # #save the file # saveFile = cmds.file(q = True, sceneName = True) # # # try: # cmds.file(save = True) # except Exception, e: # cmds.error("Could not save file. Error: " + str(e)) # return # # # #for each LOD # for each in exportData: # meshValue = each[1] # pathValue = each[0] # boneValue = each[2] # poseData = each[3] # utils.exportMesh(self.mainUI, meshValue, pathValue, boneValue, poseData) # # #open the file # cmds.file(saveFile, open = True, force = True) # # #update UI # self.infoText.setTextColor(QtGui.QColor(0,255,18)) # self.infoText.append(" SUCCESS: FBX file exported.") # self.infoText.append(" " + str(pathValue)) # self.infoText.setTextColor(QtGui.QColor(255,255,255)) # # #update progress bar # curVal = self.currentTask.value() # self.currentTask.setValue(curVal + 1) # # #update main progress bar # self.totalProgress.setValue(7) # # #run pre-script # self.preScript() """
def exportWeights(self): """ Exports all skin weights of meshes that have skinClusters to a .weights file (JSON). It also has functionality to deal with morph targets, making sure they are preserved when history on the meshes is deleted. .. seealso:: riggingUtils.export_skin_weights() """ self.infoText.append("\n") self.infoText.append("|| EXPORTING SKIN WEIGHTS ||") # find meshes that are weighted weightedMeshes = [] skinClusters = cmds.ls(type='skinCluster') for cluster in skinClusters: geometry = cmds.skinCluster(cluster, q=True, g=True)[0] geoTransform = cmds.listRelatives(geometry, parent=True)[0] weightedMeshes.append([geoTransform, cluster]) # update progress bar numMeshes = len(weightedMeshes) self.currentTask.setRange(0, numMeshes) self.currentTask.setValue(0) # save out weights of meshes for mesh in weightedMeshes: filePath = utils.returnFriendlyPath(os.path.join(cmds.internalVar(utd=True), mesh[0] + ".WEIGHTS")) # export skin weights riggingUtils.export_skin_weights(filePath, mesh[0]) # CHECK FOR MORPH TARGETS blendshapeList = [] # find blendshapes skinCluster = riggingUtils.findRelatedSkinCluster(mesh[0]) if skinCluster is not None: blendshapes = cmds.listConnections(skinCluster + ".input", source=True, type="blendShape") deleteShapes = [] if blendshapes is not None: for each in blendshapes: attrs = cmds.listAttr(each, m=True, string="weight") if attrs is not None: for attr in attrs: # if not, manually create shapes by toggling attrs and duplicating mesh if not cmds.objExists(attr): cmds.setAttr(each + "." + attr, 1) dupe = cmds.duplicate(mesh[0])[0] # parent to world parent = cmds.listRelatives(dupe, parent=True) if parent is not None: cmds.parent(dupe, world=True) # rename the duplicate mesh to the blendshape name cmds.rename(dupe, attr) cmds.setAttr(each + "." + attr, 0) deleteShapes.append(attr) # add the blendshape node name and its attrs to the master blendshape list blendshapeList.append([each, attrs]) # delete history of meshes cmds.delete(mesh[0], ch=True) # reapply blendshapes for item in blendshapeList: bshapeName = item[0] shapeList = item[1] i = 1 for shape in shapeList: if cmds.objExists(bshapeName): cmds.blendShape(bshapeName, edit=True, t=(mesh[0], i, shape, 1.0)) else: cmds.select([shape, mesh[0]], r=True) cmds.blendShape(name=bshapeName) cmds.select(clear=True) try: for each in deleteShapes: cmds.delete(each) except: pass # update progress and info self.infoText.append(" Exported Skin Weights for " + mesh[0]) curVal = self.currentTask.value() self.currentTask.setValue(curVal + 1) # update main progress bar self.totalProgress.setValue(1) self.infoText.append("\n") # rebuild the skeleton in rig pose self.rebuildSkeleton()