Skip to content

Commit

Permalink
Merge pull request #193 from TrevisanGMW/dev
Browse files Browse the repository at this point in the history
release <- dev (3.2.1)
  • Loading branch information
TrevisanGMW authored Sep 27, 2023
2 parents 11d7b6d + 07f75c5 commit c98ac6d
Show file tree
Hide file tree
Showing 57 changed files with 3,048 additions and 873 deletions.
2 changes: 1 addition & 1 deletion gt/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import sys

# Package Variables
__version_tuple__ = (3, 2, 0)
__version_tuple__ = (3, 2, 1)
__version_suffix__ = ''
__version__ = '.'.join(str(n) for n in __version_tuple__) + __version_suffix__
__authors__ = ['Guilherme Trevisan']
Expand Down
6 changes: 4 additions & 2 deletions gt/utils/attr_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,17 +494,19 @@ def get_multiple_attr(attribute_path=None, obj_list=None, attr_list=None, enum_a
return attribute_values


def get_trs_attr_as_list(obj):
def get_trs_attr_as_list(obj, verbose=True):
"""
Gets Translate, Rotation and Scale values as a list
Args:
obj (str): Name of the source object
verbose (bool, optional): If active, it will return a warning when the object is missing.
Returns:
list or None: A list with TRS values in order [TX, TY, TZ, RX, RY, RZ, SX, SY, SZ], None if missing object.
e.g. [0, 0, 0, 15, 15, 15, 1, 1, 1]
"""
if not obj or not cmds.objExists(obj):
logger.warning(f'Unable to get TRS channels as list. Unable to find object "{obj}".')
if verbose:
logger.warning(f'Unable to get TRS channels as list. Unable to find object "{obj}".')
return
output = []
for channel in DEFAULT_CHANNELS: # TRS
Expand Down
155 changes: 96 additions & 59 deletions gt/utils/cleanup_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,59 +13,74 @@
logger.setLevel(logging.INFO)


def delete_unused_nodes():
def delete_unused_nodes(verbose=True):
"""
Deleted unused nodes (such as materials not connected to anything or nodes without any connections)
This is done through a Maya MEL function "MLdeleteUnused()" but it's called here again for better feedback.
Args:
verbose (bool, optional): If True, it will print feedback with the number of unused deleted nodes.
Returns:
int: Number of unused deleted nodes.
"""
num_deleted_nodes = mel.eval('MLdeleteUnused();')
feedback = FeedbackMessage(quantity=num_deleted_nodes,
singular='unused node was',
plural='unused nodes were',
conclusion='deleted.',
zero_overwrite_message='No unused nodes found in this scene.')
feedback.print_inview_message()
if verbose:
feedback = FeedbackMessage(quantity=num_deleted_nodes,
singular='unused node was',
plural='unused nodes were',
conclusion='deleted.',
zero_overwrite_message='No unused nodes found in this scene.')
feedback.print_inview_message()
return num_deleted_nodes


def delete_nucleus_nodes():
""" Deletes all elements related to particles """
def delete_nucleus_nodes(verbose=True, include_fields=True):
"""
Deletes all elements related to particles.
Args:
verbose (bool, optional): If True, it will print feedback with the number of deleted nodes.
include_fields (bool, optional): If True, it will also count field as "nucleus nodes" to be deleted.
Returns:
int: Number of nucleus deleted nodes.
"""
errors = ''
function_name = 'Delete Nucleus Nodes'
deleted_counter = 0
try:
cmds.undoInfo(openChunk=True, chunkName=function_name)

# Without Transform
emitters = cmds.ls(typ='pointEmitter')
solvers = cmds.ls(typ='nucleus')
instancers = cmds.ls(typ='instancer')

no_transforms = emitters + instancers + solvers + instancers
# Without Transform Types
no_transform_types = ['nucleus',
'pointEmitter',
'instancer']
# Fields/Solvers Types
if include_fields:
field_types = ['airField',
'dragField',
'newtonField',
'radialField',
'turbulenceField',
'uniformField',
'vortexField',
'volumeAxisField']
no_transform_types += field_types
no_transforms = []
for node_type in no_transform_types:
no_transforms += cmds.ls(typ=node_type) or []

# With Transform
nparticle_nodes = cmds.ls(typ='nParticle')
spring_nodes = cmds.ls(typ='spring')
particle_nodes = cmds.ls(typ='particle')
nrigid_nodes = cmds.ls(typ='nRigid')
ncloth_nodes = cmds.ls(typ='nCloth')
pfxhair_nodes = cmds.ls(typ='pfxHair')
hair_nodes = cmds.ls(typ='hairSystem')
nconstraint_nodes = cmds.ls(typ='dynamicConstraint')

transforms = nparticle_nodes + spring_nodes + particle_nodes + nrigid_nodes
transforms += ncloth_nodes + pfxhair_nodes + hair_nodes + nconstraint_nodes

# Fields/Solvers Types
# airField
# dragField
# newtonField
# radialField
# turbulenceField
# uniformField
# vortexField
# volumeAxisField

deleted_counter = 0
for obj in transforms:
with_transform_types = ['nParticle',
'spring',
'particle',
'nRigid',
'nCloth',
'pfxHair',
'hairSystem',
'dynamicConstraint']
with_transforms = []
for transform_node_type in with_transform_types:
with_transforms += cmds.ls(typ=transform_node_type) or []

for obj in with_transforms:
try:
parent = cmds.listRelatives(obj, parent=True) or []
cmds.delete(parent[0])
Expand All @@ -78,13 +93,13 @@ def delete_nucleus_nodes():
deleted_counter += 1
except Exception as e:
logger.debug(str(e))

feedback = FeedbackMessage(quantity=deleted_counter,
singular='object was',
plural='objects were',
conclusion='deleted.',
zero_overwrite_message='No nucleus nodes found in this scene.')
feedback.print_inview_message()
if verbose:
feedback = FeedbackMessage(quantity=deleted_counter,
singular='object was',
plural='objects were',
conclusion='deleted.',
zero_overwrite_message='No nucleus nodes found in this scene.')
feedback.print_inview_message()

except Exception as e:
errors += str(e) + '\n'
Expand All @@ -94,32 +109,50 @@ def delete_nucleus_nodes():
if errors != '':
print('######## Errors: ########')
print(errors)
return deleted_counter


def delete_all_locators():
""" Deletes all locators """
def delete_locators(verbose=True, filter_str=None):
"""
Deletes all locators
Args:
verbose (bool, optional): If True, it will print feedback when executing operation.
filter_str (str, optional): If provided, it will be used to filter locators.
Only locators containing this string will be deleted.
Returns:
int: Number of deleted locators
"""
errors = ''
function_name = 'Delete All Locators'
function_name = 'Delete Locators'
deleted_counter = 0
try:
cmds.undoInfo(openChunk=True, chunkName=function_name)

# With Transform
locators = cmds.ls(typ='locator')

deleted_counter = 0
for obj in locators:
filtered_locators = []
if filter_str and isinstance(filter_str, str):
for loc in locators:
if filter_str in loc:
filtered_locators.append(loc)
else:
filtered_locators = locators

for obj in filtered_locators:
try:
parent = cmds.listRelatives(obj, parent=True) or []
cmds.delete(parent[0])
loc_transform = cmds.listRelatives(obj, parent=True) or []
cmds.delete(loc_transform[0])
deleted_counter += 1
except Exception as e:
logger.debug(str(e))
feedback = FeedbackMessage(quantity=deleted_counter,
singular='locator was',
plural='locators were',
conclusion='deleted.',
zero_overwrite_message='No locators found in this scene.')
feedback.print_inview_message()
if verbose:
feedback = FeedbackMessage(quantity=deleted_counter,
singular='locator was',
plural='locators were',
conclusion='deleted.',
zero_overwrite_message='No locators found in this scene.')
feedback.print_inview_message()

except Exception as e:
errors += str(e) + '\n'
Expand All @@ -129,4 +162,8 @@ def delete_all_locators():
if errors != '':
print('######## Errors: ########')
print(errors)
return deleted_counter


if __name__ == "__main__":
logger.setLevel(logging.DEBUG)
34 changes: 17 additions & 17 deletions gt/utils/color_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ def __init__(self):
"""
Constant tuple RGB values used for element colors.
"""
CENTER = (1, 1, 0.65)
LEFT = (0, 0.5, 1)
RIGHT = (1, 0.5, 0.5)

Expand Down Expand Up @@ -61,16 +62,19 @@ def set_color_override_outliner(obj, rgb_color=(1, 1, 1)):


def add_side_color_setup(obj, color_attr_name="autoColor",
left_clr=ColorConstants.LEFT, right_clr=ColorConstants.RIGHT):
clr_default=ColorConstants.CENTER,
clr_left=ColorConstants.LEFT,
clr_right=ColorConstants.RIGHT):
"""
This function sets up a side color setup for the specified object in the Maya scene.
It creates connections and attributes to control the color of the object based on its position in the scene.
Parameters:
obj (str): The name of the object to set up the color for.
color_attr_name (str, optional): Name of the attribute used to determine if auto color is active or not.
left_clr (tuple, optional): The RGB color values for the left side of the object. Default is (0, 0.5, 1).
right_clr (tuple, optional): The RGB color values for the right side of the object. Default is (1, 0.5, 0.5).
clr_default (tuple, optional): The RGB color for when the object is in the center or not automatically defined.
clr_left (tuple, optional): The RGB color for when on the left side. e.g. (0, 0.5, 1).
clr_right (tuple, optional): The RGB color for when on the right side. e.g.(1, 0.5, 0.5).
Example:
# Example usage in Maya Python script editor:
Expand All @@ -80,7 +84,6 @@ def add_side_color_setup(obj, color_attr_name="autoColor",
return

# Setup Base Connections
default_clr = (1, 1, 0.65)
cmds.setAttr(obj + ".overrideEnabled", 1)
cmds.setAttr(obj + ".overrideRGBColors", 1)
clr_side_condition = cmds.createNode("condition", name=obj + "_clr_side_condition")
Expand All @@ -103,34 +106,31 @@ def add_side_color_setup(obj, color_attr_name="autoColor",
# Setup Color Attributes
clr_attr = "colorDefault"
add_attr_double_three(obj, clr_attr, keyable=False)
cmds.setAttr(f'{obj}.{clr_attr}R', default_clr[0])
cmds.setAttr(f'{obj}.{clr_attr}G', default_clr[1])
cmds.setAttr(f'{obj}.{clr_attr}B', default_clr[2])
cmds.setAttr(f'{obj}.{clr_attr}R', clr_default[0])
cmds.setAttr(f'{obj}.{clr_attr}G', clr_default[1])
cmds.setAttr(f'{obj}.{clr_attr}B', clr_default[2])
cmds.connectAttr(f'{obj}.{clr_attr}R', clr_center_condition + ".colorIfTrueR")
cmds.connectAttr(f'{obj}.{clr_attr}G', clr_center_condition + ".colorIfTrueG")
cmds.connectAttr(f'{obj}.{clr_attr}B', clr_center_condition + ".colorIfTrueB")
cmds.connectAttr(f'{obj}.{clr_attr}', clr_auto_blend + ".color2") # Blend node input
r_clr_attr = "colorRight"
add_attr_double_three(obj, r_clr_attr, keyable=False)
cmds.setAttr(obj + "." + r_clr_attr + "R", left_clr[0])
cmds.setAttr(obj + "." + r_clr_attr + "G", left_clr[1])
cmds.setAttr(obj + "." + r_clr_attr + "B", left_clr[2])
cmds.setAttr(obj + "." + r_clr_attr + "R", clr_left[0])
cmds.setAttr(obj + "." + r_clr_attr + "G", clr_left[1])
cmds.setAttr(obj + "." + r_clr_attr + "B", clr_left[2])
cmds.connectAttr(obj + "." + r_clr_attr + "R", clr_side_condition + ".colorIfTrueR")
cmds.connectAttr(obj + "." + r_clr_attr + "G", clr_side_condition + ".colorIfTrueG")
cmds.connectAttr(obj + "." + r_clr_attr + "B", clr_side_condition + ".colorIfTrueB")
l_clr_attr = "colorLeft"
add_attr_double_three(obj, l_clr_attr, keyable=False)
cmds.setAttr(obj + "." + l_clr_attr + "R", right_clr[0])
cmds.setAttr(obj + "." + l_clr_attr + "G", right_clr[1])
cmds.setAttr(obj + "." + l_clr_attr + "B", right_clr[2])
cmds.setAttr(obj + "." + l_clr_attr + "R", clr_right[0])
cmds.setAttr(obj + "." + l_clr_attr + "G", clr_right[1])
cmds.setAttr(obj + "." + l_clr_attr + "B", clr_right[2])
cmds.connectAttr(obj + "." + l_clr_attr + "R", clr_side_condition + ".colorIfFalseR")
cmds.connectAttr(obj + "." + l_clr_attr + "G", clr_side_condition + ".colorIfFalseG")
cmds.connectAttr(obj + "." + l_clr_attr + "B", clr_side_condition + ".colorIfFalseB")


if __name__ == "__main__":
logger.setLevel(logging.DEBUG)
from pprint import pprint
out = None
pprint(out)

add_side_color_setup("pSphere1")
3 changes: 2 additions & 1 deletion gt/utils/data/controls/cluster_driven.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def create_scalable_one_side_arrow(name='scalable_one_side_arrow', initial_scale


def create_scalable_two_sides_arrow(name='scalable_two_sides_arrow', initial_scale=1,
min_scale_apply=False, min_scale=0.01):
min_scale_apply=False, min_scale=0.01):
"""
Creates a curve in the shape of an arrow and rigs it so when scaling it up the curve doesn't lose its shape.
Instead, it scales only in the direction of the arrow heads. Use the "<name>_scaleCtrl" to determine the scale.
Expand Down Expand Up @@ -197,3 +197,4 @@ def create_scalable_two_sides_arrow(name='scalable_two_sides_arrow', initial_sca
logger.setLevel(logging.DEBUG)
cmds.file(new=True, force=True)
create_scalable_one_side_arrow()

Loading

0 comments on commit c98ac6d

Please sign in to comment.