FK/IK 与蒙皮编辑器
正向/逆向运动学与蒙皮编辑器,及 Unity Foot-IK 插件
概述
这是我在计算机动画课上用 C++ 和 OpenGL 写的一个 FK/IK 与蒙皮项目:正向运动学、limb-based IK 求解器、CCD IK 求解器,以及自动皮肤绑定加线性混合蒙皮。同一套核心我还编译成了 Unity 原生插件,给行走角色做随地形自适应的 Foot IK。
正向运动学
骨骼是一棵关节树。每个关节只存相对父级的变换,FK 从根节点遍历整棵树,把每个关节的局部变换乘上父级的世界变换,得到全局位置和朝向。两个 IK 求解器、蒙皮和 Unity 插件读的都是这些世界变换,所以在任何位置改一个局部旋转,下面的整个子树都会跟着动。
Limb-Based IK
手和脚用解析的两骨骼求解器。基关节、中间关节和目标点构成一个三角形,所以肘/膝的角度直接由余弦定理得出。基关节到目标的距离会被限制在骨骼链的总长度以内:目标够不到时肢体伸直,而不会算出 NaN。然后在基关节上再做一次轴角旋转,把整条肢体转过去,让末端落到目标点上。
CCD IK
Cyclic Coordinate Descent 对任意长度的链都适用,最长可以从末端一直到根。每一轮从链的末端往根的方向走:
- 在全局空间里算出能把当前末端位置转向目标的旋转轴和角度。
- 把这个轴换算到该关节的局部坐标系。
- 作为四元数增量叠加上去,然后处理父关节。
如此反复,直到末端与目标的距离在容差以内。它没有 limb 求解器那样的闭式解保证,但可以弯脊椎、尾巴这类东西,而且因为从末端开始扫,运动会分散到整条链上,而不是全堆在根部。
皮肤绑定
绑定这一步自动给每个顶点分配关节权重。每个关节根据到最近顶点的距离得到一个绑定半径,再乘上用户设定的系数。对每个顶点:
- 找到最近的关节。
- 把顶点投影到从该关节指向父关节的骨骼上,以此判断顶点在关节的哪一侧。
- 在半径以内,权重按归一化距离在关节和父关节之间线性混合;在半径以外,完全归到其中一边。
没有这个衰减的话,两根骨头的影响会在一条硬边上突然切换,肘部和膝盖就会出现折痕。
线性混合蒙皮
绑定时把每个关节全局变换的逆存为绑定矩阵,它把顶点从模型空间变到该关节的局部空间。每一帧,每个顶点把自己受到的影响求和:
newPosition = sum( weight_i * (jointGlobal_i * bindMatrix_i) * restPosition )
每一项先把顶点从绑定姿态带进关节空间,再经关节当前的姿态带出来。权重决定顶点继承每根骨头多少运动。法线走同样的求和,但只用每个矩阵的旋转部分,这样网格变形时光照仍然正确。
Unity Foot-IK 插件
C++ 核心被编译为 Unity 原生插件,驱动一个在起伏地形上行走的角色。一个投影到地面的引导关节把角色引向目标,行进方向用最短弧四元数旋转。每一帧:
- 采样每只脚下方的地形高度。
- 把根关节降低到两个高度中较低的那个,这样支撑腿永远不需要伸到超出它能到的范围。
- 对每条腿运行 limb IK 求解器,把脚拉到各自的接触点。
- 可选地让每只脚旋转到与接触点处的地形法线一致。
使用工具
C++、OpenGL、Eigen、ImGui、Unity、CMake