单骨骼FK/IK无缝切换技术

// January 20th, 2009 // CG, 绑定

[原文作者]:Seith
[原文地址]:Arm Rig Setup For Seamless FK/IK Switching
[译文作者]:XRacZ
[译文地址]:单骨骼FK/IK无缝切换技术

相信很多动画师在K动画时最头疼的就是进行FK/IK切换时,骨骼会自己摆动回以前的状态,然后再手工对位把物体对回去,这不仅降低了K动画的效率,还难以把握位置的准确,我也曾因此被困扰了许久,于是带着问题在Google搜寻,还真找到几篇关于FK/IK无缝切换的文章,但从实现的效果来看,只有SeithArm Rig Setup For Seamless FK/IK Switching最完善。鉴于目前国内此类文章较少,所以决定将此文翻译出来奉献给大家。

译者注:原文有很多地方利用编程来实现,我尽可能给每句代码加上注释便于大家理解。还有,转载请注明出处!!

本教程假设你已经创建好了这样一套简单的骨骼:

  • 一个名为 L_shoulder_JNT 的骨点
  • 一个名为 L_elbow_JNT 的骨点
  • 一个名为 L_armIk_CON 的手臂控制器 (采用点约束对IK手柄进行控制)
  • 一个名为 L_armPole_CON 的极向量控制器

你也可以下载我做好的 Maya (6.0以上版本) 源文件: armRig_001.ma.

本教程的目的在于通过对一个简单手臂的绑定来详细阐述FK/IK无缝切换的实现方法,即在进行FK/IK切换的时候不会出现骨骼自己摆动的情况,这对于动画师给角色摆Pose将非常有用(尤其在K动画方面)。切记,此方法只使用一套骨骼。

skeleton 01 单骨骼FK/IK无缝切换技术skeleton 02 单骨骼FK/IK无缝切换技术

在本案例中,手臂IK和极向量控制器用Nurbs曲线来制作,但你也可以按自己的喜好用别的物体来代替。当然也可以使用我的源文件: armRig_001.ma.

请记住一定要在一个绝对平面上创骨骼。 肘部弯曲正常,而且不带扭曲(即骨骼不能带旋转值)!

1) 用MEL来绑定:

现在我们已经有了一套简单的骨骼和几个控制器, 下一步来进行绑定. 以下代码用于优化该场景中的骨骼和控制器使其适于做FK/IK切换(其实就是用代码来完成一些手工操作):

// 1) 锁上肘部骨点的Y、Z旋转(这是为了使其像真实肘部那样运动)。
setAttr "L_elbow_JNT.jointTypeY" 0; //取消骨点L_elbow_JNT的Y轴自由角功能(对应骨骼属性栏里的Degrees of Freedom)
setAttr "L_elbow_JNT.jointTypeZ" 0; //取消骨点L_elbow_JNT的Z轴自由角功能(对应骨骼属性栏里的Degrees of Freedom)
setAttr -lock true -keyable false "L_elbow_JNT.ry"; //锁上骨点L_elbow_JNT的Y轴旋转,并使其不可K帧
setAttr -lock true -keyable false "L_elbow_JNT.rz"; //锁上骨点L_elbow_JNT的Z轴旋转,并使其不可K帧
//
// 2) 创建IK手柄。
ikHandle -sol ikRPsolver -sj L_shoulder_JNT -ee L_wrist_JNT -n L_arm_IK; //从骨点L_shoulder_JNT至骨点L_wrist_JNT创建一名为L_arm_IK的IK手柄

//
// 3) 设置手臂IK控制器在世界空间 (默认值不是0,但我们不用担心)。
move -rpr 0 0 0 L_armIk_CON; //将控制器L_armIk_CON移至世界坐标原点
makeIdentity -a 1 -r 1 -t 1 -s 1 L_armIk_CON; //对其进行Freeze
vector $wristPos = `xform -query -a -worldSpace -rp L_wrist_JNT`; //用xform命令提取骨点L_wrist_JNT的世界坐标值,赋予变量$wristPos
move -worldSpace -a ($wristPos.x) ($wristPos.y) ($wristPos.z) L_armIk_CON; //将控制器L_armIk_CON移至骨点L_wrist_JNT的位置
makeIdentity -a 1 -r 1 -t 1 -s 1 L_armIk_CON; //对控制器L_armIk_CON进行Freeze
pointConstraint -w 1 -o 0 0 0 L_armIk_CON L_arm_IK; //控制器L_armIk_CON对IK手柄L_arm_IK进行点约束
//
// 4) 为手臂极向量创建locator进行定位
// (当由FK切换至IK的时候我们用locator来对极向量定位)。
spaceLocator -p 0 0 0 -n "L_armPoleDefault_LOC"; //创建一名为L_armPoleDefault_LOC的locator
vector $elbowPos = `xform -query -a -worldSpace -rp L_elbow_JNT`; //用xform命令提取骨点L_elbow_JNT的世界坐标值,赋予变量$elbowPos
move -a ($elbowPos.x) ($elbowPos.y) ($elbowPos.z) L_armPoleDefault_LOC; //将L_armPoleDefault_LOC移至骨点L_elbow_JNT的位置
//
// 5) 将刚创建的locator作为肩膀骨点的子物体,并将其放置在肘部的后面。
parent L_armPoleDefault_LOC L_shoulder_JNT; //将L_armPoleDefault_LOC P给骨点L_shoulder_JNT
move -r -ws -wd 0 0 -10 "L_armPoleDefault_LOC"; //将L_armPoleDefault_LOC延Z轴反方向移动十个单位

setAttr "L_armPoleDefault_LOC.visibility" 0; //将L_armPoleDefault_LOC隐藏
//
// 6) 匹配极向量和locator的位置。
pointConstraint -w 1 -o 0 0 0 L_armPoleDefault_LOC L_armPole_CON; //L_armPoleDefault_LOC对控制器L_armPole_CON进行点约束
delete L_armPole_CON_pointConstraint1; //删除这个点约束
makeIdentity -apply true -t 1 -r 1 -s 1 -n 0 "L_armPole_CON"; //对控制器L_armPole_CON进行Freeze
//
// 7) 对IK手柄L_arm_IK进行极向量约束。
poleVectorConstraint -w 1 L_armPole_CON L_arm_IK; //控制器L_armPole_CON对IK手柄L_arm_IK创建极向量约束
//
// 8 ) 连接IK手柄的显示隐藏属性至腕部IK控制器的自定义属性
addAttr -ln enableIk -at bool -k on -dv 0 L_armIk_CON; //给控制器L_armIk_CON添加名为enableIk的bool类型属性,并设置默认值为0
connectAttr -f L_armIk_CON.enableIk L_arm_IK.ikBlend; //将控制器L_armIk_CON的enableIk属性连接至IK手柄L_arm_IK的ikBlend属性
connectAttr -f L_armIk_CON.enableIk L_arm_IK.visibility; //将控制器L_armIk_CON的enableIk属性连接至IK手柄L_arm_IK的visibility属性
connectAttr -f L_armIk_CON.enableIk L_armIk_CON.visibility; //将控制器L_armIk_CON的enableIk属性连接至自身的visibility属性
//
// 9) 将手臂默认设为FK方式。
setAttr "L_armIk_CON.enableIk" 0; //设置控制器L_armIk_CON的enableIk属性值为0

鉴于网页字符转换的问题,提供这段Mel源文件下载,推荐使用:armrig_mel_001.mel

2) IK/FK切换:

至此我们已经完成了绑定,可以进行切换的设置了。 如果一切顺利,腕部的IK控制器会消失不见。 这很正常,因为当前骨骼正处在FK状态。因此你可以通过旋转肩膀和肘部的骨点让其运动。

整个手臂的绑定仅需一套骨骼即可实现,并且同时存在FK和IK。技巧在于采用一个locator作为肩膀骨点L_shoulder_JNT的子物体,从而充当一个定位器,每次切换到IK时,将控制器L_armPole_CON吸附到locator上即可达到无缝的目的。

这样做的一个好处在于locator能永远处在正确的位置来帮助定位,从而避免了切换时骨骼自己摆动的问题。

另一个好处就是动画师不必再为切换至IK时寻找极向量控制器而烦恼,因为它会自始至终停留在切换前的位置。

当你想切换至IK时,使用这个脚本: IkFk_switch_002.mel。你可以将其载入(source)脚本编辑器,或者复制/粘贴进去,做成一个按钮。要运行,仅需执行以下命令:

IkFk_switch( "", "L_", "arm" );

