← 返回图形编程

FK/IK 与蒙皮编辑器

正向/逆向运动学与蒙皮编辑器,及 Unity Foot-IK 插件

日期 2024年12月
标签
c++openglunity

概述

这是我在计算机动画课上用 C++ 和 OpenGL 写的一个 FK/IK 与蒙皮项目:正向运动学、limb-based IK 求解器、CCD IK 求解器,以及自动皮肤绑定加线性混合蒙皮。同一套核心我还编译成了 Unity 原生插件,给行走角色做随地形自适应的 Foot IK。

0:00/0:00
FK 播放、Limb-based 与 CCD 逆向运动学、线性混合蒙皮(注:录制时因打印语句导致帧率偏低,正常情况下可达到显示器最高刷新率)

正向运动学

骨骼是一棵关节树。每个关节只存相对父级的变换,FK 从根节点遍历整棵树,把每个关节的局部变换乘上父级的世界变换,得到全局位置和朝向。两个 IK 求解器、蒙皮和 Unity 插件读的都是这些世界变换,所以在任何位置改一个局部旋转,下面的整个子树都会跟着动。

Limb-Based IK

手和脚用解析的两骨骼求解器。基关节、中间关节和目标点构成一个三角形,所以肘/膝的角度直接由余弦定理得出。基关节到目标的距离会被限制在骨骼链的总长度以内:目标够不到时肢体伸直,而不会算出 NaN。然后在基关节上再做一次轴角旋转,把整条肢体转过去,让末端落到目标点上。

CCD IK

Cyclic Coordinate Descent 对任意长度的链都适用,最长可以从末端一直到根。每一轮从链的末端往根的方向走:

  1. 在全局空间里算出能把当前末端位置转向目标的旋转轴和角度。
  2. 把这个轴换算到该关节的局部坐标系。
  3. 作为四元数增量叠加上去,然后处理父关节。

如此反复,直到末端与目标的距离在容差以内。它没有 limb 求解器那样的闭式解保证,但可以弯脊椎、尾巴这类东西,而且因为从末端开始扫,运动会分散到整条链上,而不是全堆在根部。

皮肤绑定

绑定这一步自动给每个顶点分配关节权重。每个关节根据到最近顶点的距离得到一个绑定半径,再乘上用户设定的系数。对每个顶点:

  1. 找到最近的关节。
  2. 把顶点投影到从该关节指向父关节的骨骼上,以此判断顶点在关节的哪一侧。
  3. 在半径以内,权重按归一化距离在关节和父关节之间线性混合;在半径以外,完全归到其中一边。

没有这个衰减的话,两根骨头的影响会在一条硬边上突然切换,肘部和膝盖就会出现折痕。

线性混合蒙皮

绑定时把每个关节全局变换的逆存为绑定矩阵,它把顶点从模型空间变到该关节的局部空间。每一帧,每个顶点把自己受到的影响求和:

newPosition = sum( weight_i * (jointGlobal_i * bindMatrix_i) * restPosition )

每一项先把顶点从绑定姿态带进关节空间,再经关节当前的姿态带出来。权重决定顶点继承每根骨头多少运动。法线走同样的求和,但只用每个矩阵的旋转部分,这样网格变形时光照仍然正确。

Unity Foot-IK 插件

C++ 核心被编译为 Unity 原生插件,驱动一个在起伏地形上行走的角色。一个投影到地面的引导关节把角色引向目标,行进方向用最短弧四元数旋转。每一帧:

  1. 采样每只脚下方的地形高度。
  2. 把根关节降低到两个高度中较低的那个,这样支撑腿永远不需要伸到超出它能到的范围。
  3. 对每条腿运行 limb IK 求解器,把脚拉到各自的接触点。
  4. 可选地让每只脚旋转到与接触点处的地形法线一致。
0:00/0:00
Unity Foot-IK 插件

使用工具

C++、OpenGL、Eigen、ImGui、Unity、CMake