反向动力学,Inverse Kinematics,简称IK。简单地说,由父骨骼的方位和子骨骼的相对变换得到子骨骼的方位,称为正向动力学(Forward Kinematics,FK);而IK则是先确定子骨骼的方位,反向推导出其继承链上n级父骨骼方位的方法。
IK在游戏里最常见的应用是foot placement,就是当角色站在一个不平的表面上(台阶,斜坡)时,自动调整两脚的高低(当然,同时会影响小腿和大腿的姿态)以便看上去脚是真正“踩”在地面上的,而不是浮在空气中或者陷入地面以下。
如果不用IK的话,要解决这个问题就只能为所有可能的地形起伏情况制作不同的角色动作,其工作量是不可想象的。另外的应用就是象《波斯王子》,《古墓丽影》这样的游戏,经常会需要主角向前跃起然后抓住一样东西,比如一根旗杆。主角的弹跳能力通常是固定的,游戏也不可能要求玩家控制角色在一个精确的特定地点朝一个精确的特定方向跳跃,一般都是允许一个误差范围。那么问题就出现了,当主角飞到旗杆附近时,可能旗杆在头顶上,也可能在肩膀之下,或者偏左偏右都有可能,这时IK就可以使主角的双手自然地伸向旗杆,不管它在哪里(当然,必须physically possible,也就是在生理学上够得着的距离内)。
下面是去年写的一个demo视频
如何实现IK呢?最容易想到的是求解方程,但这样通常会得到无穷多的解。用自己的身体试验一下,即使手和肩膀都不动,小臂和大臂仍然可以自由灵活的转动,更不用说涉及超过2级骨骼的IK了。现在最常用的IK实现方法称为CCD(Cyclic Coordinate Descent,中文不知道叫什么),这是一种迭代的方法,在绝大多数情况下,目标骨骼的位置都会收敛到指定位置。见下图,即使不写程序,自己拿几根火柴棍也很容易验证这个算法的有效性。
对所有受IK影响的骨骼,按从子骨骼到父骨骼的顺序执行迭代操作:旋转当前骨骼,使当前骨骼位置到目标骨骼的连线指向IK目标位置。由于所有骨骼是从一个特定状态出发开始IK计算,所得到的结果也会比较稳定。通常5~10次迭代之后就能得到很好的结果。
目前为止,指定骨骼到达指定位置已经没问题了,但通常这是不够的。如果是人体骨骼的话,不是所有的关节都可以向任意方向旋转,所以我们必须对骨骼的旋转加以限制,比如肘关节实际上只有一个轴的自由度,而且不能向后弯曲。由于通常骨骼动画都是用四元数来表示旋转,而关节的角度限制只能用欧拉角来表示,所以在迭代过程中每次算出骨骼的旋转后都要转成欧拉角,看是否超过极限值,如果超过则需要校正,然后再转回四元数进行计算。
限制了旋转角之后,结果看起来就很好了。但是还有一个细节需要注意,当所有需要IK控制的骨骼正好在一条直线上,而IK目标位置正好在也落在这条直线上时(如下图),算法就会失败,因为不论迭代多少次,每一个骨骼都会认为自己不需要旋转。所以一个小技巧是,如果发现骨骼链“很直”,就向骨骼允许的任意方向加一些细微的旋转;或者干脆在骨骼的限制角度数据中就禁止完全“伸直”。