为绑定器未提供骨骼的尾巴制作动画
作者:Oleg Sidorkin,Cinevva CTO 兼联合创始人
2026 年 9 月 11 日更新:这只鼠类角色教会了我们什么,新增弹性弯曲、地面接触,以及第二种由尾巴引起的身体抬升问题。
一位用户使用我们的绑定器为一只拟人狐狸完成了绑定,并播放了 Walk 动画片段。身体表现正常。尾巴却像湿毛巾一样折叠在左腿旁,而在左右腿权重相接的地方,网格发生了撕裂。下面将一直以这只狐狸为例;相关修复现已上线到绑定器,以及负责播放其动画片段的运行时库中。
本文中的狐狸和鼠类角色均由我们的 3D 模型生成器生成,随后在 Cinevva 中完成绑定和动画制作。

从左到右,三者都处于同一帧的迈步中段:绑定器直接输出的绑定;将整条尾巴作为一个整体交给骨盆控制的同一绑定;以及拥有独立骨骼链、由运行时驱动摆动的尾巴。你可以在下文环绕查看全部三个版本。
为什么人形绑定器会产生这种结果
我们的 Fast 引擎基于 Make-It-Animatable 构建,它预测的是固定的 Mixamo 风格骨架:22 根身体骨骼,包含手指时则为 65 根。网格中的每个顶点都必须分配给这些骨骼中的一根。列表中没有尾巴,因此模型只能采取它所知的次优方案:把尾巴顶点交给在其学习到的特征空间中最接近的身体部位。对于这只狐狸,那个部位是左小腿,其余权重则分散在两侧大腿上。
这并不是权重中的缺陷,而是模板本身的限制。无论使用什么提示词或设置,都无法让模型输出尾骨,因为它根本没有可供输出的尾骨。翅膀、披风、长发以及其他从躯干延伸出来的结构也会遇到同样的问题。
在进行任何修改之前,我们先测量了狐狸尾巴上 1,582 个顶点所付出的代价。每个顶点到实际驱动它的骨骼之间的距离,按权重加权后,在这只身高 191 厘米的模型上平均为 47 厘米。也就是说,尾巴正被半米之外的骨骼驱动。
找到尾巴
此时我们手中只有完成绑定的 GLB,而这已经足够。这个处理步骤可以用于任何绑定器的输出,而不仅限于我们的绑定器。
骨架上的距离场。 对于绑定空间中的每个顶点
而一个顶点的骨架距离,就是它到所有线段距离中的最小值。对于叶节点关节,我们会在关节末端之外补上一小段,以免口鼻部或手部被判断为远离自身骨骼。当该距离超过模型身高的 7% 时,顶点就属于远端顶点。对这只狐狸而言,阈值为 13 厘米。
远端蒙皮的连通区域。 我们沿网格自身的面,将远端顶点分组为若干连通分量。有个细节让我们多花了一个小时:导出器会在 UV 接缝和硬法线接缝处分裂顶点,因此这个网格有 23,129 个顶点,却只有 29,081 个三角形;如果只使用面图,一条尾巴就会被拆成几十个孤岛。我们先按位置焊接顶点,在焊接后的图上计算连通性,再将权重写回每个原始顶点。
它连接在哪里? 一个区域的领口,是与其相邻的非远端顶点所组成的环。领口中心可以通过寻找最近关节来告诉我们该区域从哪里悬挂下来,不过我们加入了一项偏置:如果躯干或大腿关节与领口中心的距离不超过最近距离的 1.5 倍,就优先选择该关节。因为在骨盆附近,大腿根部与髋部的距离几乎完全相同,而位于两者之间的尾根应当归属于身体。我们刻意不信任领口上的权重。对于作为独立壳体建模的尾巴(大多数游戏模型都是如此),所谓领口其实就是尾巴自身的根部环,它携带的仍然是我们正要修复的错误权重。
它是附肢还是身体? 我们使用两项测试。较粗躯干上的远端蒙皮会包围骨骼,因此其质心仍会落回骨骼附近。尾巴则会向一侧伸出,所以质心会远离所有骨骼。我们要求质心到骨架的距离至少达到该区域延伸长度的 40%。然后进行形状测试:令
狐狸的尾巴由两个相互重叠的壳体组成(毛发覆盖在皮肤之上,彼此从未焊接),因此,如果连接在同一位置的多个区域,其包围盒重叠超过一半,我们就将它们合并。一条尾巴,一条骨骼链。
第一步:让尾巴成为刚体
最直接可靠的第一步修复只需一个下午。该区域的每个顶点都在 Hips 上获得 1.0 的权重。尾巴不再撕裂,而是作为一个整体随骨盆移动。它看起来像块木板,也就是图片中间的那只狐狸。我们把这个版本作为一个里程碑发布,因为按照构造方式,它的拉伸值严格为零,因此可作为下文测量中的实用参照。
第二步:沿尾巴生成骨骼链
沿尾巴的坐标。 我们从领口开始,沿以边长作为权重的网格边,对该区域运行 Dijkstra 算法。每个尾巴顶点都会获得距根部的测地距离
关节。 分段数量为 Tail_1 到 Tail_K,再加上一根无权重的 Tail_End;它们以 Hips 为父级,共享 Hips 的绑定旋转,因此每根骨骼在其父级坐标系中都只是一次纯平移。由此可以直接得到它们的逆绑定矩阵;现有动画片段从未引用这些骨骼,因此下游流程不会被破坏。
权重。 令
在关节处,两根骨骼各占 50%;在分段中部,则由一根骨骼完全控制蒙皮。对于根部分段,“prev”是 Hips,因此尾巴会平滑融入身体,而不是在领口处产生折痕。
处理完成后,尾巴上按权重计算的骨骼距离从 47 厘米降至 17 厘米,大致相当于尾巴自身的半径。对蒙皮而言,这已经接近它与驱动骨骼之间所能达到的最短距离。

