做个备份,给以前的代码做了部分优化
from functools import partial
import maya.api.OpenMaya as om
import maya.cmds as cmds
class Utils(object):
@classmethod
def obj_exists(cls, lst):
'''
Check if a list of objects exists one by one.
return: True or False
'''
for i in lst:
if not cmds.objExists(i):
break
else:
return True
return False
@classmethod
def get_norm_vec(cls, obj, get_type='t'):
'''
Normalize a vector.
obj: Object to get the attribute from.
get_type: Specify the attribute to get from the object ('t', 'r', 's').
return: Normalized vector.
'''
vec = om.MVector(cmds.getAttr('{}.{}'.format(obj, get_type))[0])
vec.normalize()
return vec
@classmethod
def cond_switch(cls, lst, func):
'''
Evaluate multiple conditions and execute a dynamic function.
lst: List of conditions.
func: Function to be executed.
'''
for cond in lst:
if cmds.objExists(cond):
pass
else:
func()
@classmethod
def bake_obj(cls, obj, keys=True):
'''
Bake keyframes. The object needs to be constrained for this to work properly.
obj: Object to be baked, can be a list.
keys: Whether to bake every frame.
'''
start_key = cmds.playbackOptions(q=True, ast=True)
end_key = cmds.playbackOptions(q=True, aet=True)
if obj:
cmds.bakeResults(obj, t=(start_key, end_key), sr=[keys, 0],
sm=False, pok=False, sac=False, ral=False,
bol=False, mr=True, cp=False, s=True)
@classmethod
def set_attr(cls, nodes, attrs, value):
'''
Add attributes to nodes.
nodes: List of objects to add attributes to.
attrs: List of attributes to be added.
value: List of values to set for the attributes.
'''
for n in nodes:
for ids, i in enumerate(attrs):
if isinstance(value[ids], (list, tuple)):
cmds.setAttr('{}.{}'.format(n, i), *value[ids]) # 如果是向量就解包
else:
cmds.setAttr('{}.{}'.format(n, i), value[ids])
@classmethod
def lock_attr(cls, nodes, attrs, v=False):
'''
Lock attributes on nodes.
nodes: List of objects to lock attributes on.
attrs: List of attributes to be locked.
v: Value for lock and keyable properties.
'''
if isinstance(nodes and attrs, list):
if 't' in attrs:
attrs.remove('t')
attrs.extend(['tx', 'ty', 'tz'])
if 'r' in attrs:
attrs.remove('r')
attrs.extend(['rx', 'ry', 'rz'])
if 's' in attrs:
attrs.remove('s')
attrs.extend(['sx', 'sy', 'sz'])
for n in nodes:
for i in attrs:
cmds.setAttr('{}.{}'.format(n, i), l=False, k=False, cb=v)
@classmethod
def create_loc(cls, obj, prefix):
'''
Create a locator, get the object's rotate order, and hide a series of attributes.
obj: The object to get the name from.
prefix: The prefix to be added.
return: Locator object.
'''
ro = cmds.getAttr('{}.rotateOrder'.format(obj))
loc = cmds.spaceLocator(n='{}{}'.format(prefix, obj))
cmds.setAttr('{}.rotateOrder'.format(loc[0]), ro)
cls.lock_attr([loc[0]], ['v', 'lpx', 'lpy', 'lpz', 'lsx', 'lsy', 'lsz'], v=False)
return loc[0]
@classmethod
def scale_loc(cls, obj, value):
'''
Scale the locator.
obj: The locator object.
value: Scale value.
'''
try: # 没有形状节点pass
if cmds.nodeType(cmds.listRelatives(obj, s=True)[0]) == 'locator':
x = cmds.getAttr('{}.{}'.format(obj, 'lsx'))
Utils.set_attr([obj], ['lsx', 'lsy', 'lsz'], [x * value for i in range(3)])
else:
shapes = cmds.listRelatives(obj, s=True)
for i in shapes:
points = cmds.ls(i + '.cv[*]')[0]
# cmds.scale(*[value for i in range(3)], points, r=1, ocp=1)
cmds.scale(value, value, value, points, r=1, ocp=1)
except:
pass
class WorldSpaceLoc(object):
def __init__(self):
self.prefix = 'WSpace_loc_'
self.aim_grp_prefix = 'WSpace_loc_aim_grp_'
self.aim_prefix = 'WSpace_loc_aim_target_'
self.up_prefix = 'WSpace_loc_aim_up_'
self.parent_constr = '_parentConstraint'
self.point_constr = '_pointConstraint'
self.orient_constr = '_orientConstraint'
self.aim_constr = '_aimConstraint'
self.target_constr = 'target_aimConstraint'
self.up_constr = 'up_aimConstraint'
def bake_loc(self, every_frame):
'''
Bake the animation of the selected objects to locators.
every_frame: Whether to bake every frame.
'''
s_lst = cmds.ls(sl=True)
bake_lst = []
if s_lst:
for obj in s_lst:
if cmds.objExists('{}{}'.format(self.prefix, obj)):
cmds.delete('{}{}'.format(self.prefix, obj))
loc = Utils.create_loc(obj, self.prefix)
bake_lst.append(loc)
cmds.parentConstraint(obj, loc, w=1.0, mo=False)
Utils.bake_obj(bake_lst, every_frame)
cmds.delete(bake_lst, cn=True)
cmds.select(s_lst)
def parent_loc(self, offset):
'''
Parent the locators to the controllers using various constraint types.
offset: Preserve offset.
'''
s_lst = cmds.ls(sl=True)
if s_lst:
for obj in s_lst:
if cmds.objExists('{}{}'.format(self.prefix, obj)):
def constr_func():
cmds.parentConstraint('{}{}'.format(self.prefix, obj), obj, w=1.0, mo=offset,
n='{}{}{}'.format(self.prefix, obj, self.parent_constr))
if cmds.objExists('{}{}{}'.format(self.prefix, obj, self.parent_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.point_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.orient_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.aim_constr)):
pass
else:
constr_func()
def point_loc(self, offset):
'''
Point constrain the locators to the controllers using various constraint types.
offset: Preserve offset.
'''
s_lst = cmds.ls(sl=True)
if s_lst:
for obj in s_lst:
if cmds.objExists('{}{}'.format(self.prefix, obj)):
# Check constraint types
def constr_func():
cmds.pointConstraint('{}{}'.format(self.prefix, obj), obj, w=1.0, mo=offset,
n='{}{}{}'.format(self.prefix, obj, self.point_constr))
if cmds.objExists('{}{}{}'.format(self.prefix, obj, self.point_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.parent_constr)):
pass
else:
constr_func()
def orient_loc(self, offset):
'''
Orient constrain the locators to the controllers using various constraint types.
offset: Preserve offset.
'''
s_lst = cmds.ls(sl=True)
if s_lst:
for obj in s_lst:
if cmds.objExists('{}{}'.format(self.prefix, obj)):
# Check constraint types
def constr_func():
cmds.orientConstraint('{}{}'.format(self.prefix, obj), obj, w=1.0, mo=offset,
n='{}{}{}'.format(self.prefix, obj, self.orient_constr))
if cmds.objExists('{}{}{}'.format(self.prefix, obj, self.parent_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.orient_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.aim_constr)):
pass
else:
constr_func()
def select_loc(self):
'''
Select locators for the currently selected objects.
'''
s_lst = cmds.ls(sl=True)
prefix_lst = [self.aim_prefix, self.up_prefix, self.prefix]
loc_lst = []
if s_lst:
for obj in s_lst:
for n in prefix_lst:
if cmds.objExists('{}{}'.format(n, obj)):
loc_lst.append('{}{}'.format(n, obj))
cmds.select(loc_lst)
def delect_constr(self):
'''
Delete world space constraints on selected objects.
'''
s_lst = cmds.ls(sl=True)
constr_prefix_lst = [self.parent_constr, self.point_constr, self.orient_constr,
self.aim_constr]
if s_lst:
for obj in s_lst:
for n in constr_prefix_lst:
if cmds.objExists('{}{}{}'.format(self.prefix, obj, n)):
cmds.delete('{}{}{}'.format(self.prefix, obj, n), cn=True)
# Delete target constraints
if '{}{}{}'.format(self.prefix, obj, n) == '{}{}{}'.format(self.prefix, obj,
self.aim_constr):
cmds.delete('{}{}'.format(self.aim_prefix, obj),
'{}{}'.format(self.up_prefix, obj))
# Delete target constraint groups
if cmds.objExists('{}{}'.format(self.aim_grp_prefix, obj)):
cmds.delete('{}{}'.format(self.aim_grp_prefix, obj))
def bake_ctrl(self, every_frame):
'''
Bake the animation of the controllers and delete the constraints.
every_frame: Whether to bake every frame.
'''
s_lst = cmds.ls(sl=True)
bake_lst = []
constr_lst = []
# Target constraint components
aim_lst = []
# Constraint suffixes
constr_prefix_lst = [self.parent_constr, self.point_constr, self.orient_constr,
self.aim_constr]
if s_lst:
for obj in s_lst:
# Loop through constraint list
for n in constr_prefix_lst:
# If the constraint exists
if cmds.objExists('{}{}{}'.format(self.prefix, obj, n)):
bake_lst.append(obj)
constr_lst.append('{}{}{}'.format(self.prefix, obj, n))
# If it's the aim constraint, handle the two locators separately
if '{}{}{}'.format(self.prefix, obj, n) == '{}{}{}'.format(self.prefix, obj,
self.aim_constr):
aim_lst.extend(['{}{}'.format(self.aim_prefix, obj),
'{}{}'.format(self.up_prefix, obj)])
Utils.bake_obj(bake_lst, keys=every_frame)
cmds.delete(constr_lst, cn=True)
# Clean up aim constraint locators
if aim_lst:
cmds.delete(aim_lst)
def scale_loc_add(self, num):
'''
Scale the locators by a given value.
'''
s_lst = cmds.ls(sl=True)
if s_lst:
for obj in s_lst:
Utils.scale_loc(obj, num)
# def scale_loc_sub(self):
# s_lst = cmds.ls(sl=True)
# if s_lst:
# for obj in s_lst:
# Utils.scale_loc(obj, num)
def aim_loc(self):
'''
Create aim constraint locators.
'''
s_lst = cmds.ls(sl=True)
if s_lst:
for obj in s_lst:
if cmds.objExists('{}{}'.format(self.aim_grp_prefix, obj)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.parent_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.aim_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.orient_constr)):
pass
else:
aim_loc = Utils.create_loc(obj, self.aim_prefix)
up_loc = Utils.create_loc(obj, self.up_prefix)
grp = cmds.group(aim_loc, up_loc, n='{}{}'.format(self.aim_grp_prefix, obj))
cmds.parentConstraint(obj, grp, w=1.0, mo=False,
n='{}{}{}'.format(self.prefix, obj, self.parent_constr))
cmds.select(aim_loc)
def bake_aim(self, every_frame):
'''
Bake aim constraint locators and apply aim constraints.
every_frame: Whether to bake every frame.
'''
s_lst = cmds.ls(sl=True)
normal_lst = []
bake_lst = []
if s_lst:
for obj in s_lst:
if Utils.obj_exists(['{}{}'.format(self.aim_grp_prefix, obj), '{}{}'.format(self.aim_prefix, obj),
'{}{}'.format(self.up_prefix, obj)]):
# Get the normalized vectors of the locators
normal_lst.append(Utils.get_norm_vec('{}{}'.format(self.aim_prefix, obj)))
normal_lst.append(Utils.get_norm_vec('{}{}'.format(self.up_prefix, obj)))
# Unparent the constraints
cmds.parent('{}{}'.format(self.aim_prefix, obj),
'{}{}'.format(self.up_prefix, obj), w=True)
cmds.delete('{}{}'.format(self.aim_grp_prefix, obj))
cmds.parentConstraint(obj, '{}{}'.format(self.aim_prefix, obj), w=1.0, mo=True,
n='{}{}{}'.format(self.prefix, obj, self.target_constr))
cmds.parentConstraint(obj, '{}{}'.format(self.up_prefix, obj), w=1.0, mo=True,
n='{}{}{}'.format(self.prefix, obj, self.up_constr))
bake_lst.extend(['{}{}'.format(self.aim_prefix, obj),
'{}{}'.format(self.up_prefix, obj)])
Utils.bake_obj(bake_lst, every_frame)
cmds.delete('{}{}'.format(self.aim_prefix, obj), '{}{}'.format(self.up_prefix, obj), cn=True)
cmds.aimConstraint('{}{}'.format(self.aim_prefix, obj), obj, aim=normal_lst[0], u=normal_lst[1],
mo=False, w=1.0, wut='object', wuo='{}{}'.format(self.up_prefix, obj),
n='{}{}{}'.format(self.prefix, obj, self.aim_constr))
normal_lst = []
cmds.select(s_lst)
def set_color(self, colorid):
'''
Batch set controller color.
colorid: Color ID.
'''
s_lst = cmds.ls(sl=True)
shape = cmds.listRelatives(s_lst, c=True)
for obj in s_lst:
if cmds.nodeType(obj) == 'joint':
Utils.set_attr([obj], ['overrideEnabled', 'overrideColor'], [1, colorid])
continue
for s in shape:
if cmds.objectType(s, isa='shape'):
Utils.set_attr([s], ['overrideEnabled', 'overrideColor'], [1, colorid])
class WorldSpaceLocUi(object):
def __init__(self):
self.__name = 'World_Space_Locator'
self.windows()
self.layout()
self.button()
def windows(self):
if cmds.window(self.__name, exists=1):
cmds.deleteUI(self.__name)
self.window = cmds.window(self.__name, rtf=1, w=280, h=280, t=self.__name, s=1)
cmds.showWindow(self.__name)
def layout(self):
self.ly1 = cmds.columnLayout(rs=5, adj=1, p=self.window)
self.ly2 = cmds.rowColumnLayout(nc=2, adj=1, p=self.ly1)
self.ly3 = cmds.rowColumnLayout(nc=1, adj=1, p=self.ly1)
self.ly4 = cmds.rowColumnLayout(nc=1, adj=1, p=self.ly1)
self.button_test1()
self.ly5 = cmds.rowColumnLayout(nc=2, adj=2, p=self.ly4)
self.ly6 = cmds.rowColumnLayout(nc=1, adj=1, p=self.ly1)
self.button_test2()
self.ly7 = cmds.frameLayout(l='Color Picker', cll=True, cl=True, p=self.ly6)
self.ly8 = cmds.rowColumnLayout(nc=9, adj=5, p=self.ly7)
self.ly9 = cmds.rowColumnLayout(nc=2, adj=2, p=self.ly6)
self.ly10 = cmds.rowColumnLayout(nc=1, adj=1, p=self.ly1)
# To arrange the button order correctly, you need to define a method.
def button_test1(self):
cmds.button(l='Parent Locator', h=40, c=self.parent_loc, p=self.ly4, ann='Add parent-child constraint')
cmds.button(l='Point Locator', h=25, c=self.point_loc, p=self.ly4, ann='Add point constraint')
cmds.button(l='Orient Locator', h=25, c=self.orient_loc, p=self.ly4, ann='Add orient constraint')
# Same as above
def button_test2(self):
cmds.button(l='Delete Constraint', h=40, c=self.delect_constr, p=self.ly6, ann='Delete constraints')
cmds.button(l='Select Locators', h=50, c=self.select_loc, p=self.ly6, ann='Select associated locators')
def button(self):
self.every_frames_bool = cmds.checkBox(l='Smart Bake', v=False, p=self.ly2, ann='Whether to bake every frame')
self.offset_con = cmds.checkBox(l='Maintain Offset', v=False, p=self.ly2, ann='Whether to maintain offset in constraints')
cmds.button(l='Bake Locators', h=40, c=self.bake_loc, p=self.ly3, ann='Bake selected objects animation to locators')
cmds.button(l='Aim Locator', w=115, h=25, c=self.aim_loc, p=self.ly5, ann='Create aim constraint locators')
cmds.button(l='Bake Aim', w=115, h=25, c=self.bake_aim, p=self.ly5, ann='Bake aim constraint locators and apply aim constraints')
color_lis = [(1.0, 0.0, 0.0), (1.0, 0.5, 0.0), (1.0, 1.0, 0.0),
(0.0, 1.0, 0.0), (0.0, 1.0, 1.0), (0.0, 0.0, 1.0),
(1.0, 0.5, 0.5), (0.75, 0.75, 0.75), (1.0, 1.0, 1.0)]
null_id = []
for idd, i in enumerate(range(1, 10)):
id = cmds.button(l='ID' + str(idd + 1), w=26, h=20, bgc=color_lis[idd], p=self.ly8)
null_id.append(id)
color_index = [13, 24, 17, 14, 18, 6, 20, 3, 16]
for idd, i in enumerate(range(1, 10)):
id = cmds.button(null_id[idd], edit=True, c=partial(self.set_color, color_index[idd]), p=self.ly8,
ann='Set color')
cmds.button(l='locator + ', w=115, h=35, c=self.scale_loc_add, p=self.ly9, ann='Scale locator')
cmds.button(l='locator - ', w=115, h=35, c=self.scale_loc_sub, p=self.ly9, ann='Scale locator')
cmds.button(l='Bake Controls', h=40, c=self.bake_ctrl, p=self.ly10, ann='Bake controller animation')
cmds.text(label='World - Space - Locator - v1.5', w=40, h=13, p=self.ly10)
def bake_loc(self, *args):
keys = not cmds.checkBox(self.every_frames_bool, q=True, value=True)
WorldSpaceLoc().bake_loc(every_frame=keys)
def parent_loc(self, *args):
keys = cmds.checkBox(self.offset_con, q=True, value=True)
WorldSpaceLoc().parent_loc(offset=keys)
def point_loc(self, *args):
keys = cmds.checkBox(self.offset_con, q=True, value=True)
WorldSpaceLoc().point_loc(offset=keys)
def orient_loc(self, *args):
keys = cmds.checkBox(self.offset_con, q=True, value=True)
WorldSpaceLoc().orient_loc(offset=keys)
def aim_loc(self, *args):
WorldSpaceLoc().aim_loc()
def bake_aim(self, *args):
keys = not cmds.checkBox(self.every_frames_bool, q=True, value=True)
WorldSpaceLoc().bake_aim(every_frame=keys)
def delect_constr(self, *args):
WorldSpaceLoc().delect_constr()
def select_loc(self, *args):
WorldSpaceLoc().select_loc()
def scale_loc_add(self, *args):
WorldSpaceLoc().scale_loc_add(1.3)
def scale_loc_sub(self, *args):
WorldSpaceLoc().scale_loc_add(0.8)
def bake_ctrl(self, *args):
keys = not cmds.checkBox(self.every_frames_bool, q=True, value=True)
WorldSpaceLoc().bake_ctrl(every_frame=keys)
def set_color(self, colorid, *args):
WorldSpaceLoc().set_color(colorid)
if __name__ == '__main__':
WorldSpaceLocUi()
Pyside2 ui版本
from maya import cmds
from PySide2 import QtWidgets
from PySide2 import QtCore
from PySide2 import QtGui
from functools import partial
from maya.api import OpenMaya as om
class Utils(object):
@classmethod
def add_undo(cls, func):
def undo(*args, **kwargs):
cmds.undoInfo(openChunk=True)
func(*args, **kwargs)
cmds.undoInfo(closeChunk=True)
return undo
@classmethod
def mayaWindow(cls):
from maya.OpenMayaUI import MQtUtil
from shiboken2 import wrapInstance
return wrapInstance(int(MQtUtil.mainWindow()), QtWidgets.QMainWindow)
@classmethod
def obj_exists(cls, lst):
'''
Check if a list of objects exists one by one.
return: True or False
'''
for i in lst:
if not cmds.objExists(i):
break
else:
return True
return False
@classmethod
def get_norm_vec(cls, obj, get_type='t'):
'''
Normalize a vector.
obj: Object to get the attribute from.
get_type: Specify the attribute to get from the object ('t', 'r', 's').
return: Normalized vector.
'''
vec = om.MVector(cmds.getAttr('{}.{}'.format(obj, get_type))[0])
vec.normalize()
return vec
@classmethod
def cond_switch(cls, lst, func):
'''
Evaluate multiple conditions and execute a dynamic function.
lst: List of conditions.
func: Function to be executed.
'''
for cond in lst:
if cmds.objExists(cond):
pass
else:
func()
@classmethod
def bake_obj(cls, obj, keys=True):
'''
Bake keyframes. The object needs to be constrained for this to work properly.
obj: Object to be baked, can be a list.
keys: Whether to bake every frame.
'''
start_key = cmds.playbackOptions(q=True, ast=True)
end_key = cmds.playbackOptions(q=True, aet=True)
if obj:
cmds.bakeResults(obj, t=(start_key, end_key), sr=[keys, 0],
sm=False, pok=False, sac=False, ral=False,
bol=False, mr=True, cp=False, s=True)
@classmethod
def set_attr(cls, nodes, attrs, value):
'''
Add attributes to nodes.
nodes: List of objects to add attributes to.
attrs: List of attributes to be added.
value: List of values to set for the attributes.
'''
for n in nodes:
for ids, i in enumerate(attrs):
if isinstance(value[ids], (list, tuple)):
cmds.setAttr('{}.{}'.format(n, i), *value[ids])
else:
cmds.setAttr('{}.{}'.format(n, i), value[ids])
@classmethod
def lock_attr(cls, nodes, attrs, v=False):
'''
Lock attributes on nodes.
nodes: List of objects to lock attributes on.
attrs: List of attributes to be locked.
v: Value for lock and keyable properties.
'''
if isinstance(nodes and attrs, list):
if 't' in attrs:
attrs.remove('t')
attrs.extend(['tx', 'ty', 'tz'])
if 'r' in attrs:
attrs.remove('r')
attrs.extend(['rx', 'ry', 'rz'])
if 's' in attrs:
attrs.remove('s')
attrs.extend(['sx', 'sy', 'sz'])
for n in nodes:
for i in attrs:
cmds.setAttr('{}.{}'.format(n, i), l=False, k=False, cb=v)
@classmethod
def create_loc(cls, obj, prefix):
'''
Create a locator, get the object's rotate order, and hide a series of attributes.
obj: The object to get the name from.
prefix: The prefix to be added.
return: Locator object.
'''
ro = cmds.getAttr('{}.rotateOrder'.format(obj))
loc = cmds.spaceLocator(n='{}{}'.format(prefix, obj))
cmds.setAttr('{}.rotateOrder'.format(loc[0]), ro)
cls.lock_attr([loc[0]], ['v', 'lpx', 'lpy', 'lpz', 'lsx', 'lsy', 'lsz'], v=False)
return loc[0]
@classmethod
def scale_loc(cls, obj, value):
'''
Scale the locator.
obj: The locator object.
value: Scale value.
'''
try:
if cmds.nodeType(cmds.listRelatives(obj, s=True)[0]) == 'locator':
x = cmds.getAttr('{}.{}'.format(obj, 'lsx'))
Utils.set_attr([obj], ['lsx', 'lsy', 'lsz'], [x * value for i in range(3)])
else:
shapes = cmds.listRelatives(obj, s=True)
for i in shapes:
points = cmds.ls(i + '.cv[*]')[0]
# cmds.scale(*[value for i in range(3)], points, r=1, ocp=1)
cmds.scale(value, value, value, points, r=1, ocp=1)
except:
pass
class WorldSpaceLoc(object):
def __init__(self):
self.prefix = 'WSpace_loc_'
self.aim_grp_prefix = 'WSpace_loc_aim_grp_'
self.aim_prefix = 'WSpace_loc_aim_target_'
self.up_prefix = 'WSpace_loc_aim_up_'
self.parent_constr = '_parentConstraint'
self.point_constr = '_pointConstraint'
self.orient_constr = '_orientConstraint'
self.aim_constr = '_aimConstraint'
self.target_constr = 'target_aimConstraint'
self.up_constr = 'up_aimConstraint'
def bake_loc(self, every_frame):
'''
Bake the animation of the selected objects to locators.
every_frame: Whether to bake every frame.
'''
s_lst = cmds.ls(sl=True)
bake_lst = []
if s_lst:
for obj in s_lst:
if cmds.objExists('{}{}'.format(self.prefix, obj)):
cmds.delete('{}{}'.format(self.prefix, obj))
loc = Utils.create_loc(obj, self.prefix)
bake_lst.append(loc)
cmds.parentConstraint(obj, loc, w=1.0, mo=False)
Utils.bake_obj(bake_lst, every_frame)
cmds.delete(bake_lst, cn=True)
cmds.select(s_lst)
def parent_loc(self, offset):
'''
Parent the locators to the controllers using various constraint types.
offset: Preserve offset.
'''
s_lst = cmds.ls(sl=True)
if s_lst:
for obj in s_lst:
if cmds.objExists('{}{}'.format(self.prefix, obj)):
def constr_func():
cmds.parentConstraint('{}{}'.format(self.prefix, obj), obj, w=1.0, mo=offset,
n='{}{}{}'.format(self.prefix, obj, self.parent_constr))
if cmds.objExists('{}{}{}'.format(self.prefix, obj, self.parent_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.point_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.orient_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.aim_constr)):
pass
else:
constr_func()
def point_loc(self, offset):
'''
Point constrain the locators to the controllers using various constraint types.
offset: Preserve offset.
'''
s_lst = cmds.ls(sl=True)
if s_lst:
for obj in s_lst:
if cmds.objExists('{}{}'.format(self.prefix, obj)):
# Check constraint types
def constr_func():
cmds.pointConstraint('{}{}'.format(self.prefix, obj), obj, w=1.0, mo=offset,
n='{}{}{}'.format(self.prefix, obj, self.point_constr))
if cmds.objExists('{}{}{}'.format(self.prefix, obj, self.point_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.parent_constr)):
pass
else:
constr_func()
def orient_loc(self, offset):
'''
Orient constrain the locators to the controllers using various constraint types.
offset: Preserve offset.
'''
s_lst = cmds.ls(sl=True)
if s_lst:
for obj in s_lst:
if cmds.objExists('{}{}'.format(self.prefix, obj)):
# Check constraint types
def constr_func():
cmds.orientConstraint('{}{}'.format(self.prefix, obj), obj, w=1.0, mo=offset,
n='{}{}{}'.format(self.prefix, obj, self.orient_constr))
if cmds.objExists('{}{}{}'.format(self.prefix, obj, self.parent_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.orient_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.aim_constr)):
pass
else:
constr_func()
def select_loc(self):
'''
Select locators for the currently selected objects.
'''
s_lst = cmds.ls(sl=True)
prefix_lst = [self.aim_prefix, self.up_prefix, self.prefix]
loc_lst = []
if s_lst:
for obj in s_lst:
for n in prefix_lst:
if cmds.objExists('{}{}'.format(n, obj)):
loc_lst.append('{}{}'.format(n, obj))
cmds.select(loc_lst)
def delete_constr(self):
'''
Delete world space constraints on selected objects.
'''
s_lst = cmds.ls(sl=True)
constr_prefix_lst = [self.parent_constr, self.point_constr, self.orient_constr,
self.aim_constr]
if s_lst:
for obj in s_lst:
for n in constr_prefix_lst:
if cmds.objExists('{}{}{}'.format(self.prefix, obj, n)):
cmds.delete('{}{}{}'.format(self.prefix, obj, n), cn=True)
# Delete target constraints
if '{}{}{}'.format(self.prefix, obj, n) == '{}{}{}'.format(self.prefix, obj,
self.aim_constr):
cmds.delete('{}{}'.format(self.aim_prefix, obj),
'{}{}'.format(self.up_prefix, obj))
# Delete target constraint groups
if cmds.objExists('{}{}'.format(self.aim_grp_prefix, obj)):
cmds.delete('{}{}'.format(self.aim_grp_prefix, obj))
def bake_ctrl(self, every_frame):
'''
Bake the animation of the controllers and delete the constraints.
every_frame: Whether to bake every frame.
'''
s_lst = cmds.ls(sl=True)
bake_lst = []
constr_lst = []
# Target constraint components
aim_lst = []
# Constraint suffixes
constr_prefix_lst = [self.parent_constr, self.point_constr, self.orient_constr,
self.aim_constr]
if s_lst:
for obj in s_lst:
# Loop through constraint list
for n in constr_prefix_lst:
# If the constraint exists
if cmds.objExists('{}{}{}'.format(self.prefix, obj, n)):
bake_lst.append(obj)
constr_lst.append('{}{}{}'.format(self.prefix, obj, n))
# If it's the aim constraint, handle the two locators separately
if '{}{}{}'.format(self.prefix, obj, n) == '{}{}{}'.format(self.prefix, obj,
self.aim_constr):
aim_lst.extend(['{}{}'.format(self.aim_prefix, obj),
'{}{}'.format(self.up_prefix, obj)])
Utils.bake_obj(bake_lst, keys=every_frame)
cmds.delete(constr_lst, cn=True)
# Clean up aim constraint locators
if aim_lst:
cmds.delete(aim_lst)
def scale_loc_add(self, num):
'''
Scale the locators by a given value.
'''
s_lst = cmds.ls(sl=True)
if s_lst:
for obj in s_lst:
Utils.scale_loc(obj, num)
def aim_loc(self):
'''
Create aim constraint locators.
'''
s_lst = cmds.ls(sl=True)
if s_lst:
for obj in s_lst:
if cmds.objExists('{}{}'.format(self.aim_grp_prefix, obj)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.parent_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.aim_constr)):
pass
elif cmds.objExists('{}{}{}'.format(self.prefix, obj, self.orient_constr)):
pass
else:
aim_loc = Utils.create_loc(obj, self.aim_prefix)
up_loc = Utils.create_loc(obj, self.up_prefix)
grp = cmds.group(aim_loc, up_loc, n='{}{}'.format(self.aim_grp_prefix, obj))
cmds.parentConstraint(obj, grp, w=1.0, mo=False,
n='{}{}{}'.format(self.prefix, obj, self.parent_constr))
cmds.select(aim_loc)
def bake_aim(self, every_frame):
'''
Bake aim constraint locators and apply aim constraints.
every_frame: Whether to bake every frame.
'''
s_lst = cmds.ls(sl=True)
normal_lst = []
bake_lst = []
if s_lst:
for obj in s_lst:
if Utils.obj_exists(['{}{}'.format(self.aim_grp_prefix, obj), '{}{}'.format(self.aim_prefix, obj),
'{}{}'.format(self.up_prefix, obj)]):
# Get the normalized vectors of the locators
normal_lst.append(Utils.get_norm_vec('{}{}'.format(self.aim_prefix, obj)))
normal_lst.append(Utils.get_norm_vec('{}{}'.format(self.up_prefix, obj)))
# Unparent the constraints
cmds.parent('{}{}'.format(self.aim_prefix, obj),
'{}{}'.format(self.up_prefix, obj), w=True)
cmds.delete('{}{}'.format(self.aim_grp_prefix, obj))
cmds.parentConstraint(obj, '{}{}'.format(self.aim_prefix, obj), w=1.0, mo=True,
n='{}{}{}'.format(self.prefix, obj, self.target_constr))
cmds.parentConstraint(obj, '{}{}'.format(self.up_prefix, obj), w=1.0, mo=True,
n='{}{}{}'.format(self.prefix, obj, self.up_constr))
bake_lst.extend(['{}{}'.format(self.aim_prefix, obj),
'{}{}'.format(self.up_prefix, obj)])
Utils.bake_obj(bake_lst, every_frame)
cmds.delete('{}{}'.format(self.aim_prefix, obj), '{}{}'.format(self.up_prefix, obj), cn=True)
cmds.aimConstraint('{}{}'.format(self.aim_prefix, obj), obj, aim=normal_lst[0], u=normal_lst[1],
mo=False, w=1.0, wut='object', wuo='{}{}'.format(self.up_prefix, obj),
n='{}{}{}'.format(self.prefix, obj, self.aim_constr))
normal_lst = []
cmds.select(s_lst)
def set_color(self, colorid):
'''
Batch set controller color.
colorid: Color ID.
'''
s_lst = cmds.ls(sl=True)
shape = cmds.listRelatives(s_lst, c=True)
for obj in s_lst:
if cmds.nodeType(obj) == 'joint':
Utils.set_attr([obj], ['overrideEnabled', 'overrideColor'], [1, colorid])
continue
for s in shape:
if cmds.objectType(s, isa='shape'):
Utils.set_attr([s], ['overrideEnabled', 'overrideColor'], [1, colorid])
class Window(QtWidgets.QDialog):
SLIDER_BASIC_VALUE = 50
def __init__(self, parent):
super(Window, self).__init__(parent)
self.setWindowTitle('World Space Locator')
self.main_layout = QtWidgets.QVBoxLayout()
#self.setWindowFlags(self.windowFlags() ^ QtCore.Qt.WindowContextHelpButtonHint)
self.main_layout.addLayout(self.check_box())
self.main_layout.addLayout(self.bake_layout())
self.main_layout.addLayout(self.loc_layout())
self.main_layout.setSpacing(5)
self.main_layout.addStretch()
self.main_layout.setContentsMargins(4, 5, 4, 5)
self.setLayout(self.main_layout)
def check_box(self):
T_CheckBox = """
QCheckBox {
color: #FFFFFF;
}
QCheckBox:hover {
color: #FFFF88;
}
QCheckBox:checked {
color: #FFFF88;
}
"""
self.Bake_check = QtWidgets.QCheckBox('Bake Every Frame ')
self.Bake_check.setStyleSheet(T_CheckBox)
self.Offset_check = QtWidgets.QCheckBox('Maintain Offset ')
#self.Offset_check.setLayoutDirection(QtCore.Qt.RightToLeft)
self.Offset_check.setStyleSheet(T_CheckBox)
self.check_ly = QtWidgets.QHBoxLayout()
self.check_ly.addWidget(self.Bake_check)
self.check_ly.addStretch()
self.check_ly.addWidget(self.Offset_check)
return self.check_ly
########################## bake ly #################################
def bake_layout(self):
self.baake_ly = QtWidgets.QVBoxLayout()
self.baake_ly.setSpacing(1)
self.baake_ly.addLayout(self.bake_button())
self.baake_ly.addLayout(self.aim_button())
return self.baake_ly
def bake_button(self):
button_names = ['Bake Locators', 'Parent Locator',
'Point Locator', 'Orient Locator']
self.button_objs = [QtWidgets.QPushButton(name) for name in button_names]
self.button_objs[0].setMinimumSize(0, 55)
self.button_objs[1].setMinimumSize(0, 50)
self.button_objs[0].clicked.connect(self.bake_loc)
self.button_objs[1].clicked.connect(self.parent_loc)
self.button_objs[2].clicked.connect(self.point_loc)
self.button_objs[3].clicked.connect(self.orient_loc)
self.bake_button_ly = QtWidgets.QVBoxLayout()
#self.bake_button_ly.setSpacing(2)
for ids, button in enumerate(self.button_objs):
self.bake_button_ly.addWidget(button)
if ids in [0, 1]:
button.setStyleSheet("color: rgb(255, 255, 136);")
return self.bake_button_ly
def aim_button(self):
self.add_aim_loc = QtWidgets.QPushButton('Aim Locator')
self.bake_aim = QtWidgets.QPushButton('Bake Aim')
self.add_aim_loc.clicked.connect(self.aim_loc)
self.bake_aim.clicked.connect(self.bake_aim_loc)
self.aim_ly = QtWidgets.QHBoxLayout()
self.aim_ly.addWidget(self.add_aim_loc)
self.aim_ly.addWidget(self.bake_aim)
return self.aim_ly
########################## bake ly #################################
def loc_layout(self):
self.loc_ly = QtWidgets.QVBoxLayout()
self.loc_ly.setSpacing(1)
self.loc_ly.addLayout(self.loc_button())
self.loc_ly.addLayout(self.loc_attr())
self.loc_ly.addLayout(self.bake_con())
return self.loc_ly
def loc_button(self):
self.del_button = QtWidgets.QPushButton('Del Constraint')
self.del_button.setMinimumSize(0, 50)
self.sl_loc = QtWidgets.QPushButton('Select Locators')
self.sl_loc.setMinimumSize(0, 50)
self.del_button.clicked.connect(self.delete_constr)
self.sl_loc.clicked.connect(self.select_loc)
self.v_ly = QtWidgets.QVBoxLayout()
self.v_ly.addWidget(self.del_button)
self.v_ly.addWidget(self.sl_loc)
return self.v_ly
def loc_attr(self):
style_sheet = """
QSlider::groove:horizontal { /* 滑块进度 */
border: none;
height: 5px; /* 滑块高度 */
background-color: #1C1C1C; /* 滑块背景色 */
}
QSlider::handle:horizontal { /* 滑块手柄 */
background-color: #FFFFFF; /* 滑块手柄颜色 */
width: 10px; /* 滑块手柄宽度度 */
margin: -5px 0px -5px 0px; /* 滑块手柄高度度 */
border-radius: 2px;
}
QSlider::sub-page:horizontal { /* 滑块进度外层颜色 */
background-color: #8289D9;
}
"""
self.loc_attr_h_ly = QtWidgets.QHBoxLayout()
self.loc_scale_text = QtWidgets.QLabel(' Loc Scale ')
self.loc_scale_slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
self.loc_scale_slider.setStyleSheet(style_sheet)
self.loc_scale_slider.setRange(0, 100)
self.loc_scale_slider.setValue(50)
self.loc_scale_slider.sliderPressed.connect(lambda: cmds.undoInfo(openChunk=True))
self.loc_scale_slider.sliderMoved.connect(self.scale_loc_addaa)
self.loc_scale_slider.sliderReleased.connect(lambda: (self.loc_scale_slider.setValue(50),
cmds.undoInfo(closeChunk=True)))
self.loc_scale_slider.sliderReleased.connect(self.resete_slider_basic_value)
self.loc_attr_h_ly.addWidget(self.loc_scale_text)
self.loc_attr_h_ly.addWidget(self.loc_scale_slider)
return self.loc_attr_h_ly
def bake_con(self):
self.bake_button = QtWidgets.QPushButton('Bake Controls')
self.bake_button.setStyleSheet("color: rgb(255, 255, 136);")
self.bake_button.setMinimumSize(0, 60)
self.bake_button.clicked.connect(self.bake_ctrl)
self.bake_con_v_ly = QtWidgets.QVBoxLayout()
self.bake_con_v_ly.addWidget(self.bake_button)
return self.bake_con_v_ly
############# set func ####################
@Utils.add_undo
def bake_loc(self):
bl = not bool(self.Bake_check.checkState())
wsl.bake_loc(every_frame=bl)
@Utils.add_undo
def parent_loc(self):
bl = bool(self.Offset_check.checkState())
wsl.parent_loc(offset=bl)
@Utils.add_undo
def point_loc(self):
bl = bool(self.Offset_check.checkState())
wsl.point_loc(offset=bl)
@Utils.add_undo
def orient_loc(self):
bl = bool(self.Offset_check.checkState())
wsl.orient_loc(offset=bl)
@Utils.add_undo
def aim_loc(self):
wsl.aim_loc()
@Utils.add_undo
def bake_aim_loc(self):
bl = not bool(self.Bake_check.checkState())
wsl.bake_aim(every_frame=bl)
@Utils.add_undo
def delete_constr(self):
wsl.delete_constr()
@Utils.add_undo
def select_loc(self):
wsl.select_loc()
def resete_slider_basic_value(self):
SLIDER_BASIC_VALUE = 50
def scale_loc_addaa(self):
slider_value = self.loc_scale_slider.value()
if slider_value > Window.SLIDER_BASIC_VALUE:
wsl.scale_loc_add(num=1.05)
elif slider_value < Window.SLIDER_BASIC_VALUE:
wsl.scale_loc_add(num=1 / 1.05)
Window.SLIDER_BASIC_VALUE = slider_value
@Utils.add_undo
def bake_ctrl(self):
bl = not bool(self.Bake_check.checkState())
wsl.bake_ctrl(every_frame=bl)
if __name__ == '__main__':
wsl = WorldSpaceLoc()
try:
w.close()
w.deleteLater()
except:
pass
w = Window(Utils.mayaWindow())
w.show()