aboutsummaryrefslogtreecommitdiff
path: root/Core/Scripts/Interfaces/ART_BuildProgressUI.py
diff options
context:
space:
mode:
Diffstat (limited to 'Core/Scripts/Interfaces/ART_BuildProgressUI.py')
-rw-r--r--Core/Scripts/Interfaces/ART_BuildProgressUI.py835
1 files changed, 835 insertions, 0 deletions
diff --git a/Core/Scripts/Interfaces/ART_BuildProgressUI.py b/Core/Scripts/Interfaces/ART_BuildProgressUI.py
new file mode 100644
index 0000000..809c2d1
--- /dev/null
+++ b/Core/Scripts/Interfaces/ART_BuildProgressUI.py
@@ -0,0 +1,835 @@
+"""
+Author: Jeremy Ernst
+"""
+
+import os
+
+import maya.cmds as cmds
+import maya.mel as mel
+import System.utils as utils
+
+import System.interfaceUtils as interfaceUtils
+import System.riggingUtils as riggingUtils
+from ThirdParty.Qt import QtGui, QtCore, QtWidgets
+
+
+class ART_BuildProgress_UI():
+ """
+ This class kicks off building all of the rigs for the modules. It displays an interface that shows progress and
+ displays information about the rig build.
+
+ It exports skin weights, rebuilds the skeleton in rig pose, imports skin weights, runs any pre-script,
+ calls on each module's rig building code, sets up rig parenting and hierarchy, and finally runs any post-script.
+
+ .. image:: /images/buildProgress.gif
+
+ """
+
+ 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 buildUI(self):
+ """
+ Builds the interface, which doesn't really have any user-interaction, but is there to display information
+ about the progress of the rig build. There are two QProgressBars that show current module build progress and
+ total build progress, then a QTextEdit which outputs information about what the build process is currently
+ working on.
+
+ After the interface is built, it sets the rig pose on the joints of each module.
+
+ """
+
+ # create the main window
+ self.mainWin = QtWidgets.QMainWindow(interfaceUtils.getMainWindow())
+ self.mainWin.setStyleSheet("background-color: rgb(0, 0, 0);, color: rgb(0,0,0);")
+
+ styleSheetFile = utils.returnNicePath(self.toolsPath, "Core/Scripts/Interfaces/StyleSheets/mainScheme.qss")
+ f = open(styleSheetFile, "r")
+ self.style = f.read()
+ f.close()
+
+ self.mainWin.setStyleSheet(self.style)
+
+ # create the main widget
+ self.mainWidget = QtWidgets.QWidget()
+ self.mainWin.setCentralWidget(self.mainWidget)
+
+ # set qt object name
+ self.mainWin.setObjectName("ART_BuildProgressWin")
+ self.mainWin.setWindowTitle("Build Progress")
+
+ # font
+ headerFont = QtGui.QFont()
+ headerFont.setPointSize(8)
+ headerFont.setBold(True)
+
+ # set size policy
+ mainSizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+
+ # create the mainLayout for the rig creator UI
+ self.layout = QtWidgets.QVBoxLayout(self.mainWidget)
+
+ self.mainWin.resize(500, 300)
+ self.mainWin.setSizePolicy(mainSizePolicy)
+ self.mainWin.setMinimumSize(QtCore.QSize(500, 300))
+ self.mainWin.setMaximumSize(QtCore.QSize(500, 300))
+
+ # create the QFrame for this page
+ self.background = QtWidgets.QFrame()
+ self.layout.addWidget(self.background)
+ self.mainLayout = QtWidgets.QVBoxLayout(self.background)
+ self.background.setObjectName("epic")
+
+ # build the progress bars:
+
+ self.currentTask = QtWidgets.QProgressBar()
+ self.mainLayout.addWidget(self.currentTask)
+ self.currentTask.setRange(0, 100)
+ self.currentTask.setTextVisible(True)
+ self.currentTask.setValue(0)
+
+ self.totalProgress = QtWidgets.QProgressBar()
+ self.mainLayout.addWidget(self.totalProgress)
+ self.totalProgress.setFormat("Total Progress..")
+ self.totalProgress.setRange(0, 12)
+ self.totalProgress.setTextVisible(True)
+ self.totalProgress.setValue(0)
+
+ # detailed information
+ self.infoText = QtWidgets.QTextEdit()
+ self.mainLayout.addWidget(self.infoText)
+ self.infoText.setMinimumHeight(200)
+ self.infoText.setMaximumHeight(200)
+ self.infoText.setText("Starting Build Process..")
+ self.infoText.setReadOnly(True)
+
+ # show the window
+ self.mainWin.show()
+
+ # start build
+ self.setRigPose()
+
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ 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()
+
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ def setRigPose(self):
+ """
+ Sets the rig pose on each module's joints. Lastly, calls on ART_BuildProgressUI.exportWeights()
+
+ ..seealso :: ART_BuildProgressUI.exportWeights()
+
+ """
+
+ # set rig pose
+ self.infoText.append("Setting Rig Pose..")
+ numMods = len(self.mainUI.moduleInstances) - 1
+
+ self.currentTask.setRange(0, numMods)
+ self.currentTask.setValue(0)
+
+ for inst in self.mainUI.moduleInstances:
+ if inst.name != "root":
+ inst.setupForRigPose()
+ inst.setReferencePose("rigPose")
+ inst.cleanUpRigPose()
+ curVal = self.currentTask.value()
+ self.currentTask.setValue(curVal + 1)
+
+ # update main progress bar
+ self.totalProgress.setValue(2)
+
+ self.exportWeights()
+
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ def rebuildSkeleton(self):
+ """
+ Rebuilds the skeleton in rig pose, meaning that all joint rotations will be zeroed in rig pose rather than
+ model pose. This ensures clean rigging.
+
+ Lastly, calls on ART_BuildProgressUI.importWeights() to reimport weighting back onto the meshes.
+
+ .. seealso:: riggingUtils.buildSkeleton(), ART_BuildProgressUI.importWeights()
+
+ """
+
+ # rebuild the skeleton
+ cmds.delete("root")
+
+ self.infoText.append("Rebuilding Skeleton in Rig Pose..")
+
+ # build skeleton from utils
+ riggingUtils.buildSkeleton()
+
+ # update main progress bar
+ self.totalProgress.setValue(3)
+
+ # import weights
+ self.importWeights()
+
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ 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()
+
+ """
+ Keeping this around for now, but currently it is not being used.
+ Exporting is now done through edit rig -> Export Skeletal Meshes
+ """
+
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ def preScript(self):
+ """
+ If there is a pre-script to run, this will call on ART_BuildProgressUI.executeScript() to run the pre-script.
+ Then it will call on ART_BuildProgressUI.buildRigs() to build each module's rigs.
+
+ .. note:: Pre-Scipts are used if you ever want to do something to your character before the rig gets built.
+ An example usage would be adding IK joints for UE4 in a pre-script, as you don't want or need
+ controls for those IK joints, and setting up those constraints.
+
+ .. seealso:: ART_BuildProgressUI.executeScript(), ART_BuildProgressUI.buildRigs()
+
+ """
+
+ self.infoText.append(" \n")
+
+ # get pre-script path from character node, if it exists
+ characterNode = utils.returnCharacterModule()
+ if cmds.objExists(characterNode + ".preScriptPath"):
+ scriptPath = cmds.getAttr(characterNode + ".preScriptPath")
+ self.infoText.append("Executing Pre-Script..")
+ self.infoText.append(" " + scriptPath)
+
+ # try to execute the pre-script
+ status = self.executeScript(scriptPath)
+ if status:
+ self.infoText.setTextColor(QtGui.QColor(0, 255, 18))
+ self.infoText.append(" SUCCESS: Pre-Script Was Successfully Executed..")
+ self.infoText.setTextColor(QtGui.QColor(255, 255, 255))
+
+ if not status:
+ self.infoText.setTextColor(QtGui.QColor(255, 0, 0))
+ self.infoText.append(" FAILED: Pre-Script Was Not Successfully Executed..")
+ self.infoText.setTextColor(QtGui.QColor(255, 255, 255))
+ self.errors += 1
+ else:
+ self.infoText.setTextColor(QtGui.QColor(255, 255, 0))
+ self.infoText.append("No Pre-Script To Run..")
+ self.infoText.setTextColor(QtGui.QColor(255, 255, 255))
+
+ # update main progress bar
+ self.totalProgress.setValue(8)
+
+ # build rigs
+ self.buildRigs()
+
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ def buildRigs(self):
+ """
+ First, create a driver skeleton which the rig will build upon, then calls on each module's buildCustomRig
+ function, which will build the rig for that module, then sets up rig parenting and hiearchy once all modules
+ are built.
+
+ Lastly, calls on the function to execute a post script if one was given during publish.
+
+ .. seealso:: riggingUtils.createDriverSkeleton(), ART_BuildProgressUI.postScript()
+
+ """
+
+ self.infoText.append(" \n")
+ self.infoText.append("|| PREPARING TO BUILD CONTROL RIGS.. ||")
+
+ # Update Current Task bar with num modules
+ self.currentTask.setRange(0, len(self.mainUI.moduleInstances))
+ self.currentTask.setValue(0)
+
+ # create the driver skeleton
+ riggingUtils.createDriverSkeleton()
+
+ # Loop through modules, building rigs
+ for inst in self.mainUI.moduleInstances:
+ self.infoText.append(" \n")
+ self.infoText.append(" Building: " + str(inst.name))
+
+ # build module rigs
+ inst.buildRig(self.infoText, self)
+
+ # update progress bar
+ curVal = self.currentTask.value()
+ self.currentTask.setValue(curVal + 1)
+
+ # =======================================================================
+ # #Setup the rig parenting
+ # =======================================================================
+ for data in self.rigData:
+ createdConstraints = []
+
+ if data[1] == "driver_root":
+ pConst = cmds.pointConstraint("offset_anim", data[0], mo=True)[0]
+ oConst = cmds.orientConstraint("offset_anim", data[0], mo=True)[0]
+ if pConst not in createdConstraints:
+ createdConstraints.append(pConst)
+ if oConst not in createdConstraints:
+ createdConstraints.append(oConst)
+
+ else:
+ # get the connections of the passed in parent bone
+ connections = []
+ for connection in cmds.listConnections(data[1], type="constraint"):
+ connections.append(connection)
+
+ for connection in list(set(connections)):
+ constraintType = cmds.nodeType(connection)
+ driveAttrs = []
+ targetWeights = []
+
+ # get those constraint target attributes for each constraint connection
+ targets = cmds.getAttr(connection + ".target", mi=True)
+ if len(targets) >= 1:
+ for each in targets:
+ # get the names of the constraint targets
+ targetWeights.append(
+ cmds.listConnections(connection + ".target[" + str(each) + "].targetWeight",
+ p=True)[0])
+ for targetWeight in targetWeights:
+ name = targetWeight.rpartition(".")[2]
+ name = name.rpartition("W")[0]
+ if name not in driveAttrs:
+ driveAttrs.append(name)
+
+ # Setup constraint between the driveAttrs and the rigData[0] node
+ for attr in driveAttrs:
+ print attr, data[0]
+ if constraintType == "pointConstraint":
+ try:
+ pConst = cmds.pointConstraint(attr, data[0], mo=True)[0]
+ if pConst not in createdConstraints:
+ createdConstraints.append(pConst)
+ except Exception, e:
+ cmds.warning(str(e))
+
+ if constraintType == "orientConstraint":
+ try:
+ oConst = cmds.orientConstraint(attr, data[0], mo=True)[0]
+ if oConst not in createdConstraints:
+ createdConstraints.append(oConst)
+ except Exception, e:
+ cmds.warning(str(e))
+
+ if constraintType == "parentConstraint":
+ try:
+ paConst = cmds.parentConstraint(attr, data[0], mo=True)[0]
+ if paConst not in createdConstraints:
+ createdConstraints.append(paConst)
+ except Exception, e:
+ cmds.warning(str(e))
+
+ # get the names of the constraint targets
+ for const in createdConstraints:
+ constraintAttrs = []
+ targets = cmds.getAttr(const + ".target", mi=True)
+ for each in targets:
+ constraintAttrs.append(
+ cmds.listConnections(const + ".target[" + str(each) + "].targetWeight", p=True)[0])
+
+ # setup connections between the parent bone constraints and the newly created constraints
+ if len(constraintAttrs) > 0:
+ for i in range(len(constraintAttrs)):
+ try:
+ cmds.connectAttr(targetWeights[i], constraintAttrs[i])
+ except:
+ pass
+
+ # =======================================================================
+ # #set the state on the main network node
+ # =======================================================================
+ if cmds.objExists("ART_RIG_ROOT.state"):
+ cmds.setAttr("ART_RIG_ROOT.state", 2)
+
+ # =======================================================================
+ # #hide all joints
+ # =======================================================================
+ joints = cmds.ls(type="joint")
+ for joint in joints:
+ try:
+ cmds.setAttr(joint + ".v", lock=False)
+ cmds.setAttr(joint + ".v", 0, lock=True)
+ except:
+ pass
+
+ # =======================================================================
+ # #remove unused skin influences to optimize scene
+ # =======================================================================
+ mel.eval("removeAllUnusedSkinInfs()")
+
+ # =======================================================================
+ # #save the file
+ # =======================================================================
+ cmds.file(save=True, type="mayaAscii")
+
+ # update main progress bar
+ self.totalProgress.setValue(9)
+
+ # =======================================================================
+ # #execute post script
+ # =======================================================================
+ self.postScript()
+
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ def postScript(self):
+ """
+ If there is a post-script to run, this will call on ART_BuildProgressUI.executeScript() to run the post-script.
+ Then it will call on ART_BuildProgressUI.completeBuild() which wraps up the build process and alerts the user
+ the build is done.
+
+ .. note:: Post-Scipts are used if you ever want to do something to your character after the rig gets built.
+ An example usage would be adding custom rigging to joints or controls in the scene, setting up custom
+ relationships or set-driven keys, etc.
+
+ .. seealso:: ART_BuildProgressUI.executeScript(), ART_BuildProgressUI.completeBuild()
+
+ """
+
+ self.infoText.append(" \n")
+
+ # get pre-script path from character node, if it exists
+ characterNode = utils.returnCharacterModule()
+ if cmds.objExists(characterNode + ".postScriptPath"):
+ scriptPath = cmds.getAttr(characterNode + ".postScriptPath")
+ self.infoText.append("Executing Post-Script..")
+ self.infoText.append(" " + scriptPath)
+
+ # try to execute the pre-script
+ status = self.executeScript(scriptPath)
+ if status:
+ self.infoText.setTextColor(QtGui.QColor(0, 255, 18))
+ self.infoText.append(" SUCCESS: Post-Script Was Successfully Executed..")
+ self.infoText.setTextColor(QtGui.QColor(255, 255, 255))
+
+ if not status:
+ self.infoText.setTextColor(QtGui.QColor(255, 0, 0))
+ self.infoText.append(" FAILED: Post-Script Was Not Successfully Executed..")
+ self.infoText.setTextColor(QtGui.QColor(255, 255, 255))
+ self.errors += 1
+
+ else:
+ self.infoText.setTextColor(QtGui.QColor(255, 255, 0))
+ self.infoText.append("No Post-Script To Run..")
+ self.infoText.setTextColor(QtGui.QColor(255, 255, 255))
+
+ # update main progress bar
+ self.totalProgress.setValue(10)
+
+ # capture model pose for rig controls
+ cmds.file(save=True, type="mayaAscii")
+ self.completeBuild()
+
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ def completeBuild(self):
+ """
+ Locks down all network nodes, saves the scene, and alerts user that the rig build is complete.
+
+ """
+
+ self.infoText.append(" \n")
+ self.infoText.append("Cleaning Up..")
+
+ # go through each module instance, and lock down the nodes
+ cmds.select("rig_grp", hi=True)
+ rigNodes = cmds.ls(sl=True)
+ numNodes = len(rigNodes)
+ self.currentTask.setMaximum(numNodes)
+
+ for node in rigNodes:
+ curVal = self.currentTask.value()
+
+ try:
+ cmds.lockNode(node, lock=True)
+ self.currentTask.setValue(curVal + 1)
+
+ except:
+ pass
+
+ # save scene
+ cmds.file(save=True, type="mayaAscii")
+
+ # iterate total progress
+ self.totalProgress.setValue(12)
+
+ # add build info
+ font = QtGui.QFont()
+ font.setPointSize(20)
+ font.setBold(True)
+
+ self.infoText.setFont(font)
+ self.infoText.setTextColor(QtGui.QColor(0, 255, 18))
+ self.infoText.append("\n\nPUBLISH COMPLETE!")
+
+ font.setPointSize(8)
+ font.setBold(False)
+ self.infoText.setTextColor(QtGui.QColor(255, 255, 255))
+ self.infoText.setFont(font)
+
+ # get file name
+ fileName = cmds.file(q=True, sceneName=True)
+ iconPath = cmds.getAttr("ART_RIG_ROOT.iconPath")
+
+ self.infoText.append("Assets Created: ")
+ self.infoText.append(" " + fileName)
+ self.infoText.append(" " + iconPath)
+ self.infoText.append(str(self.warnings) + " warnings")
+ self.infoText.append(str(self.errors) + " errors")
+
+ # tell user build is complete
+ msgBox = QtWidgets.QMessageBox()
+ msgBox.setIcon(QtWidgets.QMessageBox.Information)
+ msgBox.setText("Rig Build Complete!")
+ msgBox.addButton("New Scene", QtWidgets.QMessageBox.YesRole)
+ msgBox.addButton("Edit Rig", QtWidgets.QMessageBox.NoRole)
+ ret = msgBox.exec_()
+
+ if ret == 1:
+ import ART_RigCreatorUI as ART_RigCreatorUI
+ reload(ART_RigCreatorUI)
+ ART_RigCreatorUI.createUI()
+ cmds.refresh(force=True)
+ cmds.dockControl("pyArtRigCreatorDock", e=True, r=True)
+
+ else:
+
+ # if the rigCreatorUI exists delete UI
+ if cmds.dockControl("pyArtRigCreatorDock", q=True, exists=True):
+ cmds.deleteUI("pyArtRigCreatorUi")
+ cmds.deleteUI("pyArtRigCreatorDock", control=True)
+
+ cmds.file(new=True)
+
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+
+ def executeScript(self, scriptPath):
+ """
+ Takes a given script (mel or python) and runs it.
+
+ :param scriptPath: location of the script to be evaluated and ran.
+
+ :return: Whether or not the execution of the script failed or not.
+
+ .. seealso:: ART_BuildProgressUI.preScript(), ART_BuildProgressUI.postScript()
+
+ """
+
+ sourceType = ""
+ status = False
+
+ if scriptPath.find(".py") != -1:
+ sourceType = "python"
+
+ if scriptPath.find(".mel") != -1:
+ sourceType = "mel"
+
+ # MEL
+ if sourceType == "mel":
+ try:
+ command = ""
+ # open the file, and for each line in the file, add it to our command string.
+ f = open(scriptPath, 'r')
+ lines = f.readlines()
+ for line in lines:
+ command += line
+
+ import maya.mel as mel
+ mel.eval(command)
+
+ # save the file
+ cmds.file(save=True, type="mayaAscii")
+ status = True
+ except:
+ pass
+
+ # PYTHON
+ if sourceType == "python":
+ try:
+ execfile("" + scriptPath + "")
+
+ # save the file
+ cmds.file(save=True, type="mayaAscii")
+ status = True
+ except:
+ pass
+
+ return status