Skip to content

Commit c98ac6d

Browse files
authored
Merge pull request #193 from TrevisanGMW/dev
release <- dev (3.2.1)
2 parents 11d7b6d + 07f75c5 commit c98ac6d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+3048
-873
lines changed

gt/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import sys
22

33
# Package Variables
4-
__version_tuple__ = (3, 2, 0)
4+
__version_tuple__ = (3, 2, 1)
55
__version_suffix__ = ''
66
__version__ = '.'.join(str(n) for n in __version_tuple__) + __version_suffix__
77
__authors__ = ['Guilherme Trevisan']

gt/utils/attr_utils.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -494,17 +494,19 @@ def get_multiple_attr(attribute_path=None, obj_list=None, attr_list=None, enum_a
494494
return attribute_values
495495

496496

497-
def get_trs_attr_as_list(obj):
497+
def get_trs_attr_as_list(obj, verbose=True):
498498
"""
499499
Gets Translate, Rotation and Scale values as a list
500500
Args:
501501
obj (str): Name of the source object
502+
verbose (bool, optional): If active, it will return a warning when the object is missing.
502503
Returns:
503504
list or None: A list with TRS values in order [TX, TY, TZ, RX, RY, RZ, SX, SY, SZ], None if missing object.
504505
e.g. [0, 0, 0, 15, 15, 15, 1, 1, 1]
505506
"""
506507
if not obj or not cmds.objExists(obj):
507-
logger.warning(f'Unable to get TRS channels as list. Unable to find object "{obj}".')
508+
if verbose:
509+
logger.warning(f'Unable to get TRS channels as list. Unable to find object "{obj}".')
508510
return
509511
output = []
510512
for channel in DEFAULT_CHANNELS: # TRS

gt/utils/cleanup_utils.py

Lines changed: 96 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -13,59 +13,74 @@
1313
logger.setLevel(logging.INFO)
1414

1515

16-
def delete_unused_nodes():
16+
def delete_unused_nodes(verbose=True):
1717
"""
1818
Deleted unused nodes (such as materials not connected to anything or nodes without any connections)
1919
This is done through a Maya MEL function "MLdeleteUnused()" but it's called here again for better feedback.
20+
Args:
21+
verbose (bool, optional): If True, it will print feedback with the number of unused deleted nodes.
22+
Returns:
23+
int: Number of unused deleted nodes.
2024
"""
2125
num_deleted_nodes = mel.eval('MLdeleteUnused();')
22-
feedback = FeedbackMessage(quantity=num_deleted_nodes,
23-
singular='unused node was',
24-
plural='unused nodes were',
25-
conclusion='deleted.',
26-
zero_overwrite_message='No unused nodes found in this scene.')
27-
feedback.print_inview_message()
26+
if verbose:
27+
feedback = FeedbackMessage(quantity=num_deleted_nodes,
28+
singular='unused node was',
29+
plural='unused nodes were',
30+
conclusion='deleted.',
31+
zero_overwrite_message='No unused nodes found in this scene.')
32+
feedback.print_inview_message()
33+
return num_deleted_nodes
2834

2935

30-
def delete_nucleus_nodes():
31-
""" Deletes all elements related to particles """
36+
def delete_nucleus_nodes(verbose=True, include_fields=True):
37+
"""
38+
Deletes all elements related to particles.
39+
Args:
40+
verbose (bool, optional): If True, it will print feedback with the number of deleted nodes.
41+
include_fields (bool, optional): If True, it will also count field as "nucleus nodes" to be deleted.
42+
Returns:
43+
int: Number of nucleus deleted nodes.
44+
"""
3245
errors = ''
3346
function_name = 'Delete Nucleus Nodes'
47+
deleted_counter = 0
3448
try:
3549
cmds.undoInfo(openChunk=True, chunkName=function_name)
3650

37-
# Without Transform
38-
emitters = cmds.ls(typ='pointEmitter')
39-
solvers = cmds.ls(typ='nucleus')
40-
instancers = cmds.ls(typ='instancer')
41-
42-
no_transforms = emitters + instancers + solvers + instancers
51+
# Without Transform Types
52+
no_transform_types = ['nucleus',
53+
'pointEmitter',
54+
'instancer']
55+
# Fields/Solvers Types
56+
if include_fields:
57+
field_types = ['airField',
58+
'dragField',
59+
'newtonField',
60+
'radialField',
61+
'turbulenceField',
62+
'uniformField',
63+
'vortexField',
64+
'volumeAxisField']
65+
no_transform_types += field_types
66+
no_transforms = []
67+
for node_type in no_transform_types:
68+
no_transforms += cmds.ls(typ=node_type) or []
4369

4470
# With Transform
45-
nparticle_nodes = cmds.ls(typ='nParticle')
46-
spring_nodes = cmds.ls(typ='spring')
47-
particle_nodes = cmds.ls(typ='particle')
48-
nrigid_nodes = cmds.ls(typ='nRigid')
49-
ncloth_nodes = cmds.ls(typ='nCloth')
50-
pfxhair_nodes = cmds.ls(typ='pfxHair')
51-
hair_nodes = cmds.ls(typ='hairSystem')
52-
nconstraint_nodes = cmds.ls(typ='dynamicConstraint')
53-
54-
transforms = nparticle_nodes + spring_nodes + particle_nodes + nrigid_nodes
55-
transforms += ncloth_nodes + pfxhair_nodes + hair_nodes + nconstraint_nodes
56-
57-
# Fields/Solvers Types
58-
# airField
59-
# dragField
60-
# newtonField
61-
# radialField
62-
# turbulenceField
63-
# uniformField
64-
# vortexField
65-
# volumeAxisField
66-
67-
deleted_counter = 0
68-
for obj in transforms:
71+
with_transform_types = ['nParticle',
72+
'spring',
73+
'particle',
74+
'nRigid',
75+
'nCloth',
76+
'pfxHair',
77+
'hairSystem',
78+
'dynamicConstraint']
79+
with_transforms = []
80+
for transform_node_type in with_transform_types:
81+
with_transforms += cmds.ls(typ=transform_node_type) or []
82+
83+
for obj in with_transforms:
6984
try:
7085
parent = cmds.listRelatives(obj, parent=True) or []
7186
cmds.delete(parent[0])
@@ -78,13 +93,13 @@ def delete_nucleus_nodes():
7893
deleted_counter += 1
7994
except Exception as e:
8095
logger.debug(str(e))
81-
82-
feedback = FeedbackMessage(quantity=deleted_counter,
83-
singular='object was',
84-
plural='objects were',
85-
conclusion='deleted.',
86-
zero_overwrite_message='No nucleus nodes found in this scene.')
87-
feedback.print_inview_message()
96+
if verbose:
97+
feedback = FeedbackMessage(quantity=deleted_counter,
98+
singular='object was',
99+
plural='objects were',
100+
conclusion='deleted.',
101+
zero_overwrite_message='No nucleus nodes found in this scene.')
102+
feedback.print_inview_message()
88103

89104
except Exception as e:
90105
errors += str(e) + '\n'
@@ -94,32 +109,50 @@ def delete_nucleus_nodes():
94109
if errors != '':
95110
print('######## Errors: ########')
96111
print(errors)
112+
return deleted_counter
97113

98114

99-
def delete_all_locators():
100-
""" Deletes all locators """
115+
def delete_locators(verbose=True, filter_str=None):
116+
"""
117+
Deletes all locators
118+
Args:
119+
verbose (bool, optional): If True, it will print feedback when executing operation.
120+
filter_str (str, optional): If provided, it will be used to filter locators.
121+
Only locators containing this string will be deleted.
122+
Returns:
123+
int: Number of deleted locators
124+
"""
101125
errors = ''
102-
function_name = 'Delete All Locators'
126+
function_name = 'Delete Locators'
127+
deleted_counter = 0
103128
try:
104129
cmds.undoInfo(openChunk=True, chunkName=function_name)
105130

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

109-
deleted_counter = 0
110-
for obj in locators:
134+
filtered_locators = []
135+
if filter_str and isinstance(filter_str, str):
136+
for loc in locators:
137+
if filter_str in loc:
138+
filtered_locators.append(loc)
139+
else:
140+
filtered_locators = locators
141+
142+
for obj in filtered_locators:
111143
try:
112-
parent = cmds.listRelatives(obj, parent=True) or []
113-
cmds.delete(parent[0])
144+
loc_transform = cmds.listRelatives(obj, parent=True) or []
145+
cmds.delete(loc_transform[0])
114146
deleted_counter += 1
115147
except Exception as e:
116148
logger.debug(str(e))
117-
feedback = FeedbackMessage(quantity=deleted_counter,
118-
singular='locator was',
119-
plural='locators were',
120-
conclusion='deleted.',
121-
zero_overwrite_message='No locators found in this scene.')
122-
feedback.print_inview_message()
149+
if verbose:
150+
feedback = FeedbackMessage(quantity=deleted_counter,
151+
singular='locator was',
152+
plural='locators were',
153+
conclusion='deleted.',
154+
zero_overwrite_message='No locators found in this scene.')
155+
feedback.print_inview_message()
123156

124157
except Exception as e:
125158
errors += str(e) + '\n'
@@ -129,4 +162,8 @@ def delete_all_locators():
129162
if errors != '':
130163
print('######## Errors: ########')
131164
print(errors)
165+
return deleted_counter
166+
132167

168+
if __name__ == "__main__":
169+
logger.setLevel(logging.DEBUG)

gt/utils/color_utils.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ def __init__(self):
1717
"""
1818
Constant tuple RGB values used for element colors.
1919
"""
20+
CENTER = (1, 1, 0.65)
2021
LEFT = (0, 0.5, 1)
2122
RIGHT = (1, 0.5, 0.5)
2223

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

6263

6364
def add_side_color_setup(obj, color_attr_name="autoColor",
64-
left_clr=ColorConstants.LEFT, right_clr=ColorConstants.RIGHT):
65+
clr_default=ColorConstants.CENTER,
66+
clr_left=ColorConstants.LEFT,
67+
clr_right=ColorConstants.RIGHT):
6568
"""
6669
This function sets up a side color setup for the specified object in the Maya scene.
6770
It creates connections and attributes to control the color of the object based on its position in the scene.
6871
6972
Parameters:
7073
obj (str): The name of the object to set up the color for.
7174
color_attr_name (str, optional): Name of the attribute used to determine if auto color is active or not.
72-
left_clr (tuple, optional): The RGB color values for the left side of the object. Default is (0, 0.5, 1).
73-
right_clr (tuple, optional): The RGB color values for the right side of the object. Default is (1, 0.5, 0.5).
75+
clr_default (tuple, optional): The RGB color for when the object is in the center or not automatically defined.
76+
clr_left (tuple, optional): The RGB color for when on the left side. e.g. (0, 0.5, 1).
77+
clr_right (tuple, optional): The RGB color for when on the right side. e.g.(1, 0.5, 0.5).
7478
7579
Example:
7680
# Example usage in Maya Python script editor:
@@ -80,7 +84,6 @@ def add_side_color_setup(obj, color_attr_name="autoColor",
8084
return
8185

8286
# Setup Base Connections
83-
default_clr = (1, 1, 0.65)
8487
cmds.setAttr(obj + ".overrideEnabled", 1)
8588
cmds.setAttr(obj + ".overrideRGBColors", 1)
8689
clr_side_condition = cmds.createNode("condition", name=obj + "_clr_side_condition")
@@ -103,34 +106,31 @@ def add_side_color_setup(obj, color_attr_name="autoColor",
103106
# Setup Color Attributes
104107
clr_attr = "colorDefault"
105108
add_attr_double_three(obj, clr_attr, keyable=False)
106-
cmds.setAttr(f'{obj}.{clr_attr}R', default_clr[0])
107-
cmds.setAttr(f'{obj}.{clr_attr}G', default_clr[1])
108-
cmds.setAttr(f'{obj}.{clr_attr}B', default_clr[2])
109+
cmds.setAttr(f'{obj}.{clr_attr}R', clr_default[0])
110+
cmds.setAttr(f'{obj}.{clr_attr}G', clr_default[1])
111+
cmds.setAttr(f'{obj}.{clr_attr}B', clr_default[2])
109112
cmds.connectAttr(f'{obj}.{clr_attr}R', clr_center_condition + ".colorIfTrueR")
110113
cmds.connectAttr(f'{obj}.{clr_attr}G', clr_center_condition + ".colorIfTrueG")
111114
cmds.connectAttr(f'{obj}.{clr_attr}B', clr_center_condition + ".colorIfTrueB")
112115
cmds.connectAttr(f'{obj}.{clr_attr}', clr_auto_blend + ".color2") # Blend node input
113116
r_clr_attr = "colorRight"
114117
add_attr_double_three(obj, r_clr_attr, keyable=False)
115-
cmds.setAttr(obj + "." + r_clr_attr + "R", left_clr[0])
116-
cmds.setAttr(obj + "." + r_clr_attr + "G", left_clr[1])
117-
cmds.setAttr(obj + "." + r_clr_attr + "B", left_clr[2])
118+
cmds.setAttr(obj + "." + r_clr_attr + "R", clr_left[0])
119+
cmds.setAttr(obj + "." + r_clr_attr + "G", clr_left[1])
120+
cmds.setAttr(obj + "." + r_clr_attr + "B", clr_left[2])
118121
cmds.connectAttr(obj + "." + r_clr_attr + "R", clr_side_condition + ".colorIfTrueR")
119122
cmds.connectAttr(obj + "." + r_clr_attr + "G", clr_side_condition + ".colorIfTrueG")
120123
cmds.connectAttr(obj + "." + r_clr_attr + "B", clr_side_condition + ".colorIfTrueB")
121124
l_clr_attr = "colorLeft"
122125
add_attr_double_three(obj, l_clr_attr, keyable=False)
123-
cmds.setAttr(obj + "." + l_clr_attr + "R", right_clr[0])
124-
cmds.setAttr(obj + "." + l_clr_attr + "G", right_clr[1])
125-
cmds.setAttr(obj + "." + l_clr_attr + "B", right_clr[2])
126+
cmds.setAttr(obj + "." + l_clr_attr + "R", clr_right[0])
127+
cmds.setAttr(obj + "." + l_clr_attr + "G", clr_right[1])
128+
cmds.setAttr(obj + "." + l_clr_attr + "B", clr_right[2])
126129
cmds.connectAttr(obj + "." + l_clr_attr + "R", clr_side_condition + ".colorIfFalseR")
127130
cmds.connectAttr(obj + "." + l_clr_attr + "G", clr_side_condition + ".colorIfFalseG")
128131
cmds.connectAttr(obj + "." + l_clr_attr + "B", clr_side_condition + ".colorIfFalseB")
129132

130133

131134
if __name__ == "__main__":
132135
logger.setLevel(logging.DEBUG)
133-
from pprint import pprint
134-
out = None
135-
pprint(out)
136-
136+
add_side_color_setup("pSphere1")

gt/utils/data/controls/cluster_driven.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ def create_scalable_one_side_arrow(name='scalable_one_side_arrow', initial_scale
105105

106106

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

0 commit comments

Comments
 (0)