由于几个原因,这是一个重要的问题。
首先,矩阵的欧拉化会产生许多无法正确插值的有效解(如果您曾经在 Maya 图形编辑器中使用过空白欧拉过滤器,您就会明白我的意思)。有许多欧拉组合会产生给定的四元数或旋转矩阵。这意味着很难创建一个涵盖所有可能性的确定性解决方案。
其次,样条曲线的切线是一个向量,但是如果没有至少一个其他向量来为解决方案增添趣味,就不能将向量转换为矩阵。如果您熟悉 Maya 的样条线 IK 以及为扭曲控制找到合适的参考框架的复杂性,您会在此处看到相同的问题。
第三,对于这个目的最重要的是:twist 不能表示为 3d 空间中的旋转 - 它是原始曲线的非欧几里德空间中的相对旋转,不对应于一致的世界空间矩阵。
如果你想处理扭曲,你需要为你想要采样的曲线上的任何点构建一个参考框架变换,并且你需要提供一些额外的信息来开始它。由于扭曲是相对的,因此您需要提供一个起点来测量扭曲。您会注意到所有用于沿曲线(运动路径、样条线 IK)工作的原生 Maya 工具都会执行此操作。
创建矩阵非常简单。获得曲线切线的归一化向量,以及“向上向量”的另一个。向上向量是您必须按照惯例定义的东西 - 这就是为什么所有使用曲线几何切线的 Maya 工具都需要您选择或提供一个。如果您的曲线或多或少位于 XZ 平面上,则可以使用世界上矢量。如果它或多或少是垂直的,您可以使用 X 或 Z。无论如何,您需要标准化的向上向量。您的“边”向量,即最终矩阵的局部 z 轴,是切线向量和边向量的叉积。现在将原始向上向量替换为切线和侧向量的交叉向量(否则您的矩阵将被剪切)。最后,
现在像这样组装你的矩阵:
tangent.x tangent.y tangent.z 0
up.x up.y up.z 0
side.x side.y side.z 0
pos.x pos.y pos.z 1
这会在采样点创建一个矩阵,局部 x 指向曲线切线,局部 y 或多或少指向原始向上向量。在该矩阵的上下文中,扭曲轴是局部 X 旋转。通过创建两个变换更容易控制扭曲:使用此矩阵提供参考框架的父级和锁定在 Y 和 Z 上且仅在 X 上旋转的子级。切线框架矩阵中的欧拉数不会扭曲值 - 在这种情况下,twiat 是一个完全相对的概念,不能用单个矩阵表示!
老实说,对于这种事情,使用内置工具可能更容易解决。我会尝试使用运动路径将参考变换(关节或定位器)约束到曲线:Animation>Motion Paths>Attach to Motion Path。默认情况下,这将满足您的要求,您的 X 轴将是曲线的切线,而 Y 将是世界上的。您可以将第二个关节作为第一个关节的父节点(局部归零),它的局部 X 将是扭曲轴,您可以锁定其他两个轴并使用该值。
根据曲线的形状,您可能会遇到两组不同的问题。如果您的向上向量太接近曲线的方向,则解是不稳定的。您可以通过选择不同的“向上”向量来解决这个问题——对于垂直方向的曲线,您可以使用世界 Z 而不是世界 Y。但是,如果曲线在所有 3 维中循环,则没有数学上完整的解决方案。
第二种策略是使用拉伸几何体来提供“向上”向量。如果沿着原始曲线拉伸一条线段,形成一条带,原始曲线作为 V=0 等参线,那么在曲线上的任何点,您都可以使用 U 等参线作为向上向量。这样您就可以看到并在必要时纠正沿曲线的扭曲以避免翻转和摆动——否则在这种情况下这将是很常见的。您可以使用 pointOnSurface 命令从曲面上抓取矢量。只要您的拉伸具有历史记录,您就可以编辑或动画原始曲线,并且此解决方案仍然有效。
更新
回应OP的进一步信息:
1)我不会太担心非常大的旋转。正如 jooja 指出的那样,这在您需要建模的现实世界中没有确切的含义——实际上,只有非常特殊的角色才会需要它。手腕扭转旋转的生物学极限小于 +/- 90,而在肩部则更小。卡通人物可以超越这一点——但可能只是在扭曲橡皮筋特效的背景下,而不是通用装备。
2) 欧拉扭曲相对温和,即使对于 3 轴关节,只要它是第一个欧拉项(即,XYZ 旋转中的 X)。如果您的手臂在没有任何额外的关节方向沿第一轴布置时,您可以通过仅跟踪第一个欧拉旋转来测量累积的扭曲(即,对于 XYZ 骨骼,链是沿局部 X 布置的零旋转关节的直线长度)。在该配置中,很容易添加存根骨骼以使用简单的表达式或基于节点的数学来抵消扭曲旋转。您可以将扭曲旋转分布在多个骨骼上以保持平滑(尽管使用现代双四元数蒙皮这不是问题,肩部和手腕周围的两三个骨骼可能就足够了)。由于骨骼是存根,因此它们无需进行复杂的 3d 数学运算即可计算出扭曲:例如,与肩部的 x 旋转相比,二头肌中的一根骨骼从肩部传播扭曲,它仅旋转 (-.5 * x) 之类的东西。您对存根骨骼而不是主线骨骼进行蒙皮,因此您会得到主骨骼的 YZ 旋转,但得到存根的调制 X 扭曲。
这种安排的主要缺点是你的绑定姿势也不能是你的归零姿势:你需要沿着链的局部轴在“未扭曲”状态下是连续的——这意味着你的肩部的 0,0,0是与世界 X 对齐的刚性 T 姿势,而不是大多数模型所获得的更放松的姿势。动画师往往不喜欢那种零姿势(当然,如果你要匹配现有的模型,你别无选择)。但是,您可以使用 dagPose 提供替代的零姿势,这些姿势实际上是归零的,但确实将角色放回中性姿势。