Skip to content

Instantly share code, notes, and snippets.

@yohawing
Last active September 30, 2023 03:00
Show Gist options
  • Save yohawing/3f5eb61dffe7713e82bb6acbe46d1b8a to your computer and use it in GitHub Desktop.
Save yohawing/3f5eb61dffe7713e82bb6acbe46d1b8a to your computer and use it in GitHub Desktop.
[maya] Make Stretchy Spline IK
import maya.cmds as cmds
# StartJointからEndJointに関連付けられているJointをListで取得
# Childが一つの想定なので骨が複数あるとおかしくなるかも。
def get_all_spline_joints(joint_list, parent_joint, last_joint):
child = cmds.listRelatives(parent_joint, children=True, type="joint")
joint_list.append(child[0])
if child and last_joint not in child:
get_all_spline_joints(joint_list, child[0], last_joint)
else:
return joint_list
# StretchySplineIKを自動作成するスクリプト
def create_stretchy_spline_ik(start_joint, end_joint, ik_name):
spline_joints = [start_joint]
get_all_spline_joints(spline_joints, start_joint, end_joint)
# Spline IKの作成
ik_handle, effector, curve = cmds.ikHandle(
sj=start_joint,
ee=end_joint,
sol='ikSplineSolver',
createCurve=True,
numSpans=2,
n=ik_name)
curve_info = cmds.arclen(curve, ch=True)
# ジョイントチェーンの初期長さを取得
original_curve_length = cmds.getAttr(curve_info + ".arcLength")
# スケールノードを作成
mult_node = cmds.shadingNode('multiplyDivide', asUtility=True, n=ik_name + "_multDiv")
cmds.setAttr(mult_node + ".operation", 2) # Divide
cmds.setAttr(mult_node + ".input2X", original_curve_length)
# ノードを接続
cmds.connectAttr(curve_info + ".arcLength", mult_node + ".input1X")
for jnt in spline_joints:
cmds.connectAttr(mult_node + ".outputX", jnt + ".scaleX")
return ik_handle, curve
# CurveのControlPointにClusterを自動作成するスクリプト
def apply_clusters_to_curve(curve_name):
curveCVs = cmds.ls('{0}.cv[:]'.format(curve_name), fl=True)
for cv in curveCVs:
cmds.cluster(cv)
# How To Use
selected_joints = cmds.ls(sl=True, flatten=True, type="joint")
start_joint = selected_joints[0]
end_joint = selected_joints[1]
ik_name = "{0}_splineIK".format(end_joint.split("_")[-1]) # ex: Character_LeftArm
ik_handle, curve = create_stretchy_spline_ik(start_joint, end_joint, ik_name)
apply_clusters_to_curve(curve)
@yohawing
Copy link
Author

yohawing commented Sep 30, 2023

Unityに持っていったときにSegmentScaleCompensateの問題が出る。
具体的には、親のスケールを打ち消すMatrixを子に渡すというMayaのデフォルトの挙動がUnityだと再現しない。

上で実現しているリグはScaleベースのため階層構造におけるスケールの解決方法が違うため起きる問題

いっぽう↑のサンプルはX軸方向への変化量しか持たないSplineIKを想定しているため、
Scaleを使わない方法でStreachySplineIKを実現する方法にしたほうがよい。

# 上のサンプルで作ってしまったノードを再設定し直す
def setup(jnt):
    srcNode = cmds.listConnections(jnt+'.scaleX')
    if srcNode:
        cmds.setAttr(jnt+".segmentScaleCompensate", 0)
        cmds.disconnectAttr(srcNode[0] + ".outputX", jnt + '.scaleX')
        moveNode = cmds.shadingNode('multiplyDivide', asUtility=True, n=jnt + "_tr")
        cmds.connectAttr(srcNode[0]+".outputX", moveNode + ".input1X")
        cmds.setAttr(moveNode + ".input2X", cmds.getAttr(jnt + ".translateX"))
        cmds.connectAttr( moveNode+".outputX",jnt + ".translateX")
        

for joint in joint_list:
    setup(joint)

スケールのコネクションを外して、translateXにX軸スケールの掛け算をして同じような挙動を再現できる。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment