Script Description:
This script is for a character importer. I wrote two versions one for Maya and one for Motion Builder. The script relies on a folder structure where the first folder holds a series of folders for different projects and in each of the project folders there are FBX files containing characters. When the user hits the import button it imports the specified character as a reference in the Maya version and merges the file into the current scene for the Motion Builder version.UI:
For this script I wrote a fairly simple UI containing two
dropdown menus, a check box with a place to input a name space and a button
that says import character. The idea was to use the dropdowns to let the user
select the files without making them enter a path themselves.
One of the things I used for the first time while writing this script was a validator to limit the possible inputs into the namespace line edit. The validator limited the first input to be a letter or an underscore and further inputs to be letters, numbers or underscores.
One of the things I used for the first time while writing this script was a validator to limit the possible inputs into the namespace line edit. The validator limited the first input to be a letter or an underscore and further inputs to be letters, numbers or underscores.
#adds a validator to limit possible inputs into the LineEdit v = QtCore.QRegExp('[A-Z|a-z|_]\w+') self.validator = QtGui.QRegExpValidator(v) self.textField.setValidator(self.validator)
Functions:
One of the other challenges with this script was make sure
that the user couldn't break things by reusing namespaces or importing the same
character without a namespace twice. This is especially important in Motion Builder
because it will overwrite things already in the scene if you merge something
with the same naming into the scene. In Motion Builder I decided to compare the name of the character or the namespace to objects already in the scene using the find objects by name function that is built into Motion Builder. For the case of looking for characters without namespaces I also limited the type of the object to constraint since in Motion Builder characters are constraints.
#this function checks if character or namespace is already in use before importing def warningsCheck(self): warning = False if self.checkbox.isChecked() == True: #checks scene for the namespace namespace = str(self.textField.text()) searchName = str(self.textField.text() + ':*') foundCharacters = utils.findObjects(searchName) #if nothing was found using that namespace import the character with the namespace if len(foundCharacters) > 0: namespaceWarning = QtGui.QMessageBox() namespaceWarning.setWindowTitle('Warning') namespaceWarning.setText('This namespace is already in use. Please change namespace to import.') namespaceWarning.exec_() warning = True #if no namespace is set elif self.checkbox.isChecked() == False: #gets the name of the character fileName = str(self.charDropdown.currentText()) #removes _skel.fbx from the character name charName = utils.shortenString(fileName, 9) #looks for uses of the character name in the scene foundCharacters = utils.findObjects(charName) charExists = False #checks to see if there is a motionbuilder character with the given name in the list for char in foundCharacters: if str(char.FullName) == str('Constraint::' + charName): charExists = True break #if no character was found imports the character if charExists == True: charExistsWarning = QtGui.QMessageBox() charExistsWarning.setWindowTitle('Warning') charExistsWarning.setText('This character is already in the scene. Please add a namespace to import') charExistsWarning.exec_() warning = True return warning return warning
For importing the character I wrote a utility function
that I kept in a separate utility file since this is defiantly a process that
could be used in other scripts. One of the things that I found tricky to grasp
when starting scripting in Motion Builder was that things like merge options
are their own object in Motion Builder. My function starts by setting merge options then checks if the user wants a namespace then merges the file.
#merges in a character to the current scene def mergeCharacter(namespace, fileName, FBApp): mergeOptions = FBFbxOptions(True) if not namespace == None: Names = FBStringList(str(namespace)) mergeOptions.SetMultiLoadNamespaceList(Names) FBApp.FileMerge(fileName, False, mergeOptions)
In the Maya version of the script I do both the importing
and warning checks in the same function. In the pymel library there is a simple
function called namespace that with the flag exists can check if that namespace
is in use in the scene which was simpler than the method I used in Motion
Builder. Though I did have to get a list of referenced nodes in Maya and
compare names to check for the existence of a character much like I did in
Motion Builder when a namespace wasn't used.
#checks for characters in the scene and imports character if no warnings def importChar(self): importFile = self.path + '\\' + self.prjDropdown.currentText() + '\\' + self.charDropdown.currentText() #if the user set a namespace and the namespace doesn't exist in maya reference the character if self.checkbox.isChecked() == True and (pm.namespace(exists = self.textBox.text()) == False): pm.createReference(importFile, namespace = self.textBox.text()) #if the user did not set a namespace check if character is already in the scene elif self.checkbox.isChecked() == False: charExists = False #gets list of referecned nodes list = pm.ls(rf = True) #gets charater name from character dropdown menu fileName = self.charDropdown.currentText() #removes .fbx and adds RN for reference name charName = fileName[0:(len(fileName)-4)] +'RN' #compares references to character name for node in list: #if the character is in the scene it marks character Exists as true if charName == node: charExists = True break #if the character exists give the user a warning if charExists == True: charExistsWarning = QtWidgets.QMessageBox() charExistsWarning.setWindowTitle('Warning') charExistsWarning.setText('This character is already in the scene. Please add a namespace to import.') charExistsWarning.exec_() #if the character doesn't exist refrence the character else: pm.createReference(importFile) #if the users set a namespace and the namespace exists in maya give the user a warning else: namespaceWarning = QtWidgets.QMessageBox() namespaceWarning.setWindowTitle('Warning') namespaceWarning.setText('This namespace is already in use. Please change namespace to import.') namespaceWarning.exec_()
The second drop down menu that held the characters for import
needed to update based off of the first drop down menu which held the projects. The first thing
that this function does is clear the character drop down menu of old characters. Next it alters
the path to look in the new project folder and gets a list of the folders
contents. After that using a for loop it filters for FBX files by using the endswith() python string function to check for
.fbx on the end of file names. This allows me to be sure that the file the user picks is one that either Motion Builder or Maya can open. If it ends with .fbx it's added to the character
drop down menu.
#changes the contents of the second dropbox based off the folder selected by the first dropbox def setupCharDropdown(self): self.charDropdown.clear() path = FILEPATH + '\\' + self.prjDropdown.currentText() files = os.listdir(path) for f in files: if f.endswith('.fbx') == True: self.charDropdown.addItem(f)
No comments:
Post a Comment