aboutsummaryrefslogtreecommitdiff
path: root/Core/Scripts/RigModules/ART_Chain.py
diff options
context:
space:
mode:
authorMobileMachine\jeremy <[email protected]>2017-06-06 22:59:03 -0400
committerMobileMachine\jeremy <[email protected]>2017-06-06 22:59:03 -0400
commit24725fa8681f906ab44d80687c09fecc171a2896 (patch)
tree312a601df29aca7f8db9f44082d96ebc7a679138 /Core/Scripts/RigModules/ART_Chain.py
parentInitial commit (diff)
downloadartv2-24725fa8681f906ab44d80687c09fecc171a2896.tar.xz
artv2-24725fa8681f906ab44d80687c09fecc171a2896.zip
Initial Submission
First submission of current state of ARTv2. Currently considered to be in Alpha. There are a couple of animation tools not implemented yet, and one module not implemented yet, as well as incomplete documentation.
Diffstat (limited to 'Core/Scripts/RigModules/ART_Chain.py')
-rw-r--r--Core/Scripts/RigModules/ART_Chain.py294
1 files changed, 294 insertions, 0 deletions
diff --git a/Core/Scripts/RigModules/ART_Chain.py b/Core/Scripts/RigModules/ART_Chain.py
new file mode 100644
index 0000000..7420c43
--- /dev/null
+++ b/Core/Scripts/RigModules/ART_Chain.py
@@ -0,0 +1,294 @@
+"""
+Author: Jeremy Ernst
+
+===============
+File Attributes
+===============
+ * **icon:** This is the image file (125x75 .png) that gets used in the RigCreatorUI
+
+ * **hoverIcon:** When you hover over the module in the module list, it will swap to this icon
+ (background changes to orange). There are .psd template files for these.
+
+ * **search:** These are search terms that are accepted when searching the list of modules in the
+ RigCreatorUI
+
+ * **class name:** The name of the class.
+
+ * **jointMover:** The relative path to the joint mover file. Relative to the ARTv2 root directory.
+
+ * **baseName:** The default name the module will get created with. Users can then add a prefix and/or
+ suffix to the base name.
+
+ * **rigs:** This is a simple list of what rigs this module can build. This feature isn't implemented yet,
+ but the plan is to query this list and present these options to the user for them to select what rigs
+ they want to build for the module. Right now, it will build all rigs.
+
+ * **fbxImport:** This is a list that will show the options for the module in the import mocap interface.
+ Normally, this list will have at least None and FK.
+
+ * **matchData:** This is a list of options that will be presented for the module in a comboBox in the
+ match over frame range interface. First argument is a bool as to whether the module can or can't
+ match. The second arg is a list of strings to display for the match options. For example:
+ matchData = [True, ["Match FK to IK", "Match IK to FK"]]
+
+ * **controlTypes:** This is a list of lists, where each item in the main list is a list comprised of the
+ name of the attribute that gets added to the network node that contains the control information.
+ The second arg in each list entry is a control type, like FK or IK. This is used in the select
+ rig controls interface for filtering out which controls on each module you want to select. On
+ this module, the values are: controlTypes = [["fkControls", "FK"]], which means that the
+ attribute that holds the control info is called fkControls, and those controls are of type FK.
+
+ .. image:: /images/selectRigControls.png
+
+===============
+Class
+===============
+"""
+# file imports
+import json
+import os
+from functools import partial
+
+import maya.cmds as cmds
+
+import System.interfaceUtils as interfaceUtils
+import System.riggingUtils as riggingUtils
+import System.utils as utils
+from System.ART_RigModule import ART_RigModule
+from ThirdParty.Qt import QtGui, QtCore, QtWidgets
+
+# file attributes
+icon = "Modules/chain.png"
+hoverIcon = "Modules/hover_chain.png"
+search = "chain"
+className = "ART_Chain"
+jointMover = "Core/JointMover/ART_Chain.ma"
+baseName = "chain"
+rigs = ["FK", "IK", "Dynamic"]
+fbxImport = ["None", "FK", "IK", "Both"]
+matchData = [True, ["Match FK to IK", "Match IK to FK"]]
+controlTypes = [["fkControls", "FK"], ["ikControls", "IK"], ["dynControls", "FK"]]
+
+
+class ART_Chain(ART_RigModule):
+ """This class creates the chain module, which can have a minimum of 2 joints and a maximum of 99."""
+
+ def __init__(self, rigUiInst, moduleUserName):
+ """Initiate the class, taking in the instance to the interface and the user specified name.
+
+ :param rigUiInst: This is the rig creator interface instance being passed in.
+ :param moduleUserName: This is the name specified by the user on module creation.
+
+ Instantiate the following class variables as well:
+ * **self.rigUiInst:** take the passed in interface instance and make it a class var
+ * **self.moduleUserName:** take the passed in moduleUserName and make it a class var
+ * **self.outlinerWidget:** an empty list that will hold all of the widgets added to the outliner
+
+ Also, read the QSettings to find out where needed paths are.
+ """
+
+ self.rigUiInst = rigUiInst
+ self.moduleUserName = moduleUserName
+ self.outlinerWidgets = {}
+
+ settings = QtCore.QSettings("Epic Games", "ARTv2")
+ self.toolsPath = settings.value("toolsPath")
+
+ ART_RigModule.__init__(self, "ART_Chain_Module", "ART_Chain", moduleUserName)
+
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ def addAttributes(self):
+ """
+ Add custom attributes this module needs to the network node.
+
+ Always calls on base class function first, then extends with any attributes unique to the class.
+ """
+
+ # call the base class method first to hook up our connections to the master module
+ ART_RigModule.addAttributes(self)
+
+ # add custom attributes for this specific module
+ cmds.addAttr(self.networkNode, sn="Created_Bones", dt="string", keyable=False)
+ cmds.setAttr(self.networkNode + ".Created_Bones", "joint_01::joint_02::joint_03::", type="string", lock=True)
+
+ cmds.addAttr(self.networkNode, sn="baseName", dt="string", keyable=False)
+ cmds.setAttr(self.networkNode + ".baseName", baseName, type="string", lock=True)
+
+ cmds.addAttr(self.networkNode, sn="canAim", at="bool", keyable=False)
+ cmds.setAttr(self.networkNode + ".canAim", True, lock=True)
+
+ cmds.addAttr(self.networkNode, sn="aimMode", at="bool", keyable=False)
+ cmds.setAttr(self.networkNode + ".aimMode", False, lock=True)
+
+ cmds.addAttr(self.networkNode, sn="numJoints", keyable=False)
+ cmds.setAttr(self.networkNode + ".numJoints", 3, lock=True)
+
+ cmds.addAttr(self.networkNode, sn="hasDynamics", at="bool", keyable=False)
+ cmds.setAttr(self.networkNode + ".hasDynamics", False, lock=True)
+
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
+ def skeletonSettings_UI(self, name):
+ """
+ This is the UI for the module that has all of the configuration settings.
+
+ :param name: user given name of module (prefix + base_name + suffix)
+ :param width: width of the skeleton settings groupBox. 335 usually
+ :param height: height of the skeleton settings groupBox.
+ :param checkable: Whether or not the groupBox can be collapsed.
+
+
+ Build the groupBox that contains all of the settings for this module. Parent the groupBox
+ into the main skeletonSettingsUI layout.
+ Lastly, call on updateSettingsUI to populate the UI based off of the network node values.
+
+ .. image:: /images/skeletonSettings.png
+
+ """
+ # width, height, checkable
+
+ networkNode = self.returnNetworkNode
+ font = QtGui.QFont()
+ font.setPointSize(8)
+
+ headerFont = QtGui.QFont()
+ headerFont.setPointSize(8)
+ headerFont.setBold(True)
+
+ # groupbox all modules get
+ ART_RigModule.skeletonSettings_UI(self, name, 335, 288, True)
+
+ # STANDARD BUTTONS
+
+ # create a VBoxLayout to add to our Groupbox and then add a QFrame for our signal/slot
+ self.mainLayout = QtWidgets.QVBoxLayout(self.groupBox)
+ self.frame = QtWidgets.QFrame(self.groupBox)
+ self.mainLayout.addWidget(self.frame)
+ self.frame.setSizePolicy(QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed))
+ self.frame.setMinimumSize(QtCore.QSize(320, 270))
+ self.frame.setMaximumSize(QtCore.QSize(320, 270))
+
+ # create layout that is a child of the frame
+ self.layout = QtWidgets.QVBoxLayout(self.frame)
+
+ # mirror module
+ self.mirrorModLayout = QtWidgets.QHBoxLayout()
+ self.layout.addLayout(self.mirrorModLayout)
+ self.mirrorModuleLabel = QtWidgets.QLabel("Mirror Module: ")
+ self.mirrorModuleLabel.setFont(font)
+ self.mirrorModLayout.addWidget(self.mirrorModuleLabel)
+
+ mirror = cmds.getAttr(networkNode + ".mirrorModule")
+ if mirror == "":
+ mirror = "None"
+ self.mirrorMod = QtWidgets.QLabel(mirror)
+ self.mirrorMod.setFont(font)
+ self.mirrorMod.setAlignment(QtCore.Qt.AlignHCenter)
+ self.mirrorModLayout.addWidget(self.mirrorMod)
+
+ # current parent
+ self.currentParentMod = QtWidgets.QHBoxLayout()
+ self.layout.addLayout(self.currentParentMod)
+ self.currentParentLabel = QtWidgets.QLabel("Current Parent: ")
+ self.currentParentLabel.setFont(font)
+ self.currentParentMod.addWidget(self.currentParentLabel)
+
+ parent = cmds.getAttr(networkNode + ".parentModuleBone")
+ self.currentParent = QtWidgets.QLabel(parent)
+ self.currentParent.setFont(font)
+ self.currentParent.setAlignment(QtCore.Qt.AlignHCenter)
+ self.currentParentMod.addWidget(self.currentParent)
+
+ # button layout for name/parent
+ self.buttonLayout = QtWidgets.QHBoxLayout()
+ self.layout.addLayout(self.buttonLayout)
+ self.changeNameBtn = QtWidgets.QPushButton("Change Name")
+ self.changeParentBtn = QtWidgets.QPushButton("Change Parent")
+ self.mirrorModuleBtn = QtWidgets.QPushButton("Mirror Module")
+ self.buttonLayout.addWidget(self.changeNameBtn)
+ self.buttonLayout.addWidget(self.changeParentBtn)
+ self.buttonLayout.addWidget(self.mirrorModuleBtn)
+ self.changeNameBtn.setObjectName("blueButton")
+ self.changeParentBtn.setObjectName("blueButton")
+ self.mirrorModuleBtn.setObjectName("blueButton")
+
+ # button signal/slots
+ self.changeNameBtn.clicked.connect(partial(self.changeModuleName, baseName, self, self.rigUiInst))
+ self.changeParentBtn.clicked.connect(partial(self.changeModuleParent, self, self.rigUiInst))
+ self.mirrorModuleBtn.clicked.connect(partial(self.setMirrorModule, self, self.rigUiInst))
+
+ # bake offsets button
+ self.bakeToolsLayout = QtWidgets.QHBoxLayout()
+ self.layout.addLayout(self.bakeToolsLayout)
+
+ # Bake OFfsets
+ self.bakeOffsetsBtn = QtWidgets.QPushButton("Bake Offsets")
+ self.bakeOffsetsBtn.setFont(headerFont)
+ self.bakeToolsLayout.addWidget(self.bakeOffsetsBtn)
+ self.bakeOffsetsBtn.clicked.connect(self.bakeOffsets)
+ self.bakeOffsetsBtn.setToolTip("Bake the offset mover values up to the global movers to get them in sync")
+ self.bakeOffsetsBtn.setObjectName("blueButton")
+
+ # Rig Settings
+ spacerItem = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ self.layout.addItem(spacerItem)
+
+ self.hasDynamics = QtWidgets.QCheckBox("Has Dynamics")
+ self.layout.addWidget(self.hasDynamics)
+ self.hasDynamics.setChecked(False)
+ # self.hasDynamics.clicked.connect(partial(self.applyModuleChanges, self))
+
+ spacerItem = QtWidgets.QSpacerItem(20, 30, QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ self.layout.addItem(spacerItem)
+
+ # Number of joints in chain
+ self.numJointsLayout = QtWidgets.QHBoxLayout()
+ self.layout.addLayout(self.numJointsLayout)
+
+ self.numJointsLabel = QtWidgets.QLabel("Number of Joints in Chain: ")
+ self.numJointsLabel.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred)
+ self.numJointsLabel.setMinimumSize(QtCore.QSize(200, 20))
+ self.numJointsLabel.setMaximumSize(QtCore.QSize(200, 20))
+ self.numJointsLayout.addWidget((self.numJointsLabel))
+
+ self.numJoints = QtWidgets.QSpinBox()
+ self.numJoints.setMaximum(99)
+ self.numJoints.setMinimum(2)
+ self.numJoints.setMinimumSize(QtCore.QSize(100, 20))
+ self.numJoints.setMaximumSize(QtCore.QSize(100, 20))
+ self.numJoints.setValue(3)
+ self.numJoints.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ self.numJointsLayout.addWidget(self.numJoints)
+
+ # rebuild button
+ spacerItem = QtWidgets.QSpacerItem(20, 10, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
+ self.layout.addItem(spacerItem)
+
+ self.applyButton = QtWidgets.QPushButton("Apply Changes")
+ self.layout.addWidget(self.applyButton)
+ self.applyButton.setFont(headerFont)
+ self.applyButton.setMinimumSize(QtCore.QSize(300, 40))
+ self.applyButton.setMaximumSize(QtCore.QSize(300, 40))
+ self.applyButton.setSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ self.applyButton.setEnabled(False)
+ self.applyButton.clicked.connect(partial(self.applyModuleChanges, self))
+
+ # signal slot for groupbox checkbox
+ QtCore.QObject.connect(self.groupBox, QtCore.SIGNAL("toggled(bool)"), self.frame.setVisible)
+ self.groupBox.setChecked(False)
+
+ # add custom skeletonUI settings name, parent, rig types to install, mirror module, etc.
+ # add to the rig cretor UI's module settings layout VBoxLayout
+ self.rigUiInst.moduleSettingsLayout.addWidget(self.groupBox)
+
+ # Populate the settings UI based on the network node attributes
+ # self.updateSettingsUI()