You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Maya Python技术咨询:能否通过用户输入生成独立IKFK匹配脚本?

Absolutely feasible—this is exactly the kind of workflow automation that Maya’s Python API was built for! Let’s walk through how to make this happen, step by step.

Core Concept Overview

Our tool will handle two key tasks:

  1. Collect user input for naming conventions (IK/FK controllers, PV locators, joints, etc.)
  2. Dynamically generate a standalone Python script populated with all required getAttr/setAttr calls and your 6-condition PV matching logic.
Step 1: Build a User Input Interface

We’ll use Maya’s built-in UI commands to create a simple window for gathering naming data. For each limb (arm, leg), we’ll collect fields like:

  • FK controller names (shoulder, elbow, wrist)
  • IK controller name
  • PV locator name
  • Optional joint names (to validate scene objects exist)

Here’s a quick snippet for the input window:

import maya.cmds as cmds

def launch_input_window():
    # Clean up existing window if it exists
    if cmds.window("ikfk_gen_win", exists=True):
        cmds.deleteUI("ikfk_gen_win")
    
    win = cmds.window("ikfk_gen_win", title="IKFK Match Script Generator", widthHeight=(450, 350))
    cmds.columnLayout(adjustableColumn=True, spacing=8)
    
    # Left Arm Input Group
    cmds.frameLayout(label="Left Arm Setup", collapsable=True, collapse=False)
    cmds.text(label="FK Shoulder Controller:")
    l_fk_shoulder = cmds.textField()
    cmds.text(label="FK Elbow Controller:")
    l_fk_elbow = cmds.textField()
    cmds.text(label="FK Wrist Controller:")
    l_fk_wrist = cmds.textField()
    cmds.text(label="IK Controller:")
    l_ik_ctrl = cmds.textField()
    cmds.text(label="PV Locator:")
    l_pv_loc = cmds.textField()
    cmds.setParent("..")
    
    # Add similar groups for right arm, left/right legs here
    
    cmds.separator(height=10)
    cmds.button(label="Generate Match Script", command=lambda x: build_ikfk_script(l_fk_shoulder, l_fk_elbow, l_fk_wrist, l_ik_ctrl, l_pv_loc))
    cmds.showWindow(win)
Step 2: Dynamically Generate the Matching Script

The magic happens here—we’ll plug user-provided names into a pre-written code template, including your 6-condition PV matching logic. This ensures the generated script is tailored exactly to the user’s rig naming.

Example PV Matching Template Logic

The 6 if conditions will handle different IK weight ranges, blending PV positions between full IK and full FK states:

