diff options
| author | MobileMachine\jeremy <[email protected]> | 2017-06-06 22:59:03 -0400 |
|---|---|---|
| committer | MobileMachine\jeremy <[email protected]> | 2017-06-06 22:59:03 -0400 |
| commit | 24725fa8681f906ab44d80687c09fecc171a2896 (patch) | |
| tree | 312a601df29aca7f8db9f44082d96ebc7a679138 /Core/Scripts/RigModules/ART_Chain.py | |
| parent | Initial commit (diff) | |
| download | artv2-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.py | 294 |
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() |