第三步:必须有东西驱动骨骼
我们的动画库中没有任何片段包含尾巴轨道,因此如果不做额外处理,骨骼链就会保持绑定姿势,狐狸也会拖着一块木板到处走。游戏通常使用程序化的次级运动来解决这个问题,我们也一样:它位于每个已绑定模型都会加载的运行时库中。
每个关节尖端都是一个位置为
其中
由于粒子存在于世界空间中,髋部转向或加速时,尾巴会滞后并自行摆动。没有任何运动是预先编排的。
这里有三个错误值得坦白,因为每一个在被测量之前看起来都没问题。
第一个版本每帧让粒子以固定比例靠近目标:在 60 fps 下是 12%。把它写成弹簧形式,就是
第二个版本把绳索修正量除以
第三个错误与下文的抬尾角度有关。它被应用在每个关节自身的坐标系中,因此一条四骨骼尾巴会被连续抬升四次,最终蜷成一团贴在狐狸背上,并在每个弯折处撕裂自身蒙皮。正是下文的测量发现了这个问题:尾巴边缘拉伸的 p99 达到 2.3,而身体基准为 1.3,甚至比最初绑定到小腿时更糟。现在,carry 表示整条尾巴的抬升量,并由所有关节共同分担。
穿模。 这条尾巴建模时笔直垂在两腿之间,而步行动画会让双脚穿过它。因此,弹簧所追踪的静止姿势并不是网格自身的姿势:carry 设为 50°,会让静止目标围绕髋部的侧轴向后、向上抬起,就像狐狸移动时抬起尾巴那样。这 50° 是整条尾巴的总抬升量,由各关节共同分担,因此无论骨骼链最终有四根还是八根骨骼,弧线都会保持平缓。此外,任何粒子都不得穿过经过尾根、朝向前方的平面,因此尾巴绝不可能摆进两腿之间。
测量结果
以下是 9 月 6 日获得的原始狐狸测量结果,采集时间早于下文针对鼠类角色所做的修改。它们记录的是第一版骨骼链求解器,而不是使用新版默认设置重新进行的基准测试。
静态图片无法证明网格不会撕裂,所以我们测量动画片段播放期间的边拉伸。对于两个顶点都位于尾巴上的每条网格边,我们在 Walk 动画片段中均匀选取 24 个时间点,计算其蒙皮后长度与绑定姿势长度之比。比值为 1 表示蒙皮未变形。拉伸超过 1.5 或压缩至低于 0.67 的边会被视为撕裂。身体边也使用相同方式测量,以作为正常蒙皮变形的基准。
| Walk 动画片段,96,864 个尾巴边样本 | p95 | p99 | 最大值 | 撕裂 |
|---|---|---|---|---|
| 原始绑定 | 1.60 | 2.42 | 4.03 | 11.4% |
| 刚性绑定到 Hips | 1.00 | 1.00 | 1.00 | 0% |
| 尾巴骨骼链 | 1.09 | 1.18 | 1.30 | 0% |
| 身体,作为参照 | 1.13 | 1.29 | 1.78 | — |
原始绑定中,每九条尾巴边就有一条被拉伸到撕裂程度,而最严重的一条达到了绑定长度的四倍。骨骼链版本最严重的边仅比原长多 30%,仍低于身体自身 1.78 的基准上限,并且没有任何撕裂。刚性尾巴严格保持在 1.00,因为它作为一个整体移动;正是这个数字让我们在把测试结果应用到骨骼链之前,确认测量工具本身是正确的。
真正会摆动的尾巴必须让自身蒙皮发生少量变形,因此骨骼链的目标并不是达到 1.00,而是把变形控制在身体原本已有的范围之内。此表的早期版本显示骨骼链的 p99 为 1.03,看起来更好,实际却更差:尾巴几乎没有移动,因为上述速度缺陷造成了过度阻尼,使它的表现接近刚性版本。
实时对比
三只狐狸,使用相同动画片段和相同帧。拖动以环绕查看,滚轮缩放。你可以切换动画片段;关闭尾巴物理效果,查看骨骼链抬起后的静止姿势;也可以显示骨骼,观察骨骼链的位置。
从侧面单独观察同一条骨骼链,并显示骨架。`Sprint` 是最能体现弹簧效果的动画片段。老鼠带给我们的启示
狐狸证明了骨骼链可以避免网格撕裂。老鼠的尾巴又细又长,让剩余的运动问题变得更容易观察。狐狸尾巴上藏在毛发中的急弯,到了老鼠身上就会像关节折断一样明显。老鼠的尾巴还会触及地面,而且建模出的形状会偏向一侧卷曲。这是三个不同的问题;单纯提高弹簧刚度并不能全部解决。
请在下面的动画库中尝试为老鼠应用不同动画。拖动角色可以环绕查看,横向滚动缩略图栏,或使用搜索和分类筛选器查找动作。点击动画卡片即可在大预览区中播放。检查尾巴时,可以先从 Walk、Crouch Backward、Crawl Idle 和 Back Flip 开始。缩略图栏使用与动画页首展示区相同的实时动画预览,并提供完整目录,浏览时会按需加载动作。
打开完整动画库 →,在你自己的绑定角色上尝试这些动作,并导出所选动画片段。
弹簧链仍然需要抗弯约束
粒子受到约束,以保持每根骨骼的长度,但各个关节仍然几乎可以独立摆动。长度约束可以防止拉伸,却无法阻止铰链式关节折叠。老鼠恰好暴露了这一区别。