def build_ikfk_script(l_fk_shoulder, l_fk_elbow, l_fk_wrist, l_ik_ctrl, l_pv_loc):
    # Pull user input values
    l_fk_shoulder_name = cmds.textField(l_fk_shoulder, query=True, text=True)
    l_fk_elbow_name = cmds.textField(l_fk_elbow, query=True, text=True)
    l_fk_wrist_name = cmds.textField(l_fk_wrist, query=True, text=True)
    l_ik_ctrl_name = cmds.textField(l_ik_ctrl, query=True, text=True)
    l_pv_loc_name = cmds.textField(l_pv_loc, query=True, text=True)
    
    # Validate inputs exist in scene
    for obj in [l_fk_shoulder_name, l_fk_elbow_name, l_fk_wrist_name, l_ik_ctrl_name, l_pv_loc_name]:
        if not cmds.objExists(obj):
            cmds.confirmDialog(message=f"Error: Object {obj} doesn't exist in scene!", button=["OK"])
            return
    
    # Full script template with user names inserted
    script_content = f"""
import maya.cmds as cmds
import math

def calculate_fk_pv(shoulder_pos, elbow_pos, wrist_pos):
    # Calculate ideal PV position for FK mode using vector math
    shoulder_to_elbow = (elbow_pos[0]-shoulder_pos[0], elbow_pos[1]-shoulder_pos[1], elbow_pos[2]-shoulder_pos[2])
    elbow_to_wrist = (wrist_pos[0]-elbow_pos[0], wrist_pos[1]-elbow_pos[1], wrist_pos[2]-elbow_pos[2])
    
    # Cross product to get perpendicular direction for PV offset
    cross_vec = (
        shoulder_to_elbow[1]*elbow_to_wrist[2] - shoulder_to_elbow[2]*elbow_to_wrist[1],
        shoulder_to_elbow[2]*elbow_to_wrist[0] - shoulder_to_elbow[0]*elbow_to_wrist[2],
        shoulder_to_elbow[0]*elbow_to_wrist[1] - shoulder_to_elbow[1]*elbow_to_wrist[0]
    )
    
    # Normalize and offset from arm midpoint
    vec_length = math.sqrt(cross_vec[0]**2 + cross_vec[1]**2 + cross_vec[2]**2)
    norm_cross = (cross_vec[0]/vec_length, cross_vec[1]/vec_length, cross_vec[2]/vec_length)
    midpoint = ((shoulder_pos[0]+wrist_pos[0])/2, (shoulder_pos[1]+wrist_pos[1])/2, (shoulder_pos[2]+wrist_pos[2])/2)
    return (midpoint[0]+norm_cross[0]*5, midpoint[1]+norm_cross[1]*5, midpoint[2]+norm_cross[2]*5)

def run_ikfk_match():
    # Match FK controllers to IK position (reverse as needed)
    ik_shoulder_rot = cmds.getAttr("{l_ik_ctrl_name}.rotate")[0]
    cmds.setAttr("{l_fk_shoulder_name}.rotate", *ik_shoulder_rot)
    
    ik_elbow_rot = cmds.getAttr("{l_ik_ctrl_name}.elbowRotate")[0]  # Adjust based on your rig's attribute names
    cmds.setAttr("{l_fk_elbow_name}.rotate", *ik_elbow_rot)
    
    # PV Matching Logic (6 conditions)
    ik_weight = cmds.getAttr("{l_ik_ctrl_name}.ikBlend")
    
    if ik_weight >= 0.95:
        # Full IK: Snap PV to IK controller's PV position
        ik_pv_pos = cmds.getAttr("{l_ik_ctrl_name}.pvTranslate")[0]
        cmds.setAttr("{l_pv_loc_name}.translate", *ik_pv_pos)
    elif ik_weight <= 0.05:
        # Full FK: Calculate and set PV to ideal FK position
        shoulder_pos = cmds.getAttr("{l_fk_shoulder_name}.translate")[0]
        elbow_pos = cmds.getAttr("{l_fk_elbow_name}.translate")[0]
        wrist_pos = cmds.getAttr("{l_fk_wrist_name}.translate")[0]
        fk_pv_pos = calculate_fk_pv(shoulder_pos, elbow_pos, wrist_pos)
        cmds.setAttr("{l_pv_loc_name}.translate", *fk_pv_pos)
    elif 0.05 < ik_weight <= 0.2:
        # 20% IK / 80% FK blend
        ik_pv = cmds.getAttr("{l_ik_ctrl_name}.pvTranslate")[0]
        shoulder_pos = cmds.getAttr("{l_fk_shoulder_name}.translate")[0]
        elbow_pos = cmds.getAttr("{l_fk_elbow_name}.translate")[0]
        wrist_pos = cmds.getAttr("{l_fk_wrist_name}.translate")[0]
        fk_pv = calculate_fk_pv(shoulder_pos, elbow_pos, wrist_pos)
        blended_pv = (ik_pv[0]*0.2 + fk_pv[0]*0.8, ik_pv[1]*0.2 + fk_pv[1]*0.8, ik_pv[2]*0.2 + fk_pv[2]*0.8)
        cmds.setAttr("{l_pv_loc_name}.translate", *blended_pv)
    elif 0.2 < ik_weight <= 0.4:
        # 40% IK / 60% FK blend
        ik_pv = cmds.getAttr("{l_ik_ctrl_name}.pvTranslate")[0]
        shoulder_pos = cmds.getAttr("{l_fk_shoulder_name}.translate")[0]
        elbow_pos = cmds.getAttr("{l_fk_elbow_name}.translate")[0]
        wrist_pos = cmds.getAttr("{l_fk_wrist_name}.translate")[0]
        fk_pv = calculate_fk_pv(shoulder_pos, elbow_pos, wrist_pos)
        blended_pv = (ik_pv[0]*0.4 + fk_pv[0]*0.6, ik_pv[1]*0.4 + fk_pv[1]*0.6, ik_pv[2]*0.4 + fk_pv[2]*0.6)
        cmds.setAttr("{l_pv_loc_name}.translate", *blended_pv)
    elif 0.4 < ik_weight <= 0.6:
        # 60% IK / 40% FK blend
        ik_pv = cmds.getAttr("{l_ik_ctrl_name}.pvTranslate")[0]
        shoulder_pos = cmds.getAttr("{l_fk_shoulder_name}.translate")[0]
        elbow_pos = cmds.getAttr("{l_fk_elbow_name}.translate")[0]
        wrist_pos = cmds.getAttr("{l_fk_wrist_name}.translate")[0]
        fk_pv = calculate_fk_pv(shoulder_pos, elbow_pos, wrist_pos)
        blended_pv = (ik_pv[0]*0.6 + fk_pv[0]*0.4, ik_pv[1]*0.6 + fk_pv[1]*0.4, ik_pv[2]*0.6 + fk_pv[2]*0.4)
        cmds.setAttr("{l_pv_loc_name}.translate", *blended_pv)
    elif 0.6 < ik_weight < 0.95:
        # 80% IK / 20% FK blend
        ik_pv = cmds.getAttr("{l_ik_ctrl_name}.pvTranslate")[0]
        shoulder_pos = cmds.getAttr("{l_fk_shoulder_name}.translate")[0]
        elbow_pos = cmds.getAttr("{l_fk_elbow_name}.translate")[0]
        wrist_pos = cmds.getAttr("{l_fk_wrist_name}.translate")[0]
        fk_pv = calculate_fk_pv(shoulder_pos, elbow_pos, wrist_pos)
        blended_pv = (ik_pv[0]*0.8 + fk_pv[0]*0.2, ik_pv[1]*0.8 + fk_pv[1]*0.2, ik_pv[2]*0.8 + fk_pv[2]*0.2)
        cmds.setAttr("{l_pv_loc_name}.translate", *blended_pv)

# Execute the match
run_ikfk_match()
"""
    # Write the generated script to file
    with open("ikfk_match_generator_output.py", "w") as f:
        f.write(script_content)
    cmds.confirmDialog(message="Script generated successfully! Check your Maya project folder.", button=["OK"])

# Launch the input window
launch_input_window()
Key Tips for Success
  • Add validation: The snippet above includes a quick check for existing scene objects—expand this to validate attribute names too (e.g., ensure ikBlend exists on the IK controller).
  • Make it flexible: Let users input custom attribute names (like if your rig uses ikWeight instead of ikBlend) via additional text fields.
  • Test incrementally: Generate a script for one limb first, test it, then add support for other limbs by duplicating the template logic.

内容的提问来源于stack exchange,提问作者Dalia Hileman

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:21:56