Skip to content

Commit

Permalink
Merge pull request #113 from GenEugene/center-of-mass-smart-projection
Browse files Browse the repository at this point in the history
Cleanup and add some tools
  • Loading branch information
GenEugene authored Nov 8, 2024
2 parents 310f5bf + 988d1c3 commit 8fca2a6
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 25 deletions.
12 changes: 6 additions & 6 deletions GETOOLS_SOURCE/modules/GeneralWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@


class GeneralWindow:
_version = "v1.3.8"
_version = "v1.4.0"
_name = "GETools"
_title = _name + " " + _version

Expand Down Expand Up @@ -119,7 +119,7 @@ def ColorsPalette(*args):
cmds.menuItem(dividerLabel = "Prints", divider = True)
cmds.menuItem(label = "Print Selected Objects To Console", command = Print.PrintSelected, image = Icons.text)
cmds.menuItem(label = "Print Animatable Attributes", command = partial(Print.PrintAttributesAnimatableOnSelected, False), image = Icons.text)
cmds.menuItem(label = "Print Animatable Attributes With Shapes", command = partial(Print.PrintAttributesAnimatableOnSelected, True), image = Icons.text)
# cmds.menuItem(label = "Print Animatable Attributes With Shapes", command = partial(Print.PrintAttributesAnimatableOnSelected, True), image = Icons.text) # FIXME
cmds.menuItem(label = "Print Channel Box Selected Attributes", command = Print.PrintAttributesSelectedFromChannelBox, image = Icons.text)
cmds.menuItem(dividerLabel = "Blendshapes", divider = True)
cmds.menuItem(label = "Print Blendshapes Base Nodes", command = Blendshapes.GetBlendshapeNodesFromSelected, image = Icons.text)
Expand Down Expand Up @@ -166,25 +166,25 @@ def LinkVersionHistory(self): cmds.showHelp("https://github.com/GenEugene/GETool
def LinkGithub(self): cmds.showHelp("https://github.com/GenEugene/GETools", absolute = True)
def LinkGumroad(self): cmds.showHelp("https://gumroad.com/l/iCNa", absolute = True)
def LinkGithubWiki(self): cmds.showHelp("https://github.com/GenEugene/GETools/wiki", absolute = True)
def LinkYoutubeTutorial(self): cmds.showHelp("https://youtube.com/playlist?list=PLhwndaM4LAxhbl95yz9WVie1iYflTFy6S&si=UOoK-mdk4Rm5bVyp", absolute = True)
def LinkYoutubeVideos(self): cmds.showHelp("https://youtube.com/playlist?list=PLhwndaM4LAxhbl95yz9WVie1iYflTFy6S&si=UOoK-mdk4Rm5bVyp", absolute = True)
def LinkLinkedin(self): cmds.showHelp("https://www.linkedin.com/in/geneugene", absolute = True)
def LinkYoutube(self): cmds.showHelp("https://youtube.com/@EugeneGataulin", absolute = True)
def LinkDiscord(self): cmds.showHelp("https://discord.gg/heMxJhTqCz", absolute = True)
def LinkShareIdeas(self): cmds.showHelp("https://github.com/GenEugene/GETools/discussions/categories/ideas", absolute = True)
def LinkReport(self): cmds.showHelp("https://github.com/GenEugene/GETools/discussions/categories/report-a-problem", absolute = True)

cmds.menuItem(label = "About GETools", enable = False, image = self.directory + Icons.get1[0]) # TODO add window with information
# cmds.menuItem(label = "About GETools", enable = False, image = self.directory + Icons.get1[0]) # TODO add window with information
cmds.menuItem(label = "Version History", command = LinkVersionHistory)
cmds.menuItem(dividerLabel = "Links", divider = True)
cmds.menuItem(label = "GitHub", command = LinkGithub, image = Icons.home)
cmds.menuItem(label = "Gumroad", command = LinkGumroad)
cmds.menuItem(dividerLabel = "HOW TO USE", divider = True)
cmds.menuItem(label = "Documentation", command = LinkGithubWiki, image = Icons.help)
cmds.menuItem(label = "Tutorial Video", command = LinkYoutubeTutorial, image = Icons.playblast)
cmds.menuItem(label = "Videos Playlist", command = LinkYoutubeVideos, image = Icons.playblast)
cmds.menuItem(dividerLabel = "Contacts", divider = True)
cmds.menuItem(label = "Discord", command = LinkDiscord)
cmds.menuItem(label = "Linkedin", command = LinkLinkedin)
cmds.menuItem(label = "YouTube", command = LinkYoutube)
cmds.menuItem(label = "Discord", command = LinkDiscord)
cmds.menuItem(dividerLabel = "Support", divider = True)
cmds.menuItem(label = "Share Your Ideas", command = LinkShareIdeas, image = Icons.light)
cmds.menuItem(label = "Report a Problem", command = LinkReport, image = Icons.warning)
Expand Down
53 changes: 42 additions & 11 deletions GETOOLS_SOURCE/modules/Rigging.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@
from ..utils import Blendshapes
from ..utils import Colors
from ..utils import Constraints
from ..utils import Create
from ..utils import Curves
from ..utils import Deformers
from ..utils import Other
from ..utils import Skinning
from ..utils import UI


class RiggingAnnotations:
Expand Down Expand Up @@ -72,16 +72,45 @@ class RiggingAnnotations:
curveCreateFromTrajectory = "***DRAFT***\nCreate a curve from objects trajectories."

class Rigging:
_version = "v1.5"
_version = "v1.6"
_name = "RIGGING"
_title = _name + " " + _version

def __init__(self):
self.checkboxConstraintReverse = None
self.checkboxConstraintMaintain = None
# self.checkboxConstraintOffset = None

self.intFieldPolygonWithLocatorsPoints = None
self.floatFieldPolygonWithLocatorsRadius = None
self.floatFieldPolygonWithLocatorsAngle = None

def UICreate(self, layoutMain):
### CONSTRAINTS
### POLYGON WITH LOCATORS
self.UILayoutPolygonWithLocators(layoutMain)
self.UILayoutConstraints(layoutMain)
self.UILayoutUtils(layoutMain)
self.UILayoutBlendshapes(layoutMain)
self.UILayoutCurves(layoutMain)

def UILayoutPolygonWithLocators(self, layoutMain):
layoutMesh = cmds.frameLayout(parent = layoutMain, label = Settings.frames2Prefix + "POLYGON WITH LOCATORS", collapsable = True, backgroundColor = Settings.frames2Color, marginWidth = 0, marginHeight = 0)
cellWidth1 = 75
cellWidth2 = 75
cellWidth3 = 75
cellWidth4 = 40
rowLayout = cmds.rowLayout(parent = layoutMesh, numberOfColumns = 4, columnWidth4 = (cellWidth1, cellWidth2, cellWidth3, cellWidth4), columnAlign = [(1, "right"), (2, "center"), (3, "center"), (4, "center")], columnAttach = [(1, "both", 0), (2, "both", 0), (3, "both", 0), (4, "both", 0)])
cmds.gridLayout(parent = rowLayout, numberOfColumns = 2, cellWidth = cellWidth1 / 2, cellHeight = Settings.lineHeight)
cmds.text(label = "Points")
self.intFieldPolygonWithLocatorsPoints = cmds.intField(value = 3, minValue = 3)
cmds.gridLayout(parent = rowLayout, numberOfColumns = 2, cellWidth = cellWidth2 / 2, cellHeight = Settings.lineHeight)
cmds.text(label = "Radius")
self.floatFieldPolygonWithLocatorsRadius = cmds.floatField(value = 10, minValue = 0, precision = 1)
cmds.gridLayout(parent = rowLayout, numberOfColumns = 2, cellWidth = cellWidth3 / 2, cellHeight = Settings.lineHeight)
cmds.text(label = "Angle")
self.floatFieldPolygonWithLocatorsAngle = cmds.floatField(value = 0, precision = 1)
cmds.button(parent = rowLayout, label = "Create", command = self.CreatePolygonWithLocators, backgroundColor = Colors.green10)
def UILayoutConstraints(self, layoutMain):
layoutConstraints = cmds.frameLayout(parent = layoutMain, label = Settings.frames2Prefix + "CONSTRAINTS", collapsable = True, backgroundColor = Settings.frames2Color, marginWidth = 0, marginHeight = 0)
layoutColumnConstraints = cmds.columnLayout(parent = layoutConstraints, adjustableColumn = True)
#
Expand All @@ -105,9 +134,7 @@ def UICreate(self, layoutMain):
cmds.gridLayout(parent = layoutColumnConstraints, numberOfColumns = countOffsets, cellWidth = Settings.windowWidthMargin / countOffsets, cellHeight = Settings.lineHeight)
cmds.button(label = "Disconnect", command = Constraints.DisconnectTargetsFromConstraintOnSelected, backgroundColor = Colors.red50, annotation = RiggingAnnotations.constraintDisconnectSelected)
cmds.button(label = "Delete Constraints", command = Constraints.DeleteConstraintsOnSelected, backgroundColor = Colors.red50, annotation = RiggingAnnotations.constraintDelete)


### UTILS
def UILayoutUtils(self, layoutMain):
layoutUtils = cmds.frameLayout(parent = layoutMain, label = Settings.frames2Prefix + "UTILS", collapsable = True, backgroundColor = Settings.frames2Color, marginWidth = 0, marginHeight = 0)
layoutColumnUtils = cmds.columnLayout(parent = layoutUtils, adjustableColumn = True)
#
Expand All @@ -131,8 +158,7 @@ def UICreate(self, layoutMain):
countOffsets = 1
cmds.gridLayout(parent = layoutColumnUtils, numberOfColumns = countOffsets, cellWidth = Settings.windowWidthMargin / countOffsets, cellHeight = Settings.lineHeight)
cmds.button(label = "Copy Skin Weights From Last Selected", command = Skinning.CopySkinWeightsFromLastMesh, backgroundColor = Colors.blue10, annotation = RiggingAnnotations.copySkinWeights)

### BLENDSHAPES
def UILayoutBlendshapes(self, layoutMain):
layoutBlendshapes = cmds.frameLayout(parent = layoutMain, label = Settings.frames2Prefix + "BLENDSHAPES", collapsable = True, backgroundColor = Settings.frames2Color, marginWidth = 0, marginHeight = 0)
layoutColumnBlendshapes = cmds.columnLayout(parent = layoutBlendshapes, adjustableColumn = True)
#
Expand All @@ -146,8 +172,7 @@ def UICreate(self, layoutMain):
countOffsets = 1
cmds.gridLayout(parent = layoutColumnBlendshapes, numberOfColumns = countOffsets, cellWidth = Settings.windowWidthMargin / countOffsets, cellHeight = Settings.lineHeight)
cmds.button(label = "Zero Weights", command = Blendshapes.ZeroBlendshapeWeightsOnSelected, backgroundColor = Colors.blackWhite100, annotation = RiggingAnnotations.blendshapeZeroWeights)

### CURVES
def UILayoutCurves(self, layoutMain):
layoutCurves = cmds.frameLayout(parent = layoutMain, label = Settings.frames2Prefix + "CURVES", collapsable = True, backgroundColor = Settings.frames2Color, marginWidth = 0, marginHeight = 0)
layoutColumnCurves = cmds.columnLayout(parent = layoutCurves, adjustableColumn = True)
#
Expand All @@ -156,7 +181,6 @@ def UICreate(self, layoutMain):
cmds.button(label = "From Selected Objects", command = Curves.CreateCurveFromSelectedObjects, backgroundColor = Colors.blue10, annotation = RiggingAnnotations.curveCreateFromSelectedObjects)
cmds.button(label = "From Trajectory", command = Curves.CreateCurveFromTrajectory, backgroundColor = Colors.orange10, annotation = RiggingAnnotations.curveCreateFromTrajectory)


### CONSTRAINTS
def GetCheckboxConstraintReverse(self):
return cmds.checkBox(self.checkboxConstraintReverse, query = True, value = True)
Expand All @@ -174,3 +198,10 @@ def ConstrainScale(self, *args):
def ConstrainAim(self, *args): # TODO
Constraints.ConstrainSelectedToLastObject(reverse = self.GetCheckboxConstraintReverse(), maintainOffset = self.GetCheckboxConstraintMaintain(), parent = False, point = False, orient = False, scale = False, aim = True)

### MESH
def CreatePolygonWithLocators(self, *args):
points = cmds.intField(self.intFieldPolygonWithLocatorsPoints, query = True, value = True)
radius = cmds.floatField(self.floatFieldPolygonWithLocatorsRadius, query = True, value = True)
angle = cmds.floatField(self.floatFieldPolygonWithLocatorsAngle, query = True, value = True)
Create.CreatePolygonWithLocators(countPoints = points, radius = radius, rotation = angle)

2 changes: 1 addition & 1 deletion GETOOLS_SOURCE/utils/Attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def FilterAttributesWithoutAnimation(attributes):

return attributesWithoutAnimation

def GetAttributesAnimatableOnSelected(useShapes=False):
def GetAttributesAnimatableOnSelected(useShapes=False): # TODO fix shapes detection, check on curves, cameras, meshes
# Check selected objects
selectedList = Selector.MultipleObjects(minimalCount = 1, transformsOnly = False)
if (selectedList == None):
Expand Down
94 changes: 94 additions & 0 deletions GETOOLS_SOURCE/utils/Create.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# 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
import math

from ..utils import Text


nameGroup = "grpPolygon"
namePolygon = "customPolygon"
nameLocator = "locator_"
nameCluster = "cluster_"


def CreatePolygonWithLocators(countPoints=3, radius=10, rotation=0):
if countPoints < 3:
cmds.warning("Number of points must be 3 or more to create a polygon")
return None

### Create main group as a container for all new objects
mainGroup = cmds.group(name = Text.SetUniqueFromText(nameGroup), empty = True)
cmds.setAttr(mainGroup + ".tx", lock = True)
cmds.setAttr(mainGroup + ".ty", lock = True)
cmds.setAttr(mainGroup + ".tz", lock = True)
cmds.setAttr(mainGroup + ".rx", lock = True)
cmds.setAttr(mainGroup + ".ry", lock = True)
cmds.setAttr(mainGroup + ".rz", lock = True)
cmds.setAttr(mainGroup + ".sx", lock = True)
cmds.setAttr(mainGroup + ".sy", lock = True)
cmds.setAttr(mainGroup + ".sz", lock = True)

### Calculate vertex positions based on the number of points and radius
angleStep = 360 / countPoints
vertices = []
for i in range(countPoints):
angleRadian = math.radians(i * angleStep + rotation)
x = math.cos(angleRadian) * radius
z = math.sin(angleRadian) * radius
vertices.append((x, 0, z))

### Create the polygon
poly = cmds.polyCreateFacet(point = vertices, name = Text.SetUniqueFromText(namePolygon))[0]

### Invert normals so the polygon faces upwards
cmds.polyNormal(poly, normalMode = 0) # normalMode = 0 inverts normals

### Create locators for each vertex and attach them via clusters
locators = []
handles = []
for i, vertex in enumerate(vertices):
### Create locator and position it at the vertex's initial position
locator = cmds.spaceLocator(name = Text.SetUniqueFromText("{0}{1}".format(nameLocator, i + 1)))[0]
locators.append(locator)
cmds.xform(locator, worldSpace = True, translation = vertex)

### Create a cluster for the current vertex
cluster, handle = cmds.cluster("{0}.vtx[{1}]".format(poly, i), name = Text.SetUniqueFromText("{0}{1}".format(nameCluster, i + 1)))
handles.append(handle)
cmds.setAttr(handle + ".visibility", 0)

### Attach the cluster to the locator
cmds.pointConstraint(locator, handle, maintainOffset = False)

### Parent to group
cmds.parent(poly, mainGroup)
cmds.parent(locators, mainGroup)
cmds.parent(handles, mainGroup)

### Select polygon
cmds.select(poly, replace = True)

return poly, locators, handles

12 changes: 5 additions & 7 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
GETools changelog

***FUTURE PLAN***
- TODO [PHYSICS] added new physics with nHair logic
- TODO [OVERLAPPY] added Chain mode with nHair
- TODO [OVERLAPPY] added collisions UI
- TODO [OVERLAPPY] added nRigid collision logic
- TODO added non-cycle origin animation with loop mode
**********************************************
v1.4.0
- [TOOLS] added "Polygon With Locators" button to create custom polygons with locators for each vertex
- [TOOLS] extracted Rigging UI code blocks to separate functions
- [UTILS] removed "Print Animatable Attributes With Shapes" button because of redundancy
- [UI] changed some button names

v1.3.8
- [CENTER OF MASS] fixed constraining to multiple selected objects
Expand Down
27 changes: 27 additions & 0 deletions todo.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
GETools TODO List

[TOOLS]
- chain distribution rig
- pin scale
- rotate Order rebake
- relative Camera

[RIGGING]
- finish Create curve from trajectory button

[OVERLAPPY]
- fix particle offset on loop mode
- fix nucleus double nodes
- fix loop mode with rootmotion
- non-cycle origin animation with loop mode
- scale baking
- chain mode with nHair
- nRigid collision logic
- collisions UI

[PHYSICS]
- physics with nHair logic

[CENTER OF MASS]
- improve projection approach

0 comments on commit 8fca2a6

Please sign in to comment.