修复之前:仅仅保持各段长度不变,还不足以让曲线保持平滑。
现在,我们会耦合相邻关节相对于静止曲线的额外弯曲。系统在同一个参考坐标系中比较这些弯曲,因此即使骨骼轴向不同,也不会把一个关节上的左弯误当成下一个关节上无关的扭转。每一步都会读取相邻关节的快照,而不是读取已被部分更新的值。耦合混合系数为
关节的弹性弯曲最多可超出静止方向 30°。我们还将阻尼提高到 0.65,并移除继续推向弯曲限位的速度,以免速度不断积累后突然释放,产生抽动。尾巴根部仍由髋部支撑,末端则保持更柔软。需要让尾巴平放在地面上时,接触约束可以覆盖弯曲限制。
耦合旋转,而不是粒子位置。 将
这里的共轭运算会改变弯曲所在的坐标系;它不会给角色额外添加一次旋转。使用上一步中的快照
在根部,相邻目标位于下一个关节的弯曲与单位四元数
对于标量分量为
我们先将这次弯曲变换回父级坐标系并应用到
加载的姿势不一定是绑定姿势
老鼠保存的文件中,尾巴最后一个关节已经带有约 28° 的旋转。我们却把加载时的旋转当作中立姿势,然后在此基础上叠加弹簧运动。于是,先前的动画姿势或导出姿势永久成为了弹簧目标的一部分。
现在,只要骨架提供了逆绑定矩阵,求解器就会从中恢复中立的局部变换。如果绑定没有 Tail_End 辅助骨骼,最后一段将沿入射切线继续延伸,并将其表示在最后一根骨骼自身的局部坐标系中。只要末端骨骼的朝向与父级不同,直接从父级坐标系复制向量就是错误的。
单侧卷曲还有另一个原因:实际绑定几何体本身就带有这种形状。因此,正确恢复绑定姿势也会保留这种偏向。现在,模拟默认使用以髋部空间构建、再转换到各个已校正父级坐标系中的居中静止弧线。restCurve 可以将建模时的卷曲混合回来:0 表示居中弧线,1 表示保留创作时的曲线。这会改变弹簧趋向的目标,但不会重写网格或其蒙皮权重。
恢复参考变换。 令
分解
构建居中弧线。 令 restCurve,
这里,
尾巴可以接触地面,但不能把老鼠抬起来
地面接触会将连接段旋转到其长度球面与地面的交线上。简单限制粒子的高度会缩短骨骼;先限制高度再恢复长度,又可能让它重新钻入地下。我们在中心线下方预留 0.025 个世界单位作为尾巴厚度,去除向下的接触速度,并对滑动施加阻尼。平坦地面默认为世界坐标 Y = 0,也可以移动或禁用。这是一个平面约束,而不是地形或完整网格碰撞。
球面与地面的交线。 令
如果预测端点低于地面,定义
它的高度恰好为
执行其他速度投影后,接触中的粒子会移除剩余的向下速度,并对速度施加阻尼:
这是带有简单阻尼的非弹性接触,而不是库仑摩擦模型。它可以防止尾巴停在地面上时,重力继续积累向下速度。
这解决了尾巴穿透地面的问题,但还有另外两个地方可能让尾巴把脚抬离地面。
首先,查看器会将整个已加载网格的最低点放到地面上。如果保存的尾巴垂到了脚底以下,它就会抬高整个角色来容纳尾巴。现在,查看器在确定身体地面高度时会忽略以尾巴蒙皮为主的部分,但相机取景仍会包含整个角色。
其次,重定向器的身体贴地流程也把尾巴计算在内。在 Back Flip 期间,它会抬高骨盆以避免尾巴蒙皮穿地,尽管独立的尾巴求解器随后还会移动尾巴。
哪些蒙皮点可以抬高骨盆? 令
这里,
在下面的对比中,报告的额外抬升量是最终骨盆轨迹之间的差值,而不仅仅是原始校正量:
Back Flip 末段实测的骨盆抬升量
我们在相同动画时间点对同一只老鼠进行采样,仅改变身体贴地计算是否包含尾巴。两列都使用相同的模型世界坐标;两者之差只反映将尾巴计入后引入的额外高度。
| 1.93 秒动画片段中的时间 | 骨盆高度:计入尾巴 | 骨盆高度:排除尾巴 | 计入尾巴造成的额外抬升 |
|---|---|---|---|
| 1.16 s | 50.5 cm | 35.0 cm | 15.4 cm |
| 1.55 s | 81.3 cm | 70.3 cm | 11.0 cm |
| 1.84 s | 92.2 cm | 77.2 cm | 15.0 cm |
| 1.93 s | 90.6 cm | 77.2 cm | 13.4 cm |
角色落地后站起时,本来就应该升高。错误在于最后一列中的额外抬升,而不是预期中的起身动作。数值分别根据采样的世界位置独立四舍五入。
对于这只老鼠,排除尾巴后,Back Flip 后段的骨盆额外抬升减少了约 15 cm。接近动画末尾时,身体探测点与参考地面的距离保持在约一毫米以内,而不是悬浮在地面上方数厘米。现在,尾巴蒙皮既不会定义身体的地面高度,也不会参与抬高骨盆的校正。尾巴求解器本身只会旋转尾巴骨骼;它绝不会平移模型、髋部或双脚。
动画甚至可能在播放前就继承一个姿势
抬高的下蹲姿势暴露了另一个问题。我们会逐步生成动画库中的片段,以便查看器在所有片段准备完毕前就能开始播放。重定向和播放共用了同一套骨架。在两次求解之间,预览可能移动骨盆,而下一个动画片段会把这个已产生动画的姿势当作校准参考。切换动画片段时重置姿势,也无法修复已经烘焙进生成轨道中的错误参考。
现在,重定向会使用私有骨架副本,这些副本来自播放开始前捕获的稳定校准状态。后续的动画片段请求会复用这一参考,并发请求则各自使用独立骨骼。回归测试会在两个已交付片段之间故意移动和旋转实时髋部;生成的轨道必须与干净运行的结果完全相同,而且求解过程不得改变实时姿势。 并非每个可见的动作都是 bug。Climb Idle 的源循环中带有轻微的骨盆上下起伏,而根骨保持静止。重新求解的 Crawl Idle 在整个循环中都让老鼠的双手保持在头部下方;双手抬起的截图与先前受污染的动画片段一致,并不能证明源动画原本就需要这个姿势。通过对比源动画、重新求解的结果和实际播放效果,我们避免了为了掩盖校准错误而抹平有意设计的动作。
我们现在检查什么
检查项涵盖不同长度骨骼链上的快速髋部摆动、相邻骨骼间更平滑的弯曲、左右两侧一致的响应、绑定姿势的恢复、没有辅助骨骼时发生旋转的末端骨骼,以及预热后的循环闭合。地面测试涵盖下蹲、抬高的地面平面、尾巴落地后的稳定,以及髋部升高时解除接触。单独的回归测试会验证尾巴接触绝不会带动身体,也会验证尾巴蒙皮不能请求抬高骨盆。
这些检查确立了明确的不变量。它们无法取代亲眼观察老鼠完成各种动作,也没有为狐狸确立新的拉伸数值。在线示例使用的是修改后的求解器;先前的狐狸数据表仍保留为原始测量记录。
这对你有什么影响
如果你在 cinevva.com/tools/rigger 为带尾巴的角色绑定骨骼,尾巴会拥有自己独立的骨骼链,任务状态中会包含一个描述检测结果的 appendages 条目,预览也会让尾巴摆动。通过平台 API 绑定的模型会得到相同的文件。rt/1.1.12 中的初始集成让 createAnimator 能够查找 Tail_* 骨骼并直接驱动它们,无需额外代码;如果你想要更沉重或更慵懒的尾巴,可以调整弹簧的频率、阻尼、重力和携带角度。没有尾巴骨骼链的旧文件可以重新绑定,再运行一次该处理流程。上文所述的 9 月 11 日改动现已部署到 Cinevva 的网页预览中。固定使用旧版运行时的游戏和之前导出的动画片段不会自动更新。现有的烘焙动画片段需要重新生成,才能应用这些修复。
在 Blender 中。 插件 会运行相同的处理流程:它会先在骨架表上完成处理,再构建骨架,因此在你自己的电脑上绑定的尾巴会以相同名称获得相同的骨骼链。Fingers 旁边有一个 Tail 复选框,结果卡片会显示检测到了什么。
在我们的运行时之外。 对于在 Blender、Unity 或 Unreal 中打开文件的人来说,游戏里的弹簧系统帮不上忙,因为尾巴在那里会静止不动。因此,导出时现在会烘焙尾巴动画:系统会模拟每个选中的动画片段,并将尾巴的旋转采样为真正的关键帧。导出器会先静默运行该动画片段,直到尾巴回到处理开始时的位置,然后才开始录制,因为从冷启动状态烘焙的循环无法闭合,尾巴会在循环时突然跳动。尾尖有意设计成最柔软的一节,因此它的瞬态过程最慢才能稳定下来,只进行一次预热并不总是足够。
这一处理流程刻意采取了保守策略。它只会为从骨盆处垂下的细长部位生成骨骼链。耳朵、头发和袖子不会被改动,躯干上的任何宽大片部位也一样:早期版本曾把斗篷或裙子刚性地交给躯干骨骼控制,但观察它在真实上传模型上的运行效果后,我们改变了主意。其中一个案例是腰部一件有 6,540 个顶点的服装,绑定器已合理地将其权重分布到髋部和两侧大腿;改用单根骨骼会让它完全无法随腿部运动。仅凭对部件类型的猜测,就把一件服装交给单根骨骼控制,会对用户的角色造成很大改动,因此这现在是一项需要你主动选择的功能,而不会擅自发生。除了前向平面之外,尾巴不会与腿部发生碰撞;角色静止站立时也不会有待机摆动,因此站立狐狸的尾巴会安静地垂在其携带姿势上。这是接下来要处理的两项内容,此外还包括以类似方式处理翅膀——翅膀需要不同的静止姿势和不同的弹簧。