From bcf5144dd127214680fb9af500ca765730b3b6c2 Mon Sep 17 00:00:00 2001 From: Eugene Date: Mon, 28 Oct 2024 11:52:21 -0700 Subject: [PATCH 01/25] Create SimpleSpineRig.py --- GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py | 80 ++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py diff --git a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py new file mode 100644 index 0000000..b12a013 --- /dev/null +++ b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py @@ -0,0 +1,80 @@ +import maya.cmds as cmds + + +### Variables to change before using script ### +locatorsSize = 130 +nameWeightAttribute = "weight" +nameMultiplyDivide = "myMultiplyDivide" + +def CreateRig(): + # Get names of selected objects as list + selected = cmds.ls(selection = True) # , absoluteName = True + + # Create main group as a container for all new objects + mainGroup = cmds.group(name = "grpLocators", empty = True) + + # Init empty lists for groups and locators + groups = [] + locators = [] + + # Count of selected objects + count = len(selected) + + # Loop through each selected object, create groups, locators and parent them + for i in range(count): + # Create group + locatorGroup = cmds.group(name = "grp_" + selected[i], empty = True) + groups.append(locatorGroup) + + # Create locator + locator = cmds.spaceLocator(name = "loc_" + selected[i])[0] + locators.append(locator) + cmds.setAttr(locator + "Shape.localScaleX", locatorsSize) + cmds.setAttr(locator + "Shape.localScaleY", locatorsSize) + cmds.setAttr(locator + "Shape.localScaleZ", locatorsSize) + + # Parent locator to group + cmds.parent(locator, locatorGroup) + + # Parent group to corresponding hierarchy object + if i == 0: + cmds.parent(locatorGroup, mainGroup) + else: + cmds.parent(locatorGroup, locators[i - 1]) + + # Match group position and rotation + position = cmds.xform(selected[i], query = True, worldSpace = True, rotatePivot = True) + rotation = cmds.xform(selected[i], query = True, worldSpace = True, rotation = True) + cmds.xform(locatorGroup, translation = position, rotation = rotation, worldSpace = True) + + # Parent constraint original object to locator + cmds.parentConstraint(locator, selected[i], maintainOffset = True) + + # Select last locator + cmds.select(locators[-1], replace = True) + + # Check if selected count less than 3 objects and break function + if (count < 3): + cmds.warning("You have less than 3 objects selected. Rotation distribution will not be created") + return + + # Create weight attribute on last locator + cmds.addAttr(locators[-1], longName = nameWeightAttribute, attributeType = "double", defaultValue = 0.5) + cmds.setAttr(locators[-1] + "." + nameWeightAttribute, edit = True, keyable = True) + + # Create MultiplyDivide node + nodeMultiplyDivide = cmds.createNode("multiplyDivide", name = nameMultiplyDivide) + + # Connect rotation and weight to MultiplyDivide node + cmds.connectAttr(locators[-1] + ".rotate", nodeMultiplyDivide + ".input1") + cmds.connectAttr(locators[-1] + "." + nameWeightAttribute, nodeMultiplyDivide + ".input2X") + cmds.connectAttr(locators[-1] + "." + nameWeightAttribute, nodeMultiplyDivide + ".input2Y") + cmds.connectAttr(locators[-1] + "." + nameWeightAttribute, nodeMultiplyDivide + ".input2Z") + + # Connect rotation distribution to other locators' groups + for i in range(1, count - 1): + cmds.connectAttr(nodeMultiplyDivide + ".output", groups[i] + ".rotate") + +### Run function ### +CreateRig() + From 58d4c60d863063c6f83870252d88912d4abecde8 Mon Sep 17 00:00:00 2001 From: Eugene Date: Mon, 28 Oct 2024 14:33:06 -0700 Subject: [PATCH 02/25] Update SimpleSpineRig.py --- GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py | 33 +++++++++++++++----- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py index b12a013..763f014 100644 --- a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py +++ b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py @@ -3,8 +3,11 @@ ### Variables to change before using script ### locatorsSize = 130 -nameWeightAttribute = "weight" -nameMultiplyDivide = "myMultiplyDivide" +nameAttributeWeight = "distribution" +nameAttributeGlobal = "global" +nameMultiplyDivide = "gtMultiplyDivide" +nameFloatMath = "gtFloatMath" + def CreateRig(): # Get names of selected objects as list @@ -59,22 +62,38 @@ def CreateRig(): return # Create weight attribute on last locator - cmds.addAttr(locators[-1], longName = nameWeightAttribute, attributeType = "double", defaultValue = 0.5) - cmds.setAttr(locators[-1] + "." + nameWeightAttribute, edit = True, keyable = True) + cmds.addAttr(locators[-1], longName = nameAttributeWeight, attributeType = "double", defaultValue = count - 1) + cmds.setAttr(locators[-1] + "." + nameAttributeWeight, edit = True, keyable = True) # Create MultiplyDivide node nodeMultiplyDivide = cmds.createNode("multiplyDivide", name = nameMultiplyDivide) + cmds.setAttr(nodeMultiplyDivide + ".operation", 2) # Connect rotation and weight to MultiplyDivide node cmds.connectAttr(locators[-1] + ".rotate", nodeMultiplyDivide + ".input1") - cmds.connectAttr(locators[-1] + "." + nameWeightAttribute, nodeMultiplyDivide + ".input2X") - cmds.connectAttr(locators[-1] + "." + nameWeightAttribute, nodeMultiplyDivide + ".input2Y") - cmds.connectAttr(locators[-1] + "." + nameWeightAttribute, nodeMultiplyDivide + ".input2Z") + cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2X") + cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2Y") + cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2Z") # Connect rotation distribution to other locators' groups for i in range(1, count - 1): cmds.connectAttr(nodeMultiplyDivide + ".output", groups[i] + ".rotate") + + # Create global behaviour for last locator + cmds.addAttr(locators[-1], longName = nameAttributeGlobal, attributeType = "double", defaultValue = 1, minValue = 0, maxValue = 1) + cmds.setAttr(locators[-1] + "." + nameAttributeGlobal, edit = True, keyable = True) + + orientConstraint = cmds.orientConstraint(mainGroup, groups[-1], maintainOffset = True)[0] + cmds.orientConstraint(locators[-2], groups[-1], maintainOffset = True) + nodeFloatMath = cmds.createNode("floatMath", name = nameFloatMath) + cmds.setAttr(nodeFloatMath + ".operation", 1) + + cmds.connectAttr(locators[-1] + "." + nameAttributeGlobal, nodeFloatMath + ".floatB") + + cmds.connectAttr(locators[-1] + "." + nameAttributeGlobal, orientConstraint + "." + mainGroup + "W0") + cmds.connectAttr(nodeFloatMath + ".outFloat", orientConstraint + "." + locators[-2] + "W1") + ### Run function ### CreateRig() From 424a57728984a423986738e67f2463b7624cd791 Mon Sep 17 00:00:00 2001 From: Eugene Date: Mon, 28 Oct 2024 17:09:12 -0700 Subject: [PATCH 03/25] Update SimpleSpineRig.py --- GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py index 763f014..8699ae5 100644 --- a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py +++ b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py @@ -74,11 +74,13 @@ def CreateRig(): cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2X") cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2Y") cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2Z") - - # Connect rotation distribution to other locators' groups + + # Connect rotation distribution to other locators' groups # FIXME for i in range(1, count - 1): cmds.connectAttr(nodeMultiplyDivide + ".output", groups[i] + ".rotate") + return + # Create global behaviour for last locator cmds.addAttr(locators[-1], longName = nameAttributeGlobal, attributeType = "double", defaultValue = 1, minValue = 0, maxValue = 1) cmds.setAttr(locators[-1] + "." + nameAttributeGlobal, edit = True, keyable = True) From 1e7d0a7f77fe89da38bbfbf85ad616d94bf9f3b0 Mon Sep 17 00:00:00 2001 From: Eugene Date: Tue, 29 Oct 2024 11:03:37 -0700 Subject: [PATCH 04/25] Update SimpleSpineRig.py - fixed rotate distribution logic - deactivated global feature --- GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py | 92 +++++++++++--------- 1 file changed, 52 insertions(+), 40 deletions(-) diff --git a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py index 8699ae5..b5e77cf 100644 --- a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py +++ b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py @@ -10,91 +10,103 @@ def CreateRig(): - # Get names of selected objects as list + ### Get names of selected objects as list selected = cmds.ls(selection = True) # , absoluteName = True - # Create main group as a container for all new objects + ### Create main group as a container for all new objects mainGroup = cmds.group(name = "grpLocators", empty = True) - # Init empty lists for groups and locators - groups = [] + ### Init empty lists for groups and locators + groupsDistributed = [] locators = [] - # Count of selected objects + ### Count of selected objects count = len(selected) - # Loop through each selected object, create groups, locators and parent them + ### Loop through each selected object, create groups, locators and parent them for i in range(count): - # Create group - locatorGroup = cmds.group(name = "grp_" + selected[i], empty = True) - groups.append(locatorGroup) + ### Create fixed group + groupFixed = cmds.group(name = "grpFixed_" + selected[i], empty = True) + + ### Create distribution group + groupDistributed = cmds.group(name = "grpDistr_" + selected[i], empty = True) + groupsDistributed.append(groupDistributed) - # Create locator + ### Create locator locator = cmds.spaceLocator(name = "loc_" + selected[i])[0] locators.append(locator) cmds.setAttr(locator + "Shape.localScaleX", locatorsSize) cmds.setAttr(locator + "Shape.localScaleY", locatorsSize) cmds.setAttr(locator + "Shape.localScaleZ", locatorsSize) - # Parent locator to group - cmds.parent(locator, locatorGroup) + ### Parent locator to group + cmds.parent(locator, groupDistributed) - # Parent group to corresponding hierarchy object + ### Parent group to corresponding hierarchy object if i == 0: - cmds.parent(locatorGroup, mainGroup) + cmds.parent(groupFixed, mainGroup) else: - cmds.parent(locatorGroup, locators[i - 1]) + cmds.parent(groupFixed, locators[i - 1]) + cmds.parent(groupDistributed, groupFixed) - # Match group position and rotation + ### Match group position and rotation position = cmds.xform(selected[i], query = True, worldSpace = True, rotatePivot = True) rotation = cmds.xform(selected[i], query = True, worldSpace = True, rotation = True) - cmds.xform(locatorGroup, translation = position, rotation = rotation, worldSpace = True) + cmds.xform(groupFixed, translation = position, rotation = rotation, worldSpace = True) - # Parent constraint original object to locator + ### Parent constraint original object to locator cmds.parentConstraint(locator, selected[i], maintainOffset = True) + + ### Show last locator Rotate Order and connect it to Distribution groups + cmds.setAttr(locators[-1] + ".rotateOrder", channelBox = True) + for i in range(count): + groupsDistributed[i] + cmds.connectAttr(locators[-1] + ".rotateOrder", groupsDistributed[i] + ".rotateOrder") - # Select last locator - cmds.select(locators[-1], replace = True) - - # Check if selected count less than 3 objects and break function + ### Check if selected count less than 3 objects and break function if (count < 3): cmds.warning("You have less than 3 objects selected. Rotation distribution will not be created") return - # Create weight attribute on last locator + ### Create weight attribute on last locator cmds.addAttr(locators[-1], longName = nameAttributeWeight, attributeType = "double", defaultValue = count - 1) cmds.setAttr(locators[-1] + "." + nameAttributeWeight, edit = True, keyable = True) - # Create MultiplyDivide node + ### Create MultiplyDivide node nodeMultiplyDivide = cmds.createNode("multiplyDivide", name = nameMultiplyDivide) cmds.setAttr(nodeMultiplyDivide + ".operation", 2) - # Connect rotation and weight to MultiplyDivide node + ### Connect rotation and weight to MultiplyDivide node cmds.connectAttr(locators[-1] + ".rotate", nodeMultiplyDivide + ".input1") cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2X") cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2Y") cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2Z") - # Connect rotation distribution to other locators' groups # FIXME + ### Connect rotation distribution to other locators' groups for i in range(1, count - 1): - cmds.connectAttr(nodeMultiplyDivide + ".output", groups[i] + ".rotate") + cmds.connectAttr(nodeMultiplyDivide + ".output", groupsDistributed[i] + ".rotate") - return - - # Create global behaviour for last locator - cmds.addAttr(locators[-1], longName = nameAttributeGlobal, attributeType = "double", defaultValue = 1, minValue = 0, maxValue = 1) - cmds.setAttr(locators[-1] + "." + nameAttributeGlobal, edit = True, keyable = True) - - orientConstraint = cmds.orientConstraint(mainGroup, groups[-1], maintainOffset = True)[0] - cmds.orientConstraint(locators[-2], groups[-1], maintainOffset = True) + # FIXME + # ### Add global attribute for last locator + # cmds.addAttr(locators[-1], longName = nameAttributeGlobal, attributeType = "double", defaultValue = 1, minValue = 0, maxValue = 1) + # cmds.setAttr(locators[-1] + "." + nameAttributeGlobal, edit = True, keyable = True) - nodeFloatMath = cmds.createNode("floatMath", name = nameFloatMath) - cmds.setAttr(nodeFloatMath + ".operation", 1) + # ### Create Orient Constraints for last locator + # orientConstraint = cmds.orientConstraint(mainGroup, groupsDistributed[-1], maintainOffset = True)[0] + # cmds.orientConstraint(locators[-2], groupsDistributed[-1], maintainOffset = True) - cmds.connectAttr(locators[-1] + "." + nameAttributeGlobal, nodeFloatMath + ".floatB") + # ### Add Float Math node + # nodeFloatMath = cmds.createNode("floatMath", name = nameFloatMath) + # cmds.setAttr(nodeFloatMath + ".operation", 1) - cmds.connectAttr(locators[-1] + "." + nameAttributeGlobal, orientConstraint + "." + mainGroup + "W0") - cmds.connectAttr(nodeFloatMath + ".outFloat", orientConstraint + "." + locators[-2] + "W1") + # ### Connect Global attribute + # cmds.connectAttr(locators[-1] + "." + nameAttributeGlobal, nodeFloatMath + ".floatB") + # cmds.connectAttr(locators[-1] + "." + nameAttributeGlobal, orientConstraint + "." + mainGroup + "W0") + # cmds.connectAttr(nodeFloatMath + ".outFloat", orientConstraint + "." + locators[-2] + "W1") + # FIXME + + ### Select last locator + cmds.select(locators[-1], replace = True) ### Run function ### CreateRig() From 71bf249cc838714c555e3635ead3d4ace53621d9 Mon Sep 17 00:00:00 2001 From: Eugene Date: Tue, 29 Oct 2024 11:52:01 -0700 Subject: [PATCH 05/25] rework global --- GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py | 55 +++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py index b5e77cf..e4e5289 100644 --- a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py +++ b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py @@ -1,20 +1,29 @@ import maya.cmds as cmds -### Variables to change before using script ### +### Change variables if needed ### locatorsSize = 130 + +### Objects names +nameGroupMain = "SimpleChain" +nameGroupFixedPrefix = "grpFixed_" +nameGroupDistributedPrefix = "grpDistr_" +nameLocatorPrefix = "loc_" + +### Attributes names nameAttributeWeight = "distribution" nameAttributeGlobal = "global" + +### Nodes names nameMultiplyDivide = "gtMultiplyDivide" -nameFloatMath = "gtFloatMath" def CreateRig(): - ### Get names of selected objects as list - selected = cmds.ls(selection = True) # , absoluteName = True + ### Create a list of names from selected objects + selected = cmds.ls(selection = True) ### Create main group as a container for all new objects - mainGroup = cmds.group(name = "grpLocators", empty = True) + mainGroup = cmds.group(name = nameGroupMain, empty = True) ### Init empty lists for groups and locators groupsDistributed = [] @@ -26,14 +35,14 @@ def CreateRig(): ### Loop through each selected object, create groups, locators and parent them for i in range(count): ### Create fixed group - groupFixed = cmds.group(name = "grpFixed_" + selected[i], empty = True) + groupFixed = cmds.group(name = nameGroupFixedPrefix + selected[i], empty = True) ### Create distribution group - groupDistributed = cmds.group(name = "grpDistr_" + selected[i], empty = True) + groupDistributed = cmds.group(name = nameGroupDistributedPrefix + selected[i], empty = True) groupsDistributed.append(groupDistributed) - ### Create locator - locator = cmds.spaceLocator(name = "loc_" + selected[i])[0] + ### Create locator # TODO use nurbs circle [circle -c 0 0 0 -nr 0 1 0 -sw 360 -r 1 -d 3 -ut 0 -tol 1e-05 -s 8 -ch 1; objectMoveCommand;] + locator = cmds.spaceLocator(name = nameLocatorPrefix + selected[i])[0] locators.append(locator) cmds.setAttr(locator + "Shape.localScaleX", locatorsSize) cmds.setAttr(locator + "Shape.localScaleY", locatorsSize) @@ -86,25 +95,21 @@ def CreateRig(): for i in range(1, count - 1): cmds.connectAttr(nodeMultiplyDivide + ".output", groupsDistributed[i] + ".rotate") - # FIXME - # ### Add global attribute for last locator - # cmds.addAttr(locators[-1], longName = nameAttributeGlobal, attributeType = "double", defaultValue = 1, minValue = 0, maxValue = 1) - # cmds.setAttr(locators[-1] + "." + nameAttributeGlobal, edit = True, keyable = True) + ### Add global attribute for last locator + cmds.addAttr(locators[-1], longName = nameAttributeGlobal, attributeType = "double", defaultValue = 1, minValue = 0, maxValue = 1) + cmds.setAttr(locators[-1] + "." + nameAttributeGlobal, edit = True, keyable = True) - # ### Create Orient Constraints for last locator - # orientConstraint = cmds.orientConstraint(mainGroup, groupsDistributed[-1], maintainOffset = True)[0] - # cmds.orientConstraint(locators[-2], groupsDistributed[-1], maintainOffset = True) + ### Create Orient Constraint for last locator + cmds.orientConstraint(mainGroup, groupsDistributed[-1], maintainOffset = True)[0] - # ### Add Float Math node - # nodeFloatMath = cmds.createNode("floatMath", name = nameFloatMath) - # cmds.setAttr(nodeFloatMath + ".operation", 1) + ### Show blend orient attribute by setting keys on constrained rotation attributes # I frankly don't know how to do it better + cmds.setKeyframe(groupsDistributed[-1] + ".rx") + cmds.setKeyframe(groupsDistributed[-1] + ".ry") + cmds.setKeyframe(groupsDistributed[-1] + ".rz") + + ### Connect Global attribute to blend orient attribute + cmds.connectAttr(locators[-1] + "." + nameAttributeGlobal, groupsDistributed[-1] + ".blendOrient1") - # ### Connect Global attribute - # cmds.connectAttr(locators[-1] + "." + nameAttributeGlobal, nodeFloatMath + ".floatB") - # cmds.connectAttr(locators[-1] + "." + nameAttributeGlobal, orientConstraint + "." + mainGroup + "W0") - # cmds.connectAttr(nodeFloatMath + ".outFloat", orientConstraint + "." + locators[-2] + "W1") - # FIXME - ### Select last locator cmds.select(locators[-1], replace = True) From 9557c469f3f06991cdc0efe4da1fca5c45748d16 Mon Sep 17 00:00:00 2001 From: Eugene Date: Tue, 29 Oct 2024 13:02:55 -0700 Subject: [PATCH 06/25] Update SimpleSpineRig.py --- GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py index e4e5289..c0dbc9b 100644 --- a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py +++ b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py @@ -1,3 +1,7 @@ +### TODO unique naming fix +### TODO support different rotate orientation +### TODO preserve animation + import maya.cmds as cmds From 5a2ee6972c5b4df07dd97177385554c1b1841017 Mon Sep 17 00:00:00 2001 From: Eugene Date: Tue, 29 Oct 2024 13:32:53 -0700 Subject: [PATCH 07/25] replace xform with matchTransform --- GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py index c0dbc9b..cbf7531 100644 --- a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py +++ b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py @@ -1,6 +1,8 @@ ### TODO unique naming fix ### TODO support different rotate orientation ### TODO preserve animation +### TODO nurbs circle as control instead of locator (optional) + import maya.cmds as cmds @@ -63,10 +65,8 @@ def CreateRig(): cmds.parent(groupDistributed, groupFixed) ### Match group position and rotation - position = cmds.xform(selected[i], query = True, worldSpace = True, rotatePivot = True) - rotation = cmds.xform(selected[i], query = True, worldSpace = True, rotation = True) - cmds.xform(groupFixed, translation = position, rotation = rotation, worldSpace = True) - + cmds.matchTransform(groupFixed, selected[i], position = True, rotation = True, scale = False) + ### Parent constraint original object to locator cmds.parentConstraint(locator, selected[i], maintainOffset = True) From 4f57074fe0a03fb9dae09f814fb3b11b062f1c7a Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 30 Oct 2024 13:36:42 -0700 Subject: [PATCH 08/25] Update SimpleSpineRig.py --- GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py index cbf7531..47fd0ae 100644 --- a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py +++ b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py @@ -11,7 +11,7 @@ locatorsSize = 130 ### Objects names -nameGroupMain = "SimpleChain" +nameGroupMain = "grpChain_" nameGroupFixedPrefix = "grpFixed_" nameGroupDistributedPrefix = "grpDistr_" nameLocatorPrefix = "loc_" @@ -29,7 +29,7 @@ def CreateRig(): selected = cmds.ls(selection = True) ### Create main group as a container for all new objects - mainGroup = cmds.group(name = nameGroupMain, empty = True) + mainGroup = cmds.group(name = nameGroupMain + selected[-1], empty = True) ### Init empty lists for groups and locators groupsDistributed = [] From d7161546d2c3ec84c5291103352917f841fb4e92 Mon Sep 17 00:00:00 2001 From: Eugene Date: Mon, 4 Nov 2024 11:39:27 -0800 Subject: [PATCH 09/25] Update SimpleSpineRig.py test baking to locators, still need to solve some issues --- GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py | 22 +++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py index 47fd0ae..d655d17 100644 --- a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py +++ b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py @@ -1,6 +1,6 @@ -### TODO unique naming fix -### TODO support different rotate orientation ### TODO preserve animation +### TODO support different rotate orientation +### TODO unique naming fix ### TODO nurbs circle as control instead of locator (optional) @@ -34,6 +34,7 @@ def CreateRig(): ### Init empty lists for groups and locators groupsDistributed = [] locators = [] + constraintsForBake = [] ### Count of selected objects count = len(selected) @@ -67,9 +68,20 @@ def CreateRig(): ### Match group position and rotation cmds.matchTransform(groupFixed, selected[i], position = True, rotation = True, scale = False) - ### Parent constraint original object to locator - cmds.parentConstraint(locator, selected[i], maintainOffset = True) + ### Parent constraint locator to original object + constraint = cmds.parentConstraint(selected[i], locator, maintainOffset = True) + constraintsForBake.append(constraint[0]) + ### Bake animation to locators and delete constraints + timeMin = cmds.playbackOptions(query = True, min = True) + timeMax = cmds.playbackOptions(query = True, max = True) + cmds.bakeResults(locators, time = (timeMin, timeMax), simulation = True, minimizeRotation = True) + cmds.delete(constraintsForBake) + + ### Parent constraint original objects to locators + for i in range(count): + cmds.parentConstraint(locators[i], selected[i], maintainOffset = True) + ### Show last locator Rotate Order and connect it to Distribution groups cmds.setAttr(locators[-1] + ".rotateOrder", channelBox = True) for i in range(count): @@ -100,7 +112,7 @@ def CreateRig(): cmds.connectAttr(nodeMultiplyDivide + ".output", groupsDistributed[i] + ".rotate") ### Add global attribute for last locator - cmds.addAttr(locators[-1], longName = nameAttributeGlobal, attributeType = "double", defaultValue = 1, minValue = 0, maxValue = 1) + cmds.addAttr(locators[-1], longName = nameAttributeGlobal, attributeType = "double", defaultValue = 0, minValue = 0, maxValue = 1) cmds.setAttr(locators[-1] + "." + nameAttributeGlobal, edit = True, keyable = True) ### Create Orient Constraint for last locator From ce895baf5a9858e33001bf575f6715994278cd9d Mon Sep 17 00:00:00 2001 From: Eugene Date: Tue, 5 Nov 2024 09:59:51 -0800 Subject: [PATCH 10/25] Update SimpleSpineRig.py bake animation to groupFixed instead of locator --- GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py index d655d17..1c388df 100644 --- a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py +++ b/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py @@ -32,6 +32,7 @@ def CreateRig(): mainGroup = cmds.group(name = nameGroupMain + selected[-1], empty = True) ### Init empty lists for groups and locators + groupsFixed = [] groupsDistributed = [] locators = [] constraintsForBake = [] @@ -43,6 +44,7 @@ def CreateRig(): for i in range(count): ### Create fixed group groupFixed = cmds.group(name = nameGroupFixedPrefix + selected[i], empty = True) + groupsFixed.append(groupFixed) ### Create distribution group groupDistributed = cmds.group(name = nameGroupDistributedPrefix + selected[i], empty = True) @@ -68,14 +70,14 @@ def CreateRig(): ### Match group position and rotation cmds.matchTransform(groupFixed, selected[i], position = True, rotation = True, scale = False) - ### Parent constraint locator to original object - constraint = cmds.parentConstraint(selected[i], locator, maintainOffset = True) + ### Parent constraint groupFixed to original object + constraint = cmds.parentConstraint(selected[i], groupFixed, maintainOffset = True) constraintsForBake.append(constraint[0]) ### Bake animation to locators and delete constraints timeMin = cmds.playbackOptions(query = True, min = True) timeMax = cmds.playbackOptions(query = True, max = True) - cmds.bakeResults(locators, time = (timeMin, timeMax), simulation = True, minimizeRotation = True) + cmds.bakeResults(groupsFixed, time = (timeMin, timeMax), simulation = True, minimizeRotation = True) cmds.delete(constraintsForBake) ### Parent constraint original objects to locators From b74d5296b8c3ae4144c525463dfdd2e9ecbc2dc4 Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 6 Nov 2024 12:27:00 -0800 Subject: [PATCH 11/25] make alternative variant for chain distribution --- ...leSpineRig.py => ChainDistributionRig1.py} | 0 .../_prototypes/ChainDistributionRig2.py | 68 +++++++++++++++++++ 2 files changed, 68 insertions(+) rename GETOOLS_SOURCE/_prototypes/{SimpleSpineRig.py => ChainDistributionRig1.py} (100%) create mode 100644 GETOOLS_SOURCE/_prototypes/ChainDistributionRig2.py diff --git a/GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py b/GETOOLS_SOURCE/_prototypes/ChainDistributionRig1.py similarity index 100% rename from GETOOLS_SOURCE/_prototypes/SimpleSpineRig.py rename to GETOOLS_SOURCE/_prototypes/ChainDistributionRig1.py diff --git a/GETOOLS_SOURCE/_prototypes/ChainDistributionRig2.py b/GETOOLS_SOURCE/_prototypes/ChainDistributionRig2.py new file mode 100644 index 0000000..fa618b8 --- /dev/null +++ b/GETOOLS_SOURCE/_prototypes/ChainDistributionRig2.py @@ -0,0 +1,68 @@ +### TODO nurbs circle as control instead of locator (optional) + + +import maya.cmds as cmds + + +### Change variables if needed ### +locatorsSize = 100 + +### Objects names +nameGroupMain = "grpChain_" +nameLocatorPrefix = "loc_" + + +def CreateRig(): + ### Create a list of names from selected objects + selected = cmds.ls(selection = True) + + ### Create main group as a container for all new objects + mainGroup = cmds.group(name = nameGroupMain + selected[-1], empty = True) + + ### Init empty lists for groups and locators + locators = [] + constraintsForBake = [] + + ### Count of selected objects + count = len(selected) + + ### Loop through each selected object, create groups, locators and parent them + for i in range(count): + ### Create locator + locator = cmds.spaceLocator(name = nameLocatorPrefix + selected[i])[0] + locators.append(locator) + cmds.setAttr(locator + "Shape.localScaleX", locatorsSize) + cmds.setAttr(locator + "Shape.localScaleY", locatorsSize) + cmds.setAttr(locator + "Shape.localScaleZ", locatorsSize) + + ### Parent locator to group + cmds.parent(locator, mainGroup) + + ### Match group position and rotation + cmds.matchTransform(locator, selected[i], position = True, rotation = True, scale = False) + + ### Parent constraint groupFixed to original object + constraint = cmds.parentConstraint(selected[i], locator, maintainOffset = False) + constraintsForBake.append(constraint[0]) + + ### Bake animation to locators and delete constraints + timeMin = cmds.playbackOptions(query = True, min = True) + timeMax = cmds.playbackOptions(query = True, max = True) + cmds.bakeResults(locators, time = (timeMin, timeMax), simulation = True, minimizeRotation = True) + cmds.delete(constraintsForBake) + + ### Constrain + for i in range(count): + cmds.orientConstraint(locators[i], selected[i], maintainOffset = False) + cmds.pointConstraint(selected[i], locators[i], maintainOffset = False) + + if (i > 0 and i < count - 1): + cmds.orientConstraint(locators[i - 1], locators[i], maintainOffset = False) + cmds.orientConstraint(locators[i + 1], locators[i], maintainOffset = False) + + ### Select last locator + cmds.select(locators[-1], replace = True) + +### Run function ### +CreateRig() + From 46b6c9ac3a3875f93bb3bee82c345eb35e97af0e Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 6 Nov 2024 12:41:41 -0800 Subject: [PATCH 12/25] Update ChainDistributionRig2.py - set timeline to current minimum frame - activate maintain offset for orient constraints --- GETOOLS_SOURCE/_prototypes/ChainDistributionRig2.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/GETOOLS_SOURCE/_prototypes/ChainDistributionRig2.py b/GETOOLS_SOURCE/_prototypes/ChainDistributionRig2.py index fa618b8..a74b643 100644 --- a/GETOOLS_SOURCE/_prototypes/ChainDistributionRig2.py +++ b/GETOOLS_SOURCE/_prototypes/ChainDistributionRig2.py @@ -13,6 +13,10 @@ def CreateRig(): + timeMin = cmds.playbackOptions(query = True, min = True) + timeMax = cmds.playbackOptions(query = True, max = True) + cmds.currentTime(timeMin, edit = True, update = True) + ### Create a list of names from selected objects selected = cmds.ls(selection = True) @@ -46,19 +50,17 @@ def CreateRig(): constraintsForBake.append(constraint[0]) ### Bake animation to locators and delete constraints - timeMin = cmds.playbackOptions(query = True, min = True) - timeMax = cmds.playbackOptions(query = True, max = True) cmds.bakeResults(locators, time = (timeMin, timeMax), simulation = True, minimizeRotation = True) cmds.delete(constraintsForBake) ### Constrain for i in range(count): - cmds.orientConstraint(locators[i], selected[i], maintainOffset = False) cmds.pointConstraint(selected[i], locators[i], maintainOffset = False) + cmds.orientConstraint(locators[i], selected[i], maintainOffset = False) if (i > 0 and i < count - 1): - cmds.orientConstraint(locators[i - 1], locators[i], maintainOffset = False) - cmds.orientConstraint(locators[i + 1], locators[i], maintainOffset = False) + cmds.orientConstraint(locators[i - 1], locators[i], maintainOffset = True) + cmds.orientConstraint(locators[i + 1], locators[i], maintainOffset = True) ### Select last locator cmds.select(locators[-1], replace = True) From 605ff5eebbcc3ed3e9575c0eab721a480bc0eda2 Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 13 Nov 2024 10:31:30 -0800 Subject: [PATCH 13/25] integrate chain distribution to UI --- GETOOLS_SOURCE/modules/Tools.py | 45 +++-- GETOOLS_SOURCE/utils/ChainDistributionRig.py | 201 +++++++++++++++++++ 2 files changed, 229 insertions(+), 17 deletions(-) create mode 100644 GETOOLS_SOURCE/utils/ChainDistributionRig.py diff --git a/GETOOLS_SOURCE/modules/Tools.py b/GETOOLS_SOURCE/modules/Tools.py index e440f87..48b60db 100644 --- a/GETOOLS_SOURCE/modules/Tools.py +++ b/GETOOLS_SOURCE/modules/Tools.py @@ -27,6 +27,7 @@ from .. import Settings from ..utils import Animation from ..utils import Baker +from ..utils import ChainDistributionRig from ..utils import Colors from ..utils import Locators from ..utils import Selector @@ -62,6 +63,8 @@ class ToolsAnnotations: # locatorsRelative = "{bake}\nThe last locator becomes the parent of other locators".format(bake = locatorsBake) locatorsRelativeReverse = "{relative}\n{reverse}\nRight click allows you to bake the same operation but with constrained last object.".format(relative = locatorsRelative, reverse = _reverseConstraint) + # + chainDistribution = "Create chain with distributed rotation. Use last locator to animate.\nPerfectly works with 3 selected objects.\nYou can use it for 4 and more selected objects, but be ready for unpredicted behavior." # locatorAimSpace = "Locator Aim distance from original object. Need to use non-zero value" locatorAimSpace = "Aim Space offset from original object.\nNeed to use non-zero value to get best result" @@ -104,7 +107,9 @@ class ToolsAnnotations: animationOffset = "Move animation curves on selected objects.\nAnimation will move relative to the index of the selected object.\nThe best way to desync animation.\nWorks with selection in the channel box." class ToolsSettings: - ### AIM SPACE + locatorSize = 10 + + ### Aim Space aimSpaceName = "Offset" aimSpaceOffsetValue = 100 aimSpaceRadioButtonDefault = 0 @@ -125,14 +130,12 @@ def __init__(self, options): self.checkboxLocatorHideParent = None self.checkboxLocatorSubLocator = None self.floatLocatorSize = None - - ### Animation Offset - self.animOffsetFloatField = None - ### Locator Aim Space self.aimSpaceFloatField = None self.aimSpaceRadioButtons = [None, None, None] self.aimSpaceCheckbox = None + ### Animation Offset + self.animOffsetFloatField = None self.bakingSamplesValue = None @@ -144,7 +147,8 @@ def UICreate(self, layoutMain): def UILayoutLocators(self, layoutMain): layoutLocators = cmds.frameLayout(parent = layoutMain, label = Settings.frames2Prefix + "LOCATORS // SPACE SWITCHING", collapsable = True, backgroundColor = Settings.frames2Color, marginWidth = 0, marginHeight = 0) layoutColumn = cmds.columnLayout(parent = layoutLocators, adjustableColumn = True) - # + + ### LOCATORS SIZE countOffsets = 6 cellWidth = Settings.windowWidthMargin / countOffsets cmds.gridLayout(parent = layoutColumn, numberOfColumns = countOffsets, cellWidth = cellWidth, cellHeight = Settings.lineHeight) @@ -182,13 +186,15 @@ def UILayoutLocators(self, layoutMain): cmds.menuItem(divider = True) cmds.menuItem(label = "1000", command = partial(Locators.SelectedLocatorsSizeSet, 1000)) cmds.menuItem(label = "5000", command = partial(Locators.SelectedLocatorsSizeSet, 5000)) - # + + ### OPTIONS cmds.rowLayout(parent = layoutColumn, numberOfColumns = 4, columnWidth4 = (85, 85, 40, 60), columnAlign = [(1, "center"), (2, "center"), (3, "right"), (4, "center")], columnAttach = [(1, "both", 0), (2, "both", 0), (3, "both", 0), (4, "both", 0)]) self.checkboxLocatorHideParent = cmds.checkBox(label = "Hide Parent", value = False, annotation = ToolsAnnotations.hideParent) self.checkboxLocatorSubLocator = cmds.checkBox(label = "Sub Locator", value = False, annotation = ToolsAnnotations.subLocator) cmds.text(label = "Size:", annotation = ToolsAnnotations.locatorSize) - self.floatLocatorSize = cmds.floatField(value = 10, precision = 3, annotation = ToolsAnnotations.locatorSize) - # + self.floatLocatorSize = cmds.floatField(value = ToolsSettings.locatorSize, precision = 3, annotation = ToolsAnnotations.locatorSize) + + ### LOCATORS ROW 1 countOffsets = 6 cmds.gridLayout(parent = layoutColumn, numberOfColumns = countOffsets, cellWidth = Settings.windowWidthMargin / countOffsets, cellHeight = Settings.lineHeight) cmds.button(label = "Locator", command = self.Locator, backgroundColor = Colors.green10, annotation = ToolsAnnotations.locator) @@ -199,18 +205,18 @@ def UILayoutLocators(self, layoutMain): cmds.menuItem(label = "Without Reverse Constraint", command = self.LocatorsBake) cmds.button(label = "P-POS", command = partial(self.LocatorsBakeReverse, True, False), backgroundColor = Colors.yellow50, annotation = ToolsAnnotations.locatorsBakeReversePos) cmds.button(label = "P-ROT", command = partial(self.LocatorsBakeReverse, False, True), backgroundColor = Colors.yellow50, annotation = ToolsAnnotations.locatorsBakeReverseRot) - # - countOffsets = 1 - cmds.gridLayout(parent = layoutColumn, numberOfColumns = countOffsets, cellWidth = Settings.windowWidthMargin / countOffsets, cellHeight = Settings.lineHeight) + + ### LOCATORS ROW 2 + cmds.rowLayout(parent = layoutColumn, numberOfColumns = 2, columnWidth2 = (110, 160), columnAlign = [(1, "center"), (2, "center")], columnAttach = [(1, "both", 0), (2, "both", 0)]) cmds.button(label = "Relative", command = self.LocatorsRelativeReverse, backgroundColor = Colors.orange10, annotation = ToolsAnnotations.locatorsRelativeReverse) cmds.popupMenu() cmds.menuItem(label = "Skip Last Object Reverse Constraint", command = self.LocatorsRelativeReverseSkipLast) cmds.menuItem(label = "Without Reverse Constraint", command = self.LocatorsRelative) - # - - ### Aim Space Switching - layoutAimSpace = cmds.frameLayout(parent = layoutColumn, label = "Aim Space Switching", labelIndent = 75, collapsable = False, backgroundColor = Settings.frames2Color, marginWidth = 0, marginHeight = 0) + cmds.button(label = "Chain Distribution", command = self.CreateChainDistributionRig, backgroundColor = Colors.purple10, annotation = ToolsAnnotations.chainDistribution) + ### AIM SPACE SWITCHING + layoutAimSpace = cmds.frameLayout(parent = layoutColumn, label = "Aim Space Switching", labelIndent = 75, collapsable = False, backgroundColor = Settings.frames2Color, marginWidth = 0, marginHeight = 0) + # cmds.rowLayout(parent = layoutAimSpace, numberOfColumns = 6, columnWidth6 = (40, 55, 35, 35, 35, 60), columnAlign = [1, "center"], columnAttach = [(1, "both", 0)]) cmds.text(label = ToolsSettings.aimSpaceName) self.aimSpaceFloatField = cmds.floatField(value = ToolsSettings.aimSpaceOffsetValue, precision = 3, minValue = 0, annotation = ToolsAnnotations.locatorAimSpace) @@ -220,7 +226,7 @@ def UILayoutLocators(self, layoutMain): self.aimSpaceRadioButtons[2] = cmds.radioButton(label = "Z") self.aimSpaceCheckbox = cmds.checkBox(label = "Reverse", value = False) cmds.radioButton(self.aimSpaceRadioButtons[ToolsSettings.aimSpaceRadioButtonDefault], edit = True, select = True) - + # cmds.rowLayout(parent = layoutAimSpace, numberOfColumns = 3, columnWidth3 = (50, 110, 110), columnAlign = [(1, "center"), (2, "center"), (3, "center")], columnAttach = [(1, "both", 0), (2, "both", 0), (3, "both", 0)]) cmds.text(label = "Create") cmds.button(label = "Translate + Rotate", command = partial(self.LocatorsBakeAim, False), backgroundColor = Colors.orange10, annotation = ToolsAnnotations.locatorAimSpaceBakeAll) @@ -313,6 +319,7 @@ def UILayoutTimeline(self, layoutMain): cmds.button(label = ">-<", command = partial(Timeline.SetTime, 6), backgroundColor = Colors.orange10, annotation = ToolsAnnotations.timelineFocusIn) cmds.button(label = "|<->|", command = partial(Timeline.SetTime, 7), backgroundColor = Colors.orange50, annotation = ToolsAnnotations.timelineSetRange) + ### LOCATORS def GetFloatLocatorSize(self): return cmds.floatField(self.floatLocatorSize, query = True, value = True) @@ -393,6 +400,10 @@ def LocatorsBakeAim(self, rotateOnly=False, *args): if (distance == 0): cmds.warning("Aim distance is 0. Highly recommended to use non-zero value.") + ### CHAIN DISTRIBUTION RIG + def CreateChainDistributionRig(self, *args): + ChainDistributionRig.CreateRigVariant1(controlSize = self.GetFloatLocatorSize()) + ### BAKING def BakeSampleGet(self): diff --git a/GETOOLS_SOURCE/utils/ChainDistributionRig.py b/GETOOLS_SOURCE/utils/ChainDistributionRig.py new file mode 100644 index 0000000..ef31e6f --- /dev/null +++ b/GETOOLS_SOURCE/utils/ChainDistributionRig.py @@ -0,0 +1,201 @@ +# GETOOLS is under the terms of the MIT License +# Copyright (c) 2018-2024 Eugene Gataulin (GenEugene). All Rights Reserved. + +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: + +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. + +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +# Author: Eugene Gataulin tek942@gmail.com https://www.linkedin.com/in/geneugene +# Source code: https://github.com/GenEugene/GETools or https://app.gumroad.com/geneugene + +import maya.cmds as cmds + + +_controlSize = 100 +_nameGroupMain = "grpChain_" +_nameLocatorPrefix = "loc_" + + +def CreateRigVariant1(controlSize=_controlSize, *args): + timeMin = cmds.playbackOptions(query = True, min = True) + timeMax = cmds.playbackOptions(query = True, max = True) + cmds.currentTime(timeMin, edit = True, update = True) + + ### Create a list of names from selected objects + selected = cmds.ls(selection = True) + + ### Create main group as a container for all new objects + mainGroup = cmds.group(name = _nameGroupMain + selected[-1], empty = True) + + ### Init empty lists for groups and locators + locators = [] + constraintsForBake = [] + + ### Count of selected objects + count = len(selected) + + ### Loop through each selected object, create groups, locators and parent them + for i in range(count): + ### Create locator # TODO nurbs circle as control instead of locator (optional) + locator = cmds.spaceLocator(name = _nameLocatorPrefix + selected[i])[0] + locators.append(locator) + cmds.setAttr(locator + "Shape.localScaleX", controlSize) + cmds.setAttr(locator + "Shape.localScaleY", controlSize) + cmds.setAttr(locator + "Shape.localScaleZ", controlSize) + + ### Parent locator to group + cmds.parent(locator, mainGroup) + + ### Match group position and rotation + cmds.matchTransform(locator, selected[i], position = True, rotation = True, scale = False) + + ### Parent constraint groupFixed to original object + constraint = cmds.parentConstraint(selected[i], locator, maintainOffset = False) + constraintsForBake.append(constraint[0]) + + ### Bake animation to locators and delete constraints + cmds.bakeResults(locators, time = (timeMin, timeMax), simulation = True, minimizeRotation = True) + cmds.delete(constraintsForBake) + + ### Constrain + for i in range(count): + cmds.pointConstraint(selected[i], locators[i], maintainOffset = False) + cmds.orientConstraint(locators[i], selected[i], maintainOffset = False) + + if (i > 0 and i < count - 1): + cmds.orientConstraint(locators[i - 1], locators[i], maintainOffset = True) + cmds.orientConstraint(locators[i + 1], locators[i], maintainOffset = True) + + ### Select last locator + cmds.select(locators[-1], replace = True) + +def CreateRigVariant2(controlSize=_controlSize, *args): + ### Objects names + nameGroupFixedPrefix = "grpFixed_" + nameGroupDistributedPrefix = "grpDistr_" + ### Attributes names + nameAttributeWeight = "distribution" + nameAttributeGlobal = "global" + ### Nodes names + nameMultiplyDivide = "gtMultiplyDivide" + + + ### Create a list of names from selected objects + selected = cmds.ls(selection = True) + + ### Create main group as a container for all new objects + mainGroup = cmds.group(name = _nameGroupMain + selected[-1], empty = True) + + ### Init empty lists for groups and locators + groupsFixed = [] + groupsDistributed = [] + locators = [] + constraintsForBake = [] + + ### Count of selected objects + count = len(selected) + + ### Loop through each selected object, create groups, locators and parent them + for i in range(count): + ### Create fixed group + groupFixed = cmds.group(name = nameGroupFixedPrefix + selected[i], empty = True) + groupsFixed.append(groupFixed) + + ### Create distribution group + groupDistributed = cmds.group(name = nameGroupDistributedPrefix + selected[i], empty = True) + groupsDistributed.append(groupDistributed) + + ### Create locator # TODO use nurbs circle [circle -c 0 0 0 -nr 0 1 0 -sw 360 -r 1 -d 3 -ut 0 -tol 1e-05 -s 8 -ch 1; objectMoveCommand;] + locator = cmds.spaceLocator(name = _nameLocatorPrefix + selected[i])[0] + locators.append(locator) + cmds.setAttr(locator + "Shape.localScaleX", controlSize) + cmds.setAttr(locator + "Shape.localScaleY", controlSize) + cmds.setAttr(locator + "Shape.localScaleZ", controlSize) + + ### Parent locator to group + cmds.parent(locator, groupDistributed) + + ### Parent group to corresponding hierarchy object + if i == 0: + cmds.parent(groupFixed, mainGroup) + else: + cmds.parent(groupFixed, locators[i - 1]) + cmds.parent(groupDistributed, groupFixed) + + ### Match group position and rotation + cmds.matchTransform(groupFixed, selected[i], position = True, rotation = True, scale = False) + + ### Parent constraint groupFixed to original object + constraint = cmds.parentConstraint(selected[i], groupFixed, maintainOffset = True) + constraintsForBake.append(constraint[0]) + + ### Bake animation to locators and delete constraints + timeMin = cmds.playbackOptions(query = True, min = True) + timeMax = cmds.playbackOptions(query = True, max = True) + cmds.bakeResults(groupsFixed, time = (timeMin, timeMax), simulation = True, minimizeRotation = True) + cmds.delete(constraintsForBake) + + ### Parent constraint original objects to locators + for i in range(count): + cmds.parentConstraint(locators[i], selected[i], maintainOffset = True) + + ### Show last locator Rotate Order and connect it to Distribution groups + cmds.setAttr(locators[-1] + ".rotateOrder", channelBox = True) + for i in range(count): + groupsDistributed[i] + cmds.connectAttr(locators[-1] + ".rotateOrder", groupsDistributed[i] + ".rotateOrder") + + ### Check if selected count less than 3 objects and break function + if (count < 3): + cmds.warning("You have less than 3 objects selected. Rotation distribution will not be created") + return + + ### Create weight attribute on last locator + cmds.addAttr(locators[-1], longName = nameAttributeWeight, attributeType = "double", defaultValue = count - 1) + cmds.setAttr(locators[-1] + "." + nameAttributeWeight, edit = True, keyable = True) + + ### Create MultiplyDivide node + nodeMultiplyDivide = cmds.createNode("multiplyDivide", name = nameMultiplyDivide) + cmds.setAttr(nodeMultiplyDivide + ".operation", 2) + + ### Connect rotation and weight to MultiplyDivide node + cmds.connectAttr(locators[-1] + ".rotate", nodeMultiplyDivide + ".input1") + cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2X") + cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2Y") + cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2Z") + + ### Connect rotation distribution to other locators' groups + for i in range(1, count - 1): + cmds.connectAttr(nodeMultiplyDivide + ".output", groupsDistributed[i] + ".rotate") + + ### Add global attribute for last locator + cmds.addAttr(locators[-1], longName = nameAttributeGlobal, attributeType = "double", defaultValue = 0, minValue = 0, maxValue = 1) + cmds.setAttr(locators[-1] + "." + nameAttributeGlobal, edit = True, keyable = True) + + ### Create Orient Constraint for last locator + cmds.orientConstraint(mainGroup, groupsDistributed[-1], maintainOffset = True)[0] + + ### Show blend orient attribute by setting keys on constrained rotation attributes # I frankly don't know how to do it better + cmds.setKeyframe(groupsDistributed[-1] + ".rx") + cmds.setKeyframe(groupsDistributed[-1] + ".ry") + cmds.setKeyframe(groupsDistributed[-1] + ".rz") + + ### Connect Global attribute to blend orient attribute + cmds.connectAttr(locators[-1] + "." + nameAttributeGlobal, groupsDistributed[-1] + ".blendOrient1") + + ### Select last locator + cmds.select(locators[-1], replace = True) + From 01435b0bbdd988c8d9d70e0ac272c06a77011edc Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 13 Nov 2024 12:40:33 -0800 Subject: [PATCH 14/25] Update ChainDistributionRig.py add checking minimum selected objects --- GETOOLS_SOURCE/utils/ChainDistributionRig.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/GETOOLS_SOURCE/utils/ChainDistributionRig.py b/GETOOLS_SOURCE/utils/ChainDistributionRig.py index ef31e6f..d4dd2f6 100644 --- a/GETOOLS_SOURCE/utils/ChainDistributionRig.py +++ b/GETOOLS_SOURCE/utils/ChainDistributionRig.py @@ -23,6 +23,8 @@ import maya.cmds as cmds +from ..utils import Selector + _controlSize = 100 _nameGroupMain = "grpChain_" @@ -30,6 +32,11 @@ def CreateRigVariant1(controlSize=_controlSize, *args): + # Check selected objects + selectedList = Selector.MultipleObjects(minimalCount = 1) + if (selectedList == None): + return + timeMin = cmds.playbackOptions(query = True, min = True) timeMax = cmds.playbackOptions(query = True, max = True) cmds.currentTime(timeMin, edit = True, update = True) @@ -83,6 +90,11 @@ def CreateRigVariant1(controlSize=_controlSize, *args): cmds.select(locators[-1], replace = True) def CreateRigVariant2(controlSize=_controlSize, *args): + # Check selected objects + selectedList = Selector.MultipleObjects(minimalCount = 1) + if (selectedList == None): + return + ### Objects names nameGroupFixedPrefix = "grpFixed_" nameGroupDistributedPrefix = "grpDistr_" From b84412f7479886bb9c70b37afaeae5f4dd3d6755 Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 13 Nov 2024 12:42:21 -0800 Subject: [PATCH 15/25] remove redundant scripts --- .../_prototypes/ChainDistributionRig1.py | 136 ------------------ .../_prototypes/ChainDistributionRig2.py | 70 --------- 2 files changed, 206 deletions(-) delete mode 100644 GETOOLS_SOURCE/_prototypes/ChainDistributionRig1.py delete mode 100644 GETOOLS_SOURCE/_prototypes/ChainDistributionRig2.py diff --git a/GETOOLS_SOURCE/_prototypes/ChainDistributionRig1.py b/GETOOLS_SOURCE/_prototypes/ChainDistributionRig1.py deleted file mode 100644 index 1c388df..0000000 --- a/GETOOLS_SOURCE/_prototypes/ChainDistributionRig1.py +++ /dev/null @@ -1,136 +0,0 @@ -### TODO preserve animation -### TODO support different rotate orientation -### TODO unique naming fix -### TODO nurbs circle as control instead of locator (optional) - - -import maya.cmds as cmds - - -### Change variables if needed ### -locatorsSize = 130 - -### Objects names -nameGroupMain = "grpChain_" -nameGroupFixedPrefix = "grpFixed_" -nameGroupDistributedPrefix = "grpDistr_" -nameLocatorPrefix = "loc_" - -### Attributes names -nameAttributeWeight = "distribution" -nameAttributeGlobal = "global" - -### Nodes names -nameMultiplyDivide = "gtMultiplyDivide" - - -def CreateRig(): - ### Create a list of names from selected objects - selected = cmds.ls(selection = True) - - ### Create main group as a container for all new objects - mainGroup = cmds.group(name = nameGroupMain + selected[-1], empty = True) - - ### Init empty lists for groups and locators - groupsFixed = [] - groupsDistributed = [] - locators = [] - constraintsForBake = [] - - ### Count of selected objects - count = len(selected) - - ### Loop through each selected object, create groups, locators and parent them - for i in range(count): - ### Create fixed group - groupFixed = cmds.group(name = nameGroupFixedPrefix + selected[i], empty = True) - groupsFixed.append(groupFixed) - - ### Create distribution group - groupDistributed = cmds.group(name = nameGroupDistributedPrefix + selected[i], empty = True) - groupsDistributed.append(groupDistributed) - - ### Create locator # TODO use nurbs circle [circle -c 0 0 0 -nr 0 1 0 -sw 360 -r 1 -d 3 -ut 0 -tol 1e-05 -s 8 -ch 1; objectMoveCommand;] - locator = cmds.spaceLocator(name = nameLocatorPrefix + selected[i])[0] - locators.append(locator) - cmds.setAttr(locator + "Shape.localScaleX", locatorsSize) - cmds.setAttr(locator + "Shape.localScaleY", locatorsSize) - cmds.setAttr(locator + "Shape.localScaleZ", locatorsSize) - - ### Parent locator to group - cmds.parent(locator, groupDistributed) - - ### Parent group to corresponding hierarchy object - if i == 0: - cmds.parent(groupFixed, mainGroup) - else: - cmds.parent(groupFixed, locators[i - 1]) - cmds.parent(groupDistributed, groupFixed) - - ### Match group position and rotation - cmds.matchTransform(groupFixed, selected[i], position = True, rotation = True, scale = False) - - ### Parent constraint groupFixed to original object - constraint = cmds.parentConstraint(selected[i], groupFixed, maintainOffset = True) - constraintsForBake.append(constraint[0]) - - ### Bake animation to locators and delete constraints - timeMin = cmds.playbackOptions(query = True, min = True) - timeMax = cmds.playbackOptions(query = True, max = True) - cmds.bakeResults(groupsFixed, time = (timeMin, timeMax), simulation = True, minimizeRotation = True) - cmds.delete(constraintsForBake) - - ### Parent constraint original objects to locators - for i in range(count): - cmds.parentConstraint(locators[i], selected[i], maintainOffset = True) - - ### Show last locator Rotate Order and connect it to Distribution groups - cmds.setAttr(locators[-1] + ".rotateOrder", channelBox = True) - for i in range(count): - groupsDistributed[i] - cmds.connectAttr(locators[-1] + ".rotateOrder", groupsDistributed[i] + ".rotateOrder") - - ### Check if selected count less than 3 objects and break function - if (count < 3): - cmds.warning("You have less than 3 objects selected. Rotation distribution will not be created") - return - - ### Create weight attribute on last locator - cmds.addAttr(locators[-1], longName = nameAttributeWeight, attributeType = "double", defaultValue = count - 1) - cmds.setAttr(locators[-1] + "." + nameAttributeWeight, edit = True, keyable = True) - - ### Create MultiplyDivide node - nodeMultiplyDivide = cmds.createNode("multiplyDivide", name = nameMultiplyDivide) - cmds.setAttr(nodeMultiplyDivide + ".operation", 2) - - ### Connect rotation and weight to MultiplyDivide node - cmds.connectAttr(locators[-1] + ".rotate", nodeMultiplyDivide + ".input1") - cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2X") - cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2Y") - cmds.connectAttr(locators[-1] + "." + nameAttributeWeight, nodeMultiplyDivide + ".input2Z") - - ### Connect rotation distribution to other locators' groups - for i in range(1, count - 1): - cmds.connectAttr(nodeMultiplyDivide + ".output", groupsDistributed[i] + ".rotate") - - ### Add global attribute for last locator - cmds.addAttr(locators[-1], longName = nameAttributeGlobal, attributeType = "double", defaultValue = 0, minValue = 0, maxValue = 1) - cmds.setAttr(locators[-1] + "." + nameAttributeGlobal, edit = True, keyable = True) - - ### Create Orient Constraint for last locator - cmds.orientConstraint(mainGroup, groupsDistributed[-1], maintainOffset = True)[0] - - ### Show blend orient attribute by setting keys on constrained rotation attributes # I frankly don't know how to do it better - cmds.setKeyframe(groupsDistributed[-1] + ".rx") - cmds.setKeyframe(groupsDistributed[-1] + ".ry") - cmds.setKeyframe(groupsDistributed[-1] + ".rz") - - ### Connect Global attribute to blend orient attribute - cmds.connectAttr(locators[-1] + "." + nameAttributeGlobal, groupsDistributed[-1] + ".blendOrient1") - - ### Select last locator - cmds.select(locators[-1], replace = True) - -### Run function ### -CreateRig() - diff --git a/GETOOLS_SOURCE/_prototypes/ChainDistributionRig2.py b/GETOOLS_SOURCE/_prototypes/ChainDistributionRig2.py deleted file mode 100644 index a74b643..0000000 --- a/GETOOLS_SOURCE/_prototypes/ChainDistributionRig2.py +++ /dev/null @@ -1,70 +0,0 @@ -### TODO nurbs circle as control instead of locator (optional) - - -import maya.cmds as cmds - - -### Change variables if needed ### -locatorsSize = 100 - -### Objects names -nameGroupMain = "grpChain_" -nameLocatorPrefix = "loc_" - - -def CreateRig(): - timeMin = cmds.playbackOptions(query = True, min = True) - timeMax = cmds.playbackOptions(query = True, max = True) - cmds.currentTime(timeMin, edit = True, update = True) - - ### Create a list of names from selected objects - selected = cmds.ls(selection = True) - - ### Create main group as a container for all new objects - mainGroup = cmds.group(name = nameGroupMain + selected[-1], empty = True) - - ### Init empty lists for groups and locators - locators = [] - constraintsForBake = [] - - ### Count of selected objects - count = len(selected) - - ### Loop through each selected object, create groups, locators and parent them - for i in range(count): - ### Create locator - locator = cmds.spaceLocator(name = nameLocatorPrefix + selected[i])[0] - locators.append(locator) - cmds.setAttr(locator + "Shape.localScaleX", locatorsSize) - cmds.setAttr(locator + "Shape.localScaleY", locatorsSize) - cmds.setAttr(locator + "Shape.localScaleZ", locatorsSize) - - ### Parent locator to group - cmds.parent(locator, mainGroup) - - ### Match group position and rotation - cmds.matchTransform(locator, selected[i], position = True, rotation = True, scale = False) - - ### Parent constraint groupFixed to original object - constraint = cmds.parentConstraint(selected[i], locator, maintainOffset = False) - constraintsForBake.append(constraint[0]) - - ### Bake animation to locators and delete constraints - cmds.bakeResults(locators, time = (timeMin, timeMax), simulation = True, minimizeRotation = True) - cmds.delete(constraintsForBake) - - ### Constrain - for i in range(count): - cmds.pointConstraint(selected[i], locators[i], maintainOffset = False) - cmds.orientConstraint(locators[i], selected[i], maintainOffset = False) - - if (i > 0 and i < count - 1): - cmds.orientConstraint(locators[i - 1], locators[i], maintainOffset = True) - cmds.orientConstraint(locators[i + 1], locators[i], maintainOffset = True) - - ### Select last locator - cmds.select(locators[-1], replace = True) - -### Run function ### -CreateRig() - From 48ed69ffb0844e6887f52a4387584371db91f65f Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 13 Nov 2024 19:17:13 -0800 Subject: [PATCH 16/25] Update ChainDistributionRig.py fixed cycle constraint issue --- GETOOLS_SOURCE/utils/ChainDistributionRig.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/GETOOLS_SOURCE/utils/ChainDistributionRig.py b/GETOOLS_SOURCE/utils/ChainDistributionRig.py index d4dd2f6..632a525 100644 --- a/GETOOLS_SOURCE/utils/ChainDistributionRig.py +++ b/GETOOLS_SOURCE/utils/ChainDistributionRig.py @@ -83,7 +83,7 @@ def CreateRigVariant1(controlSize=_controlSize, *args): cmds.orientConstraint(locators[i], selected[i], maintainOffset = False) if (i > 0 and i < count - 1): - cmds.orientConstraint(locators[i - 1], locators[i], maintainOffset = True) + cmds.orientConstraint(locators[0], locators[i], maintainOffset = True) cmds.orientConstraint(locators[i + 1], locators[i], maintainOffset = True) ### Select last locator From 608e8157ec5152fc66f998b198a9e9632457800d Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 13 Nov 2024 19:39:40 -0800 Subject: [PATCH 17/25] added unique naming --- GETOOLS_SOURCE/utils/ChainDistributionRig.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/GETOOLS_SOURCE/utils/ChainDistributionRig.py b/GETOOLS_SOURCE/utils/ChainDistributionRig.py index 632a525..c6697fb 100644 --- a/GETOOLS_SOURCE/utils/ChainDistributionRig.py +++ b/GETOOLS_SOURCE/utils/ChainDistributionRig.py @@ -24,6 +24,7 @@ import maya.cmds as cmds from ..utils import Selector +from ..utils import Text _controlSize = 100 @@ -45,7 +46,7 @@ def CreateRigVariant1(controlSize=_controlSize, *args): selected = cmds.ls(selection = True) ### Create main group as a container for all new objects - mainGroup = cmds.group(name = _nameGroupMain + selected[-1], empty = True) + mainGroup = cmds.group(name = Text.SetUniqueFromText(_nameGroupMain + selected[-1]), empty = True) ### Init empty lists for groups and locators locators = [] @@ -57,7 +58,7 @@ def CreateRigVariant1(controlSize=_controlSize, *args): ### Loop through each selected object, create groups, locators and parent them for i in range(count): ### Create locator # TODO nurbs circle as control instead of locator (optional) - locator = cmds.spaceLocator(name = _nameLocatorPrefix + selected[i])[0] + locator = cmds.spaceLocator(name = Text.SetUniqueFromText(_nameLocatorPrefix + selected[i]))[0] locators.append(locator) cmds.setAttr(locator + "Shape.localScaleX", controlSize) cmds.setAttr(locator + "Shape.localScaleY", controlSize) From 55af47912075c909dc1ee5c596d39d212fc02ae4 Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 13 Nov 2024 19:48:50 -0800 Subject: [PATCH 18/25] Update ChainDistributionRig.py --- GETOOLS_SOURCE/utils/ChainDistributionRig.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/GETOOLS_SOURCE/utils/ChainDistributionRig.py b/GETOOLS_SOURCE/utils/ChainDistributionRig.py index c6697fb..68936bc 100644 --- a/GETOOLS_SOURCE/utils/ChainDistributionRig.py +++ b/GETOOLS_SOURCE/utils/ChainDistributionRig.py @@ -110,7 +110,7 @@ def CreateRigVariant2(controlSize=_controlSize, *args): selected = cmds.ls(selection = True) ### Create main group as a container for all new objects - mainGroup = cmds.group(name = _nameGroupMain + selected[-1], empty = True) + mainGroup = cmds.group(name = Text.SetUniqueFromText(_nameGroupMain + selected[-1]), empty = True) ### Init empty lists for groups and locators groupsFixed = [] @@ -124,15 +124,15 @@ def CreateRigVariant2(controlSize=_controlSize, *args): ### Loop through each selected object, create groups, locators and parent them for i in range(count): ### Create fixed group - groupFixed = cmds.group(name = nameGroupFixedPrefix + selected[i], empty = True) + groupFixed = cmds.group(name = Text.SetUniqueFromText(nameGroupFixedPrefix + selected[i]), empty = True) groupsFixed.append(groupFixed) ### Create distribution group - groupDistributed = cmds.group(name = nameGroupDistributedPrefix + selected[i], empty = True) + groupDistributed = cmds.group(name = Text.SetUniqueFromText(nameGroupDistributedPrefix + selected[i]), empty = True) groupsDistributed.append(groupDistributed) ### Create locator # TODO use nurbs circle [circle -c 0 0 0 -nr 0 1 0 -sw 360 -r 1 -d 3 -ut 0 -tol 1e-05 -s 8 -ch 1; objectMoveCommand;] - locator = cmds.spaceLocator(name = _nameLocatorPrefix + selected[i])[0] + locator = cmds.spaceLocator(name = Text.SetUniqueFromText(_nameLocatorPrefix + selected[i]))[0] locators.append(locator) cmds.setAttr(locator + "Shape.localScaleX", controlSize) cmds.setAttr(locator + "Shape.localScaleY", controlSize) @@ -181,7 +181,7 @@ def CreateRigVariant2(controlSize=_controlSize, *args): cmds.setAttr(locators[-1] + "." + nameAttributeWeight, edit = True, keyable = True) ### Create MultiplyDivide node - nodeMultiplyDivide = cmds.createNode("multiplyDivide", name = nameMultiplyDivide) + nodeMultiplyDivide = cmds.createNode("multiplyDivide", name = Text.SetUniqueFromText(nameMultiplyDivide)) cmds.setAttr(nodeMultiplyDivide + ".operation", 2) ### Connect rotation and weight to MultiplyDivide node From 7dc8bcc718afbb5a63d80d0052b314d0638f27b6 Mon Sep 17 00:00:00 2001 From: Eugene Date: Wed, 13 Nov 2024 20:02:45 -0800 Subject: [PATCH 19/25] added alternative mode as pop-up menu --- GETOOLS_SOURCE/modules/Tools.py | 11 ++++++++--- GETOOLS_SOURCE/utils/ChainDistributionRig.py | 1 - 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/GETOOLS_SOURCE/modules/Tools.py b/GETOOLS_SOURCE/modules/Tools.py index 48b60db..9fca6d5 100644 --- a/GETOOLS_SOURCE/modules/Tools.py +++ b/GETOOLS_SOURCE/modules/Tools.py @@ -212,7 +212,9 @@ def UILayoutLocators(self, layoutMain): cmds.popupMenu() cmds.menuItem(label = "Skip Last Object Reverse Constraint", command = self.LocatorsRelativeReverseSkipLast) cmds.menuItem(label = "Without Reverse Constraint", command = self.LocatorsRelative) - cmds.button(label = "Chain Distribution", command = self.CreateChainDistributionRig, backgroundColor = Colors.purple10, annotation = ToolsAnnotations.chainDistribution) + cmds.button(label = "Chain Distribution", command = partial(self.CreateChainDistributionRig, 1), backgroundColor = Colors.purple10, annotation = ToolsAnnotations.chainDistribution) + cmds.popupMenu() + cmds.menuItem(label = "Alternative Mode", command = partial(self.CreateChainDistributionRig, 2)) ### AIM SPACE SWITCHING layoutAimSpace = cmds.frameLayout(parent = layoutColumn, label = "Aim Space Switching", labelIndent = 75, collapsable = False, backgroundColor = Settings.frames2Color, marginWidth = 0, marginHeight = 0) @@ -401,8 +403,11 @@ def LocatorsBakeAim(self, rotateOnly=False, *args): cmds.warning("Aim distance is 0. Highly recommended to use non-zero value.") ### CHAIN DISTRIBUTION RIG - def CreateChainDistributionRig(self, *args): - ChainDistributionRig.CreateRigVariant1(controlSize = self.GetFloatLocatorSize()) + def CreateChainDistributionRig(self, mode=1, *args): + if mode is 1: + ChainDistributionRig.CreateRigVariant1(controlSize = self.GetFloatLocatorSize()) + if mode is 2: + ChainDistributionRig.CreateRigVariant2(controlSize = self.GetFloatLocatorSize()) ### BAKING diff --git a/GETOOLS_SOURCE/utils/ChainDistributionRig.py b/GETOOLS_SOURCE/utils/ChainDistributionRig.py index 68936bc..00a0b5c 100644 --- a/GETOOLS_SOURCE/utils/ChainDistributionRig.py +++ b/GETOOLS_SOURCE/utils/ChainDistributionRig.py @@ -105,7 +105,6 @@ def CreateRigVariant2(controlSize=_controlSize, *args): ### Nodes names nameMultiplyDivide = "gtMultiplyDivide" - ### Create a list of names from selected objects selected = cmds.ls(selection = True) From 4ed30798e0e909514777fc8f46521d4a67645464 Mon Sep 17 00:00:00 2001 From: Eugene Date: Thu, 14 Nov 2024 14:35:39 -0800 Subject: [PATCH 20/25] update annotation and buttons width --- GETOOLS_SOURCE/modules/Tools.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/GETOOLS_SOURCE/modules/Tools.py b/GETOOLS_SOURCE/modules/Tools.py index 9fca6d5..89f4271 100644 --- a/GETOOLS_SOURCE/modules/Tools.py +++ b/GETOOLS_SOURCE/modules/Tools.py @@ -64,7 +64,7 @@ class ToolsAnnotations: locatorsRelative = "{bake}\nThe last locator becomes the parent of other locators".format(bake = locatorsBake) locatorsRelativeReverse = "{relative}\n{reverse}\nRight click allows you to bake the same operation but with constrained last object.".format(relative = locatorsRelative, reverse = _reverseConstraint) # - chainDistribution = "Create chain with distributed rotation. Use last locator to animate.\nPerfectly works with 3 selected objects.\nYou can use it for 4 and more selected objects, but be ready for unpredicted behavior." + chainDistribution = "Create a chain with distributed rotation. Use the last locator to animate.\nWorks better with 3 selected objects.\nIf you select 4+ objects, the original animation will not be fully preserved.\n\nRight-click to use the alternate mode to preserve 100% of the original animation with any number of selected objects.\nIt is not as convenient to use as the default mode." # locatorAimSpace = "Locator Aim distance from original object. Need to use non-zero value" locatorAimSpace = "Aim Space offset from original object.\nNeed to use non-zero value to get best result" @@ -207,7 +207,7 @@ def UILayoutLocators(self, layoutMain): cmds.button(label = "P-ROT", command = partial(self.LocatorsBakeReverse, False, True), backgroundColor = Colors.yellow50, annotation = ToolsAnnotations.locatorsBakeReverseRot) ### LOCATORS ROW 2 - cmds.rowLayout(parent = layoutColumn, numberOfColumns = 2, columnWidth2 = (110, 160), columnAlign = [(1, "center"), (2, "center")], columnAttach = [(1, "both", 0), (2, "both", 0)]) + cmds.rowLayout(parent = layoutColumn, numberOfColumns = 2, columnWidth2 = (113, 160), columnAlign = [(1, "center"), (2, "center")], columnAttach = [(1, "both", 0), (2, "both", 0)]) cmds.button(label = "Relative", command = self.LocatorsRelativeReverse, backgroundColor = Colors.orange10, annotation = ToolsAnnotations.locatorsRelativeReverse) cmds.popupMenu() cmds.menuItem(label = "Skip Last Object Reverse Constraint", command = self.LocatorsRelativeReverseSkipLast) From 6860a977accbbcff64e99aa162e61e3f9af042f9 Mon Sep 17 00:00:00 2001 From: Eugene Date: Mon, 18 Nov 2024 11:36:22 -0800 Subject: [PATCH 21/25] add current time revert --- GETOOLS_SOURCE/utils/ChainDistributionRig.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/GETOOLS_SOURCE/utils/ChainDistributionRig.py b/GETOOLS_SOURCE/utils/ChainDistributionRig.py index 00a0b5c..27bcace 100644 --- a/GETOOLS_SOURCE/utils/ChainDistributionRig.py +++ b/GETOOLS_SOURCE/utils/ChainDistributionRig.py @@ -38,6 +38,7 @@ def CreateRigVariant1(controlSize=_controlSize, *args): if (selectedList == None): return + timeCurrent = cmds.currentTime(query = True) timeMin = cmds.playbackOptions(query = True, min = True) timeMax = cmds.playbackOptions(query = True, max = True) cmds.currentTime(timeMin, edit = True, update = True) @@ -89,6 +90,7 @@ def CreateRigVariant1(controlSize=_controlSize, *args): ### Select last locator cmds.select(locators[-1], replace = True) + cmds.currentTime(timeCurrent, edit = True, update = True) def CreateRigVariant2(controlSize=_controlSize, *args): # Check selected objects From cf5239ec40369d76c460a5180182894dd157bace Mon Sep 17 00:00:00 2001 From: Eugene Date: Mon, 18 Nov 2024 11:45:58 -0800 Subject: [PATCH 22/25] fix Overlappy redundant timeline refresh on start --- GETOOLS_SOURCE/modules/Overlappy.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/GETOOLS_SOURCE/modules/Overlappy.py b/GETOOLS_SOURCE/modules/Overlappy.py index e3dbe91..51ac6d7 100644 --- a/GETOOLS_SOURCE/modules/Overlappy.py +++ b/GETOOLS_SOURCE/modules/Overlappy.py @@ -708,7 +708,7 @@ def UpdateParticleAllSettings(self, *args): self.UpdateParticleAimOffsetSettings() self.UpdateParticleSettings() def UpdateParticleAimOffsetSettings(self, *args): - if (self.setupCreatedPoint): + if (not self.setupCreated or self.setupCreatedPoint): return def SetParticleAimOffset(nameLocator, nameParticle, goalStartPosition, offset=(0, 0, 0)): @@ -726,6 +726,7 @@ def SetParticleAimOffset(nameLocator, nameParticle, goalStartPosition, offset=(0 self.CompileParticleAimOffset() self.time.SetCurrent(self.time.values[2]) + SetParticleAimOffset(nameLocator = self.particleLocatorGoalOffset, nameParticle = self.particleTarget, goalStartPosition = self.particleLocatorGoalOffsetStartPosition, offset = self.particleAimOffsetTarget) SetParticleAimOffset(nameLocator = self.particleLocatorGoalOffsetUp, nameParticle = self.particleUp, goalStartPosition = self.particleLocatorGoalOffsetUpStartPosition, offset = self.particleAimOffsetUp) def UpdateParticleSettings(self, *args): From b9e2f379adc5ebd83a2187dd6aa97a80f7cda4f7 Mon Sep 17 00:00:00 2001 From: Eugene Date: Mon, 18 Nov 2024 12:03:25 -0800 Subject: [PATCH 23/25] prepare for release --- GETOOLS_SOURCE/modules/GeneralWindow.py | 2 +- GETOOLS_SOURCE/modules/Tools.py | 2 +- changelog.txt | 4 ++++ todo.txt | 1 - 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/GETOOLS_SOURCE/modules/GeneralWindow.py b/GETOOLS_SOURCE/modules/GeneralWindow.py index c552e9f..97ae4e2 100644 --- a/GETOOLS_SOURCE/modules/GeneralWindow.py +++ b/GETOOLS_SOURCE/modules/GeneralWindow.py @@ -49,7 +49,7 @@ class GeneralWindow: - _version = "v1.4.4" + _version = "v1.5.0" _name = "GETools" _title = _name + " " + _version diff --git a/GETOOLS_SOURCE/modules/Tools.py b/GETOOLS_SOURCE/modules/Tools.py index 89f4271..a3a843c 100644 --- a/GETOOLS_SOURCE/modules/Tools.py +++ b/GETOOLS_SOURCE/modules/Tools.py @@ -115,7 +115,7 @@ class ToolsSettings: aimSpaceRadioButtonDefault = 0 class Tools: - _version = "v1.3" + _version = "v1.4" _name = "TOOLS" _title = _name + " " + _version diff --git a/changelog.txt b/changelog.txt index 65103b0..9483a4d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,9 @@ GETools changelog +v1.5.0 +- [TOOLS] added "Chain Distribution" button to create distributed rotatio rig over selected objects. Use last locator to control animation. +- [OVERLAPPY] removed set timeline to minimum frame on plugin start. + v1.4.4 - added Maya version check to avoid compatibility issues with Maya 2020 and older. - removed requirement to use separate GETools version for Maya 2020. diff --git a/todo.txt b/todo.txt index 121c3dd..09957a2 100644 --- a/todo.txt +++ b/todo.txt @@ -1,7 +1,6 @@ GETools TODO List [TOOLS] -- chain distribution rig - pin scale - rotate Order rebake - relative Camera From fe37176e4f6b8f9fe82d39fc33a2c652c9ce7e84 Mon Sep 17 00:00:00 2001 From: Eugene Date: Tue, 19 Nov 2024 19:50:22 -0800 Subject: [PATCH 24/25] save: - add chain distribution button install - added full parameters names to installed buttons --- GETOOLS_SOURCE/modules/GeneralWindow.py | 5 +++ GETOOLS_SOURCE/modules/Tools.py | 4 +-- GETOOLS_SOURCE/utils/ChainDistributionRig.py | 18 +++++----- GETOOLS_SOURCE/utils/Install.py | 37 +++++++++++--------- GETOOLS_SOURCE/values/CodeSamples.py | 8 +++++ changelog.txt | 1 + 6 files changed, 46 insertions(+), 27 deletions(-) diff --git a/GETOOLS_SOURCE/modules/GeneralWindow.py b/GETOOLS_SOURCE/modules/GeneralWindow.py index 97ae4e2..1573e41 100644 --- a/GETOOLS_SOURCE/modules/GeneralWindow.py +++ b/GETOOLS_SOURCE/modules/GeneralWindow.py @@ -277,6 +277,11 @@ def LayoutMenuOptions(self): cmds.menuItem(label = "Without Reverse Constraint", command = partial(Install.ToShelf_LocatorsRelativeWithoutReverse, self.optionsPlugin.directory)) cmds.setParent('..', menu = True) # + cmds.menuItem(subMenu = True, label = "Chain Distribution", tearOff = True, image = Icons.pinInvert) + cmds.menuItem(label = "Default Mode", command = partial(Install.ToShelf_LocatorsChainDistribution1, self.optionsPlugin.directory)) + cmds.menuItem(label = "Alternative Mode", command = partial(Install.ToShelf_LocatorsChainDistribution2, self.optionsPlugin.directory)) + cmds.setParent('..', menu = True) + # cmds.menuItem(subMenu = True, label = "Aim", tearOff = True, image = Icons.pin) minus = "-" plus = "+" diff --git a/GETOOLS_SOURCE/modules/Tools.py b/GETOOLS_SOURCE/modules/Tools.py index a3a843c..8145a1d 100644 --- a/GETOOLS_SOURCE/modules/Tools.py +++ b/GETOOLS_SOURCE/modules/Tools.py @@ -405,9 +405,9 @@ def LocatorsBakeAim(self, rotateOnly=False, *args): ### CHAIN DISTRIBUTION RIG def CreateChainDistributionRig(self, mode=1, *args): if mode is 1: - ChainDistributionRig.CreateRigVariant1(controlSize = self.GetFloatLocatorSize()) + ChainDistributionRig.CreateRigVariant1(locatorSize = self.GetFloatLocatorSize()) if mode is 2: - ChainDistributionRig.CreateRigVariant2(controlSize = self.GetFloatLocatorSize()) + ChainDistributionRig.CreateRigVariant2(locatorSize = self.GetFloatLocatorSize()) ### BAKING diff --git a/GETOOLS_SOURCE/utils/ChainDistributionRig.py b/GETOOLS_SOURCE/utils/ChainDistributionRig.py index 27bcace..e4906cf 100644 --- a/GETOOLS_SOURCE/utils/ChainDistributionRig.py +++ b/GETOOLS_SOURCE/utils/ChainDistributionRig.py @@ -27,12 +27,12 @@ from ..utils import Text -_controlSize = 100 +_locatorSize = 100 _nameGroupMain = "grpChain_" _nameLocatorPrefix = "loc_" -def CreateRigVariant1(controlSize=_controlSize, *args): +def CreateRigVariant1(locatorSize=_locatorSize, *args): # Check selected objects selectedList = Selector.MultipleObjects(minimalCount = 1) if (selectedList == None): @@ -61,9 +61,9 @@ def CreateRigVariant1(controlSize=_controlSize, *args): ### Create locator # TODO nurbs circle as control instead of locator (optional) locator = cmds.spaceLocator(name = Text.SetUniqueFromText(_nameLocatorPrefix + selected[i]))[0] locators.append(locator) - cmds.setAttr(locator + "Shape.localScaleX", controlSize) - cmds.setAttr(locator + "Shape.localScaleY", controlSize) - cmds.setAttr(locator + "Shape.localScaleZ", controlSize) + cmds.setAttr(locator + "Shape.localScaleX", locatorSize) + cmds.setAttr(locator + "Shape.localScaleY", locatorSize) + cmds.setAttr(locator + "Shape.localScaleZ", locatorSize) ### Parent locator to group cmds.parent(locator, mainGroup) @@ -92,7 +92,7 @@ def CreateRigVariant1(controlSize=_controlSize, *args): cmds.select(locators[-1], replace = True) cmds.currentTime(timeCurrent, edit = True, update = True) -def CreateRigVariant2(controlSize=_controlSize, *args): +def CreateRigVariant2(locatorSize=_locatorSize, *args): # Check selected objects selectedList = Selector.MultipleObjects(minimalCount = 1) if (selectedList == None): @@ -135,9 +135,9 @@ def CreateRigVariant2(controlSize=_controlSize, *args): ### Create locator # TODO use nurbs circle [circle -c 0 0 0 -nr 0 1 0 -sw 360 -r 1 -d 3 -ut 0 -tol 1e-05 -s 8 -ch 1; objectMoveCommand;] locator = cmds.spaceLocator(name = Text.SetUniqueFromText(_nameLocatorPrefix + selected[i]))[0] locators.append(locator) - cmds.setAttr(locator + "Shape.localScaleX", controlSize) - cmds.setAttr(locator + "Shape.localScaleY", controlSize) - cmds.setAttr(locator + "Shape.localScaleZ", controlSize) + cmds.setAttr(locator + "Shape.localScaleX", locatorSize) + cmds.setAttr(locator + "Shape.localScaleY", locatorSize) + cmds.setAttr(locator + "Shape.localScaleZ", locatorSize) ### Parent locator to group cmds.parent(locator, groupDistributed) diff --git a/GETOOLS_SOURCE/utils/Install.py b/GETOOLS_SOURCE/utils/Install.py index 9e5f5f5..627d8f0 100644 --- a/GETOOLS_SOURCE/utils/Install.py +++ b/GETOOLS_SOURCE/utils/Install.py @@ -129,13 +129,13 @@ def ToShelf_ToggleTextures(path, *args): MoveToShelf(path, ReadFunctionAsString( # LOCATORS def ToShelf_LocatorsSizeScale50(path, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.LocatorsSizeScale) + "(0.5)", "LocatorsSizeScale50", "L50%") + MoveToShelf(path, ReadFunctionAsString(CodeSamples.LocatorsSizeScale) + "(value = 0.5)", "LocatorsSizeScale50", "L50%") def ToShelf_LocatorsSizeScale90(path, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.LocatorsSizeScale) + "(0.9)", "LocatorsSizeScale90", "L90%") + MoveToShelf(path, ReadFunctionAsString(CodeSamples.LocatorsSizeScale) + "(value = 0.9)", "LocatorsSizeScale90", "L90%") def ToShelf_LocatorsSizeScale110(path, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.LocatorsSizeScale) + "(1.1)", "LocatorsSizeScale110", "L110%") + MoveToShelf(path, ReadFunctionAsString(CodeSamples.LocatorsSizeScale) + "(value = 1.1)", "LocatorsSizeScale110", "L110%") def ToShelf_LocatorsSizeScale200(path, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.LocatorsSizeScale) + "(2.0)", "LocatorsSizeScale200", "L200%") + MoveToShelf(path, ReadFunctionAsString(CodeSamples.LocatorsSizeScale) + "(value = 2.0)", "LocatorsSizeScale200", "L200%") def ToShelf_LocatorCreate(path, *args): MoveToShelf(path, ReadFunctionAsString(CodeSamples.LocatorCreate), "LocatorCreate", "Loc") @@ -160,6 +160,11 @@ def ToShelf_LocatorsRelativeSkipLast(path, *args): def ToShelf_LocatorsRelativeWithoutReverse(path, *args): MoveToShelf(path, ReadFunctionAsString(CodeSamples.LocatorsRelativeWithoutReverse), "RelativeWithoutReverse", "Rel-") +def ToShelf_LocatorsChainDistribution1(path, *args): + MoveToShelf(path, ReadFunctionAsString(CodeSamples.LocatorsChainDistribution1), "LocatorsChainDistribution1", "CDistr1") +def ToShelf_LocatorsChainDistribution2(path, *args): + MoveToShelf(path, ReadFunctionAsString(CodeSamples.LocatorsChainDistribution2), "LocatorsChainDistribution2", "CDistr2") + def ToShelf_LocatorsAim(path, name, rotateOnly, aimVector, *args): parameters = "(rotateOnly = {0}, vectorAim = {1}, reverse = True)".format(rotateOnly, aimVector) MoveToShelf(path, ReadFunctionAsString(CodeSamples.LocatorsAim) + parameters, "LocatorsAim{0}".format(name), "Aim {0}".format(name)) @@ -203,7 +208,7 @@ def ToShelf_BakeByWorld(path, translate, rotate, *args): # ANIMATION def ToShelf_AnimOffsetSelected(path, direction, time, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.AnimOffsetSelected) + "({0}, {1})".format(direction, time), "AnimOffset_{0}_{1}".format(direction, time), "AO{0}_{1}".format(direction, time)) + MoveToShelf(path, ReadFunctionAsString(CodeSamples.AnimOffsetSelected) + "(direction = {0}, step = {1})".format(direction, time), "AnimOffset_{0}_{1}".format(direction, time), "AO{0}_{1}".format(direction, time)) def ToShelf_DeleteKeys(path, *args): MoveToShelf(path, ReadFunctionAsString(CodeSamples.DeleteKeys), "DeleteKeys", "DKeys") @@ -215,23 +220,23 @@ def ToShelf_DeleteStatic(path, *args): def ToShelf_EulerFilterOnSelected(path, *args): MoveToShelf(path, ReadFunctionAsString(CodeSamples.EulerFilterOnSelected), "EulerFilter", "Euler") def ToShelf_SetInfinity(path, mode, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetInfinity) + "({0})".format(mode), "SetInfinity{0}".format(mode), "Inf{0}".format(mode)) + MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetInfinity) + "(mode = {0})".format(mode), "SetInfinity{0}".format(mode), "Inf{0}".format(mode)) # TIMELINE def ToShelf_SetTimelineMinOut(path, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(3)", "SetTimelineMinOut", "<<") + MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(mode = 3)", "SetTimelineMinOut", "<<") def ToShelf_SetTimelineMinIn(path, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(1)", "SetTimelineMinIn", "<-") + MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(mode = 1)", "SetTimelineMinIn", "<-") def ToShelf_SetTimelineMaxIn(path, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(2)", "SetTimelineMaxIn", "->") + MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(mode = 2)", "SetTimelineMaxIn", "->") def ToShelf_SetTimelineMaxOut(path, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(4)", "SetTimelineMaxOut", ">>") + MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(mode = 4)", "SetTimelineMaxOut", ">>") def ToShelf_SetTimelineFocusOut(path, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(5)", "SetTimelineFocusOut", "<->") + MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(mode = 5)", "SetTimelineFocusOut", "<->") def ToShelf_SetTimelineFocusIn(path, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(6)", "SetTimelineFocusIn", ">-<") + MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(mode = 6)", "SetTimelineFocusIn", ">-<") def ToShelf_SetTimelineSet(path, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(7)", "SetTimelineSet", "|<->|") + MoveToShelf(path, ReadFunctionAsString(CodeSamples.SetTimeline) + "(mode = 7)", "SetTimelineSet", "|<->|") # RIGGING def ToShelf_Constraint(path, maintainOffset, parent, point, orient, scale, *args): @@ -258,11 +263,11 @@ def ToShelf_DisconnectTargets(path, *args): MoveToShelf(path, ReadFunctionAsString(CodeSamples.DisconnectTargets), "DisconnectTargets", "Disconnect") def ToShelf_RotateOrder(path, mode, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.RotateOrder) + "({0})".format(mode), "RotateOrder{0}".format(mode), "RO{0}".format(mode)) + MoveToShelf(path, ReadFunctionAsString(CodeSamples.RotateOrder) + "(on = {0})".format(mode), "RotateOrder{0}".format(mode), "RO{0}".format(mode)) def ToShelf_SegmentScaleCompensate(path, mode, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.SegmentScaleCompensate) + "({0})".format(mode), "SegmentScaleCompensate{0}".format(mode), "SSC{0}".format(mode)) + MoveToShelf(path, ReadFunctionAsString(CodeSamples.SegmentScaleCompensate) + "(value = {0})".format(mode), "SegmentScaleCompensate{0}".format(mode), "SSC{0}".format(mode)) def ToShelf_JointDrawStyle(path, mode, *args): - MoveToShelf(path, ReadFunctionAsString(CodeSamples.JointDrawStyle) + "({0})".format(mode), "JointDrawStyle{0}".format(mode), "J{0}".format(mode)) + MoveToShelf(path, ReadFunctionAsString(CodeSamples.JointDrawStyle) + "(mode = {0})".format(mode), "JointDrawStyle{0}".format(mode), "J{0}".format(mode)) def ToShelf_CopySkin(path, *args): MoveToShelf(path, ReadFunctionAsString(CodeSamples.CopySkin), "CopySkin", "CopySkin") diff --git a/GETOOLS_SOURCE/values/CodeSamples.py b/GETOOLS_SOURCE/values/CodeSamples.py index bf305a3..9ddc504 100644 --- a/GETOOLS_SOURCE/values/CodeSamples.py +++ b/GETOOLS_SOURCE/values/CodeSamples.py @@ -227,6 +227,14 @@ def LocatorsRelativeWithoutReverse(): import GETOOLS_SOURCE.utils.Locators as Locators Locators.CreateAndBakeAsChildrenFromLastSelected() +def LocatorsChainDistribution1(): + import GETOOLS_SOURCE.utils.ChainDistributionRig as ChainDistributionRig + ChainDistributionRig.CreateRigVariant1(locatorSize = 10) + +def LocatorsChainDistribution2(): + import GETOOLS_SOURCE.utils.ChainDistributionRig as ChainDistributionRig + ChainDistributionRig.CreateRigVariant2(locatorSize = 10) + def LocatorsAim(): # brackets added when method used import GETOOLS_SOURCE.utils.Locators as Locators Locators.CreateOnSelectedAim diff --git a/changelog.txt b/changelog.txt index 9483a4d..8cc8888 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,7 @@ GETools changelog v1.5.0 - [TOOLS] added "Chain Distribution" button to create distributed rotatio rig over selected objects. Use last locator to control animation. - [OVERLAPPY] removed set timeline to minimum frame on plugin start. +- added full parameters names to installed buttons v1.4.4 - added Maya version check to avoid compatibility issues with Maya 2020 and older. From fbf96dc8864b6fd1dd5506bec7ac8cbddf6cfcda Mon Sep 17 00:00:00 2001 From: Eugene Date: Tue, 19 Nov 2024 20:01:54 -0800 Subject: [PATCH 25/25] update readme --- README.md | 6 ++++-- changelog.txt | 3 ++- install_info.txt | 6 +++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 25e08de..2ddf416 100644 --- a/README.md +++ b/README.md @@ -31,8 +31,10 @@ Discover tools for creating locators, space switching, simulating secondary anim # How to install ### First install: 1. Extract files from ZIP archive -2. Remove version numbers from folder name (use simple **"GETools"** name) -3. Drag and drop GETools\TOOLS\DRAG_AND_DROP_INSTALL.py into Maya viewport +2. Create folder `"GETools"` somewhere you prefer to keep scripts for Maya. `For example: "C:/Users/Username/Documents/maya/scripts/GETools"` +3. Copy/Paste all files from GETools folder **(usually it's 6+ files)** +4. Drag and drop `DRAG_AND_DROP_INSTALL.py` into Maya's viewport +5. Your folder should look like in this screenshot **(the most important folder is "GETOOLS_SOURCE")** ![image](https://github.com/user-attachments/assets/3bfd0765-0cee-420b-9717-4a19d4784592) ### Update to new version: diff --git a/changelog.txt b/changelog.txt index 8cc8888..4dbde0f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,7 +3,8 @@ GETools changelog v1.5.0 - [TOOLS] added "Chain Distribution" button to create distributed rotatio rig over selected objects. Use last locator to control animation. - [OVERLAPPY] removed set timeline to minimum frame on plugin start. -- added full parameters names to installed buttons +- added full parameters names to installed buttons. +- updated install instruction Readme file. v1.4.4 - added Maya version check to avoid compatibility issues with Maya 2020 and older. diff --git a/install_info.txt b/install_info.txt index 5947a7c..f10d584 100644 --- a/install_info.txt +++ b/install_info.txt @@ -4,4 +4,8 @@ For example: "C:/Users/Username/Documents/maya/scripts/GETools" 2. Drag and Drop the "DRAG_AND_DROP_INSTALL.py" file into Maya viewport. GETools will be added to the current shelf as new button. -3. It's done! \ No newline at end of file +3. Enjoy! + + + +p.s. Let me know if you see any issues, it's really help to fix bugs and develop GETools faster. Thank you. \ No newline at end of file