footIK 思路
CCD
算法核心思想:从链式骨骼的末端-1节点开始,每次让当前顶点和末端骨骼的向量,与当前节点与目标位置的向量重合,并且多次迭代。
具体核心算法如下:
for k in range(self.niterations):
for j in range(nbone-3, -1, -1): # 注意这个,逆序
grot, gpos = quat.fk(lrot, lpos, anim_data["parents"])
pos_begin = gpos[:, j] # 当前joint
pos_end = gpos[:, nbone-2] # end joint
v1 = quat.normalize( pos_end - pos_begin )
v2 = quat.normalize( pos_foot - pos_begin )
diff_rot = quat.normalize( quat.between(v1, v2) )
orot = lrot[:, j]
nrot= quat.normalize( quat.mul(diff_rot, orot) )
nrot = quat.slerp(orot, nrot, (1+j)/(nbone-2))
lrot[:, j] = quat.normalize( nrot )
注意点:
- pos_foot 就是目标位置,这里 nbone 正常是 -1 ,但是 -2 是因为我这里包含脚掌的骨骼,这个骨骼单独对齐一下
- 对于 目标位置要做合理的处理,尤其是处理算法结果脚滑的时候,其实主要是要修正 root/hip 的位置,然后再估计出合理的 foot 位置,再用这个算法
pytorch 优化思想
上述算法如果要拓展,避免不了走上加条件,然后求雅可比矩阵的路子。为了避免这样,可以用 pytorch 构造前向过程,然后自己加各种约束转换为 Loss。
具体可以参考这里的代码:InverseKinematics.
不过上述代码缺乏一些细节调整,一般还需要实现如下的优化:
1)子链优化:比如一般来说上半身是不需要优化的,只优化下半身
2)加权:不同骨骼有不同的权重,一般中间的骨骼没必要和旧位置保持一致
3)twist 惩罚,帧间平滑
其他方式
一个 c++ 的库
footskate