该函数自身是一个包含3个参数的命令。第一个是命名空间(除非该绑定是通过参考方式导入,否则保持默认为”"),第二个参数是手臂的左右位置(填”L_” 或 “R_”),最后一个指的是四肢(”arm” 或者 “leg”,本案例中为arm)。代码中包含详细的注释,想了解原理的朋友可以拿来研究一下。

你可以看到无论如何移动、旋转骨骼,当切换时,依然能保持原位。

想切换回FK,仅需用同样的参数执行那个命令即可。

还有什么不明白的地方,欢迎给我留言……

32 Responses to “单骨骼FK/IK无缝切换技术”

  1. 莫失莫忘. says:

    请记住一定要在一个绝对平面上创骨骼。 肘部弯曲正常,而且不带扭曲(即骨骼不能带旋转值)! 这个是要使用你提供的MEL才要注意的吧?不过MEL里加中文 没问题吧?

  2. XRacZ says:

    加中文没事的,//后是注释,不会执行

  3. 莫失莫忘. says:

    不行啊 我用的是您提供的源文件 但是输入代码后不行啊 提示// Error: Syntax error

  4. XRacZ says:

    谢谢你发现的问题,出现这样的错误因为是双引号复制过去后,变成其它符号,需要您手动改一下,在英文输入状态下把双引号改回来就没事了。可能是我的网页格式导致的问题,我以后尽量解决

  5. 莫失莫忘. says:

    冒昧问下 不知道您了解眼睛的高级控制么? 知道麻烦告诉一下 就是控制器控制瞳孔大小 但是模型不变 好像变的是贴图吧 就是类似这样的控制 。

  6. 莫失莫忘. says:

    // Error: No object matches name: L_armPoleDefault_LOC // 又是一个错误…

  7. XRacZ says:

    文中代码没有任何错误,我直接把人家的复制过来,然后加中文注释的,要错也是网页的问题,例如把双引号变成了其它符号。
    // Error: No object matches name: L_armPoleDefault_LOC 是因为你没有执行“spaceLocator -p 0 0 0 -n “L_armPoleDefault_LOC”;”这句,创建一个名为L_armPoleDefault_LOC的locator,请按顺序执行上面的代码

  8. XRacZ says:

    你说的那种眼睛的高级控制,原理就是控制器上加个属性来控制ramp节点上的颜色位置分布信息,但要同时控制好几个,要调一个眼球材质,ramp的颜色分布可多了,你必须同时去控制这些,具体我没做过,不弄材质好久了

  9. 莫失莫忘. says:

    哈哈 谢谢你了 还是给我提供了一个眼睛思路 以前我以为是控制贴图UV但是写表示式都不管用 提示无法控制 呵呵。 谢谢你。网页有错误的话 其实你可以把这个代码的源文件和源文件一起发出来的。呵呵 不过还说非常感谢你的。

  10. XRacZ says:

    恩,谢谢您的支持,有问题欢迎来提,我也是新手,渴望共同进步

  11. alien says:

    XracZ
    谢谢您的教程,我一直在这方面受到困扰。我会认真学习这篇教程。
    因为我MAYA一般般,所以没办法参与到技术讨论的层次,谢谢您的无私分享。真心感谢:)

  12. 笑醉尘 says:

    非常感谢你呀 呵呵 以后不懂就来问你了 哈

  13. alien says:

    XracZ,
    ||3) 设置手臂IK控制器在世界空间 (默认值不是0,但我们不用担心)。
    move -rpr 0 0 0 L_armIk_CON; //将控制器L_armIk_CON移至世界坐标原点
    makeIdentity -a 1 -r 1 -t 1 -s 1 L_armIk_CON; //对其进行Freeze
    vector $wristPos = `xform -query -a -worldSpace -rp L_wrist_JNT`; //用xform命令提取骨点L_wrist_JNT的世界坐标值,赋予变量$wristPos
    move -worldSpace -a ($wristPos.x) ($wristPos.y) ($wristPos.z) L_armIk_CON; //将控制器L_armIk_CON移至骨点L_wrist_JNT的位置
    makeIdentity -a 1 -r 1 -t 1 -s 1 L_armIk_CON; //对控制器L_armIk_CON进行Freeze||

    第一个问题:为什么把L_armIk_CON先弄到原点,Freeze属性,然后再将控制器L_armIk_CON移至骨点L_wrist_JNT的位置,再freeze?如果我使用的是您提供的场景文件,(控制器L_armIk_CON已经在L_wrist_JNT的位置,并且freeze属性了)还用操作这些几个步骤吗?
    还有一个问题,用xform命令提取骨点L_wrist_JNT的世界坐标值,赋予变量$wristPos,这个步骤一定在“将控制器L_armIk_CON移至骨点L_wrist_JNT的位置”这个步骤之前来做吗?

    谢谢咯:)

  14. alien says:

    XracZ 有个小请求,可不可以把那段用于绑定的mel 以记事本的格式上传一下,我一条一条的复制也报错了:)
    谢谢:)

  15. XRacZ says:

    您好,alien,谢谢您的留言!先回答前两个问题,一、其实我也觉得这么做多余,原文的做法只是一种规范化操作,事实上我们在世界创建好控制器后,吸附到手腕,再freeze就可以,我们不必非得遵循他的做法。二、将一个物体的数值赋予另一个变量,再通过这个变量赋予另一个物体,是编程上的一种思路,可以带来很多其它方面的便捷和代码的易懂,具体不加以讨论,如果兄弟有兴趣研究编程的话,可以学习下。
    P.S:我已经将那段绑定的源文件上传了,请到文中下载
    谢谢您的支持!

  16. alien says:

    XRacZ:
    谢谢您的耐心解答:)

    我继续研究这篇教程:)期待您更多的教程。

    祝一切顺利!

  17. alien says:

    XRacZ,有个小问题
    我执行了armrig_mel_001.mel,测试场景,发现由FK转IF时,骨骼还是要动,不知我哪里出现了问题?
    请问是在转换前要执行 IkFk_switch_002.mel吗?
    IkFk_switch( “”, “L_”, “arm” );这个mel是做什么用的?
    IkFk_switch( “”, “L_”, “arm” );与IkFk_switch_002.mel怎么配合使用?
    不知道我说的是否明白:)
    我的问题可能太幼稚了,请XRacZ原谅:)
    谢谢!

  18. XRacZ says:

    IkFk_switch( “”, “”, “” ),这个函数里所填写的内容和你骨骼命名有关,如果您使用的是本文提供的范例文件,先执行IkFk_switch_002.mel里面的代码,然后每次切换执行IkFk_switch( “”, “L_”, “arm” );这个命令,注意!切换时不是通过手控制器通道栏里的IKFK属性值调节来实现,还有armrig_mel_001.mel只是用于绑定的,用过一次就不必再用了。
    其实兄弟最大的困惑在于对编程的不了解,这一环节知识的缺乏导致你学习本文时遇到困难,如果有时间的话,建议兄弟先学习C语言基础再研究本文,能学到更多。

  19. alien says:

    十分感谢XRacZ
    哈,一上来发现昨天的留言成功了:)
    谢谢XRacZ的解答,十分感谢:)
    有时间一定按XRacZ的建议做.

  20. 镀金铆钉 says:

    哈哈,这方法在摆POSE的时候不错,但,貌似不适合动画啊,我直接在FK模式下给骨骼K帧,然后转到IK下给IK控制器K桢,没能成功……不爽,不爽啊!!!

  21. utoo says:

    请问为什么没有FK控制器,,那在K动画时非常不方便

    谢谢

  22. 百味人生 says:

    我是个新手,刚刚接触绑定这块,想请教几个问题。
    不知道楼主可以留个QQ不?
    我有好多问题要问哦。。

  23. 百味人生 says:

    楼主,看了你的教程,我研究了一个下午,还是没出来。。
    用你给的文件试了下没问题。我就用自己的文件做。结果出错了。我以为是我,命名错误,就按你的命名来做,结果还是错误。
    他没有出现错误提示。就是FK在移动的时候有部分功能不能完成。(说白点,就是手不可以弯曲了。)
    希望楼主可以解答我的问题。速求中。。。。。QQ402017170
    先在这谢谢拉。。。。

  24. 百味人生 says:

    忘记说下,IK控制器比你的多了一个属性 叫:Visitility 黄色的。。

  25. 百味人生 says:

    还有,我的shoulder rotation X跟Z方向为-0 你的是0。

  26. melone says:

    明白了,谢谢

  27. melone says:

    镀金柳丁

    得骨骼,IKControl一起K

  28. yezhipiao says:

    XRacZ,呵呵,先谢过你这篇文篇了
    我是新手,问个问题啊:
    有时候我将比如骨骼或簇Parent给其它物体为子物体时,为什么会在骨骼或簇之上自动生成一个transform#组节点啊??
    谢谢了

  29. yezhipiao says:

    这种情况不是每次都发生,只是偶尔,一直闹不清原因

  30. fp says:

    镀金柳丁想卖Victor Vinyals的技术教程赚钱,没问题,愿者自买。但看见别人发自己的经验无偿奉献给大家,就来搅和、贬损,好像rp有问题呀。正应了一句经典的话,自己rp丑没有关系,不知道自己rp丑还出来害人就是它的不对了。

    衷心谢谢楼主XRacZ,大家都拿一些自己的心得、经验来分享,你自己会提高的更快。

  31. XRacZ says:

    谢谢您的支持,我会再接再厉的!

  32. woerxi says:

    感谢你的分享!

Leave a Reply

Improve the web with Nofollow Reciprocity.