This commit is contained in:
2025-11-30 23:24:58 +08:00
parent 3186163e84
commit d853883d5f
2 changed files with 90 additions and 100 deletions

View File

@@ -23,19 +23,16 @@ class IKFKSwitchUI(object):
"""Initialize UI"""
self.target_fields = {}
self.target_values = {
'target_01': '',
'target_02': '',
'target_03': '',
'target_04': '',
'target_05': '',
'target_06': '',
'target_07': '',
'target_08': '',
'target_09': '',
'target_10': '',
'target_11': '',
'target_12': '',
'target_13': ''
'target_01': '', # FK Joint Root
'target_02': '', # FK Joint Mid
'target_03': '', # FK Joint End
'target_04': '', # FK Ctrl Root
'target_05': '', # FK Ctrl Mid
'target_06': '', # FK Ctrl End
'target_07': '', # IK Ctrl Root
'target_08': '', # IK Ctrl Pole
'target_09': '', # Switch Ctrl
'target_10': '' # Switch Attr
}
def create_ui(self):
@@ -87,12 +84,8 @@ class IKFKSwitchUI(object):
ik_frame = cmds.frameLayout(label="Load IK Ctrl")
cmds.columnLayout(rowSpacing=2, adjustableColumn=True)
self._create_text_field_row('target_07', '< IK Joint Root')
self._create_text_field_row('target_08', '< IK Joint Mid')
self._create_text_field_row('target_09', '< IK Joint End')
cmds.separator(style='in', height=5)
self._create_text_field_row('target_10', '< IK Ctrl Root')
self._create_text_field_row('target_11', '< IK Ctrl Pole')
self._create_text_field_row('target_07', '< IK Ctrl Root')
self._create_text_field_row('target_08', '< IK Ctrl Pole')
cmds.setParent('..')
cmds.setParent('..')
@@ -101,11 +94,11 @@ class IKFKSwitchUI(object):
switch_frame = cmds.frameLayout(label="Load Switch Ctrl")
cmds.columnLayout(rowSpacing=2, adjustableColumn=True)
self._create_text_field_row('target_12', '< Switch Ctrl')
self._create_text_field_row('target_09', '< Switch Ctrl')
# Special row for attribute selection
cmds.rowLayout(numberOfColumns=2, adjustableColumn=1, columnWidth2=(45, 60))
self.target_fields['target_13'] = cmds.textField(text='')
self.target_fields['target_10'] = cmds.textField(text='')
cmds.button(width=120, label='< Switch Attr', command=lambda x: self.load_attr())
cmds.setParent('..')
@@ -149,10 +142,10 @@ class IKFKSwitchUI(object):
return
attr_name = attrs[0]
cmds.textField(self.target_fields['target_13'], edit=True, text=attr_name)
self.target_values['target_13'] = attr_name
cmds.textField(self.target_fields['target_10'], edit=True, text=attr_name)
self.target_values['target_10'] = attr_name
except Exception as e:
cmds.warning(f"Failed to load attribute: {e}")
cmds.warning("Failed to load attribute: {}".format(e))
def execute(self):
"""Execute the seamless switching setup"""
@@ -163,19 +156,17 @@ class IKFKSwitchUI(object):
fk_ctrl_root = cmds.textField(self.target_fields['target_04'], query=True, text=True)
fk_ctrl_mid = cmds.textField(self.target_fields['target_05'], query=True, text=True)
fk_ctrl_end = cmds.textField(self.target_fields['target_06'], query=True, text=True)
ik_joint_root = cmds.textField(self.target_fields['target_07'], query=True, text=True)
ik_joint_mid = cmds.textField(self.target_fields['target_08'], query=True, text=True)
ik_joint_end = cmds.textField(self.target_fields['target_09'], query=True, text=True)
ik_ctrl_root = cmds.textField(self.target_fields['target_10'], query=True, text=True)
ik_ctrl_pole = cmds.textField(self.target_fields['target_11'], query=True, text=True)
switch_ctrl = cmds.textField(self.target_fields['target_12'], query=True, text=True)
switch_attr = cmds.textField(self.target_fields['target_13'], query=True, text=True)
ik_ctrl_root = cmds.textField(self.target_fields['target_07'], query=True, text=True)
ik_ctrl_pole = cmds.textField(self.target_fields['target_08'], query=True, text=True)
switch_ctrl = cmds.textField(self.target_fields['target_09'], query=True, text=True)
switch_attr = cmds.textField(self.target_fields['target_10'], query=True, text=True)
# Call the seamless switching function
# Note: IK joints use FK joints for reference (same as MEL version)
seamless_switching(
fk_joint_root, fk_joint_mid, fk_joint_end,
fk_ctrl_root, fk_ctrl_mid, fk_ctrl_end,
ik_joint_root, ik_joint_mid, ik_joint_end,
fk_joint_root, fk_joint_mid, fk_joint_end, # IK joints = FK joints
ik_ctrl_root, ik_ctrl_pole,
switch_ctrl, switch_attr
)
@@ -252,19 +243,19 @@ def seamless_switching(
switch_attr: Switch attribute name
"""
# Create locator for storing data
locator_name = f"{switch_ctrl}_Switch_Locator"
locator_name = "{}_Switch_Locator".format(switch_ctrl)
if not cmds.objExists(locator_name):
locator_shape = cmds.createNode('locator', name=locator_name)
locator_transform = cmds.listRelatives(locator_shape, parent=True)[0]
cmds.parent(locator_shape, switch_ctrl, shape=True, add=True)
cmds.delete(locator_transform)
cmds.setAttr(f"{locator_name}.visibility", 0)
cmds.setAttr("{}.visibility".format(locator_name), 0)
# Add IKFK_Seamless attribute if it doesn't exist
if not cmds.objExists(f"{switch_ctrl}.IKFK_Seamless"):
if not cmds.objExists("{}.IKFK_Seamless".format(switch_ctrl)):
cmds.addAttr(switch_ctrl, longName="IKFK_Seamless", attributeType="enum", enumName="IK:FK:", keyable=False)
cmds.setAttr(f"{switch_ctrl}.IKFK_Seamless", channelBox=True)
cmds.setAttr("{}.IKFK_Seamless".format(switch_ctrl), channelBox=True)
# Add Location attribute to all objects
objs = [
@@ -275,8 +266,12 @@ def seamless_switching(
]
for obj in objs:
if not cmds.objExists(f"{obj}.Location"):
cmds.addAttr(obj, longName="Location", dataType="string", keyable=True)
# Check if object name is not empty and exists
if obj and cmds.objExists(obj):
if not cmds.objExists("{}.Location".format(obj)):
cmds.addAttr(obj, longName="Location", dataType="string", keyable=True)
else:
cmds.warning("Object does not exist or is empty: {}".format(obj))
# Add attributes to locator and connect
attrs_data = {
@@ -297,17 +292,17 @@ def seamless_switching(
}
for attr_name, attr_value in attrs_data.items():
if not cmds.objExists(f"{locator_name}.{attr_name}"):
if not cmds.objExists("{}.{}".format(locator_name, attr_name)):
cmds.addAttr(locator_name, longName=attr_name, dataType="string", keyable=True)
cmds.setAttr(f"{locator_name}.{attr_name}", attr_value, type="string")
cmds.setAttr("{}.{}".format(locator_name, attr_name), attr_value, type="string")
# Connect to Location attribute (except for special attributes)
if attr_name not in ["IKFK_Seamless_Switching", "Switch_Attr"]:
target_obj = attr_value
if cmds.objExists(f"{target_obj}.Location"):
if not cmds.isConnected(f"{locator_name}.{attr_name}", f"{target_obj}.Location"):
cmds.connectAttr(f"{locator_name}.{attr_name}", f"{target_obj}.Location", force=True)
if cmds.objExists("{}.Location".format(target_obj)):
if not cmds.isConnected("{}.{}".format(locator_name, attr_name), "{}.Location".format(target_obj)):
cmds.connectAttr("{}.{}".format(locator_name, attr_name), "{}.Location".format(target_obj), force=True)
# Create switching script
create_switching_script()
@@ -315,7 +310,7 @@ def seamless_switching(
# Create script job for this control
create_script_job(switch_ctrl, locator_name)
print(f"IKFK Seamless Switching setup completed for {switch_ctrl}")
print("IKFK Seamless Switching setup completed for {}".format(switch_ctrl))
def create_switching_script():
@@ -419,34 +414,34 @@ global proc sg_switching (string $Switch)
else:
cmds.scriptNode(script_node_name, edit=True, beforeScript=mel_script)
cmds.setAttr(f"{script_node_name}.scriptType", 1)
cmds.setAttr("{}.scriptType".format(script_node_name), 1)
cmds.scriptNode(script_node_name, executeBefore=True)
def create_script_job(switch_ctrl, locator_name):
"""Create script job for automatic switching"""
script_node_name = f"{switch_ctrl}_Switching_Script"
script_node_name = "{}_Switching_Script".format(switch_ctrl)
# MEL script for script job creation
mel_script = f'''
mel_script = '''
string $Locator_all[]=`ls -typ "locator"`;
for($Locator in $Locator_all){{
if(`objExists ($Locator+".IKFK_Seamless_Switching")`){{
string $tmp=`getAttr ($Locator+".IKFK_Seamless_Switching")`;
if($tmp=="{locator_name}"){{
if($tmp=="{0}"){{
string $Switch[]=`listConnections ($Locator+".Switch_Ctrl")`;
scriptJob -ac ($Switch[0]+".IKFK_Seamless") ("sg_switching "+$Locator) -kws;
}}
}}
}}
'''
'''.format(locator_name)
if not cmds.objExists(script_node_name):
cmds.scriptNode(beforeScript=mel_script, name=script_node_name)
else:
cmds.scriptNode(script_node_name, edit=True, beforeScript=mel_script)
cmds.setAttr(f"{script_node_name}.scriptType", 1)
cmds.setAttr("{}.scriptType".format(script_node_name), 1)
cmds.scriptNode(script_node_name, executeBefore=True)

View File

@@ -23,19 +23,16 @@ class IKFKSwitchUI(object):
"""Initialize UI"""
self.target_fields = {}
self.target_values = {
'target_01': '',
'target_02': '',
'target_03': '',
'target_04': '',
'target_05': '',
'target_06': '',
'target_07': '',
'target_08': '',
'target_09': '',
'target_10': '',
'target_11': '',
'target_12': '',
'target_13': ''
'target_01': '', # FK Joint Root
'target_02': '', # FK Joint Mid
'target_03': '', # FK Joint End
'target_04': '', # FK Ctrl Root
'target_05': '', # FK Ctrl Mid
'target_06': '', # FK Ctrl End
'target_07': '', # IK Ctrl Root
'target_08': '', # IK Ctrl Pole
'target_09': '', # Switch Ctrl
'target_10': '' # Switch Attr
}
def create_ui(self):
@@ -87,12 +84,8 @@ class IKFKSwitchUI(object):
ik_frame = cmds.frameLayout(label="Load IK Ctrl")
cmds.columnLayout(rowSpacing=2, adjustableColumn=True)
self._create_text_field_row('target_07', '< IK Joint Root')
self._create_text_field_row('target_08', '< IK Joint Mid')
self._create_text_field_row('target_09', '< IK Joint End')
cmds.separator(style='in', height=5)
self._create_text_field_row('target_10', '< IK Ctrl Root')
self._create_text_field_row('target_11', '< IK Ctrl Pole')
self._create_text_field_row('target_07', '< IK Ctrl Root')
self._create_text_field_row('target_08', '< IK Ctrl Pole')
cmds.setParent('..')
cmds.setParent('..')
@@ -101,11 +94,11 @@ class IKFKSwitchUI(object):
switch_frame = cmds.frameLayout(label="Load Switch Ctrl")
cmds.columnLayout(rowSpacing=2, adjustableColumn=True)
self._create_text_field_row('target_12', '< Switch Ctrl')
self._create_text_field_row('target_09', '< Switch Ctrl')
# Special row for attribute selection
cmds.rowLayout(numberOfColumns=2, adjustableColumn=1, columnWidth2=(45, 60))
self.target_fields['target_13'] = cmds.textField(text='')
self.target_fields['target_10'] = cmds.textField(text='')
cmds.button(width=120, label='< Switch Attr', command=lambda x: self.load_attr())
cmds.setParent('..')
@@ -149,10 +142,10 @@ class IKFKSwitchUI(object):
return
attr_name = attrs[0]
cmds.textField(self.target_fields['target_13'], edit=True, text=attr_name)
self.target_values['target_13'] = attr_name
cmds.textField(self.target_fields['target_10'], edit=True, text=attr_name)
self.target_values['target_10'] = attr_name
except Exception as e:
cmds.warning(f"Failed to load attribute: {e}")
cmds.warning("Failed to load attribute: {}".format(e))
def execute(self):
"""Execute the seamless switching setup"""
@@ -163,19 +156,17 @@ class IKFKSwitchUI(object):
fk_ctrl_root = cmds.textField(self.target_fields['target_04'], query=True, text=True)
fk_ctrl_mid = cmds.textField(self.target_fields['target_05'], query=True, text=True)
fk_ctrl_end = cmds.textField(self.target_fields['target_06'], query=True, text=True)
ik_joint_root = cmds.textField(self.target_fields['target_07'], query=True, text=True)
ik_joint_mid = cmds.textField(self.target_fields['target_08'], query=True, text=True)
ik_joint_end = cmds.textField(self.target_fields['target_09'], query=True, text=True)
ik_ctrl_root = cmds.textField(self.target_fields['target_10'], query=True, text=True)
ik_ctrl_pole = cmds.textField(self.target_fields['target_11'], query=True, text=True)
switch_ctrl = cmds.textField(self.target_fields['target_12'], query=True, text=True)
switch_attr = cmds.textField(self.target_fields['target_13'], query=True, text=True)
ik_ctrl_root = cmds.textField(self.target_fields['target_07'], query=True, text=True)
ik_ctrl_pole = cmds.textField(self.target_fields['target_08'], query=True, text=True)
switch_ctrl = cmds.textField(self.target_fields['target_09'], query=True, text=True)
switch_attr = cmds.textField(self.target_fields['target_10'], query=True, text=True)
# Call the seamless switching function
# Note: IK joints use FK joints for reference (same as MEL version)
seamless_switching(
fk_joint_root, fk_joint_mid, fk_joint_end,
fk_ctrl_root, fk_ctrl_mid, fk_ctrl_end,
ik_joint_root, ik_joint_mid, ik_joint_end,
fk_joint_root, fk_joint_mid, fk_joint_end, # IK joints = FK joints
ik_ctrl_root, ik_ctrl_pole,
switch_ctrl, switch_attr
)
@@ -252,19 +243,19 @@ def seamless_switching(
switch_attr: Switch attribute name
"""
# Create locator for storing data
locator_name = f"{switch_ctrl}_Switch_Locator"
locator_name = "{}_Switch_Locator".format(switch_ctrl)
if not cmds.objExists(locator_name):
locator_shape = cmds.createNode('locator', name=locator_name)
locator_transform = cmds.listRelatives(locator_shape, parent=True)[0]
cmds.parent(locator_shape, switch_ctrl, shape=True, add=True)
cmds.delete(locator_transform)
cmds.setAttr(f"{locator_name}.visibility", 0)
cmds.setAttr("{}.visibility".format(locator_name), 0)
# Add IKFK_Seamless attribute if it doesn't exist
if not cmds.objExists(f"{switch_ctrl}.IKFK_Seamless"):
if not cmds.objExists("{}.IKFK_Seamless".format(switch_ctrl)):
cmds.addAttr(switch_ctrl, longName="IKFK_Seamless", attributeType="enum", enumName="IK:FK:", keyable=False)
cmds.setAttr(f"{switch_ctrl}.IKFK_Seamless", channelBox=True)
cmds.setAttr("{}.IKFK_Seamless".format(switch_ctrl), channelBox=True)
# Add Location attribute to all objects
objs = [
@@ -275,8 +266,12 @@ def seamless_switching(
]
for obj in objs:
if not cmds.objExists(f"{obj}.Location"):
cmds.addAttr(obj, longName="Location", dataType="string", keyable=True)
# Check if object name is not empty and exists
if obj and cmds.objExists(obj):
if not cmds.objExists("{}.Location".format(obj)):
cmds.addAttr(obj, longName="Location", dataType="string", keyable=True)
else:
cmds.warning("Object does not exist or is empty: {}".format(obj))
# Add attributes to locator and connect
attrs_data = {
@@ -297,17 +292,17 @@ def seamless_switching(
}
for attr_name, attr_value in attrs_data.items():
if not cmds.objExists(f"{locator_name}.{attr_name}"):
if not cmds.objExists("{}.{}".format(locator_name, attr_name)):
cmds.addAttr(locator_name, longName=attr_name, dataType="string", keyable=True)
cmds.setAttr(f"{locator_name}.{attr_name}", attr_value, type="string")
cmds.setAttr("{}.{}".format(locator_name, attr_name), attr_value, type="string")
# Connect to Location attribute (except for special attributes)
if attr_name not in ["IKFK_Seamless_Switching", "Switch_Attr"]:
target_obj = attr_value
if cmds.objExists(f"{target_obj}.Location"):
if not cmds.isConnected(f"{locator_name}.{attr_name}", f"{target_obj}.Location"):
cmds.connectAttr(f"{locator_name}.{attr_name}", f"{target_obj}.Location", force=True)
if cmds.objExists("{}.Location".format(target_obj)):
if not cmds.isConnected("{}.{}".format(locator_name, attr_name), "{}.Location".format(target_obj)):
cmds.connectAttr("{}.{}".format(locator_name, attr_name), "{}.Location".format(target_obj), force=True)
# Create switching script
create_switching_script()
@@ -315,7 +310,7 @@ def seamless_switching(
# Create script job for this control
create_script_job(switch_ctrl, locator_name)
print(f"IKFK Seamless Switching setup completed for {switch_ctrl}")
print("IKFK Seamless Switching setup completed for {}".format(switch_ctrl))
def create_switching_script():
@@ -419,34 +414,34 @@ global proc sg_switching (string $Switch)
else:
cmds.scriptNode(script_node_name, edit=True, beforeScript=mel_script)
cmds.setAttr(f"{script_node_name}.scriptType", 1)
cmds.setAttr("{}.scriptType".format(script_node_name), 1)
cmds.scriptNode(script_node_name, executeBefore=True)
def create_script_job(switch_ctrl, locator_name):
"""Create script job for automatic switching"""
script_node_name = f"{switch_ctrl}_Switching_Script"
script_node_name = "{}_Switching_Script".format(switch_ctrl)
# MEL script for script job creation
mel_script = f'''
mel_script = '''
string $Locator_all[]=`ls -typ "locator"`;
for($Locator in $Locator_all){{
if(`objExists ($Locator+".IKFK_Seamless_Switching")`){{
string $tmp=`getAttr ($Locator+".IKFK_Seamless_Switching")`;
if($tmp=="{locator_name}"){{
if($tmp=="{0}"){{
string $Switch[]=`listConnections ($Locator+".Switch_Ctrl")`;
scriptJob -ac ($Switch[0]+".IKFK_Seamless") ("sg_switching "+$Locator) -kws;
}}
}}
}}
'''
'''.format(locator_name)
if not cmds.objExists(script_node_name):
cmds.scriptNode(beforeScript=mel_script, name=script_node_name)
else:
cmds.scriptNode(script_node_name, edit=True, beforeScript=mel_script)
cmds.setAttr(f"{script_node_name}.scriptType", 1)
cmds.setAttr("{}.scriptType".format(script_node_name), 1)
cmds.scriptNode(script_node_name, executeBefore=True)