← ALL ARTICLES
动画系统3 MIN READ

面部动画

全库目录221
本文目录6

单独张嘴和单独微笑都正常,把它们同时打开却可能让嘴角塌下去。因为形状目标的差值线性相加,表情的真实组合却不是简单相加。我们先看形状数据怎样求值,再处理骨骼、组合修形和口型曲线,让几个控制器一起工作时仍能保持可读的表情。

形状目标

形状目标保存顶点相对基础网格的位置/法线/切线 Delta。运行时按权重累加:

p′=p0+∑iwiΔpi\mathbf{p}'=\mathbf{p}_0+\sum_i w_i\Delta\mathbf{p}_i

例如嘴角基础位置为(0,0,0),张嘴差值为(0,-0.01,0)米,微笑差值为(0.01,0.005,0)米。张嘴权重1、微笑权重0.5得到(0.005,-0.0075,0)。如果联合姿态的美术目标是(0.004,-0.006,0),修形差值应补(-0.001,0.0015,0)。差值针对这个组合制作,驱动权重减弱时再按项目曲线淡出。它不能由两份单动作数据自动推出。

它适合面部表情、口型和肌肉修形。目标数多时,逐目标读取完整稀疏 Delta 很浪费。可只保存受影响顶点、限制同时激活目标数,或在 Compute 中预合并结果。

形状目标强依赖顶点拓扑和顺序。重新拓扑、合并网格或改变导出设置后,旧目标通常无法直接复用。

形状目标求值

以下为单顶点求值的 C++ 算法片段,基础位置和形状差值位于同一模型空间。输入权重应符合项目的表情范围,输出再交给后续蒙皮或相应变形链。

cpp
Vec3 EvaluateMorph(Vec3 basePosition,
                   Span<const Vec3> positionDeltas,
                   Span<const float> weights)
{
    assert(positionDeltas.size() == weights.size());
    Vec3 position = basePosition;
    for (size_t targetIndex = 0; targetIndex < weights.size(); ++targetIndex)
    {
        position += positionDeltas[targetIndex] * weights[targetIndex];
    }
    return position;
}

法线和切线也有独立处理需求。组合形变并不保证拓扑不穿插,矫正目标与权重约束用于处理这些极值。用单目标、双目标和嘴唇闭合用例验证位置与法线;导出改变顶点顺序后必须重新建立目标对应。

面部 Rig

面部常组合使用:

  • 关节驱动眼球、下颌、眉毛和较大区域;
  • 形状目标驱动唇形、皱褶和非线性修形;
  • Corrective Shape 修复多个动作组合后的塌陷;
  • Wrinkle/流向图根据表情权重改变皮肤细节;
  • Look-at、眨眼和微表情由程序层控制。

FACS 可作为表情动作单元的共同语言,但项目仍需要自己的命名、范围和组合约束。直接让几十个控制器自由相加会出现穿插和不自然极值。修形目标可以由两个动作的联合激活量驱动,例如以平滑后的 jawOpen * smile 作为输入,再用项目曲线决定强度。这个乘积只是驱动示意,最终差值仍要在组合姿态中制作和验证。

音素到 Viseme 的映射只给出嘴形基础。自然口型还依赖协同发音、语速、情绪、下颌和面颊联动。自动生成结果需要可编辑曲线和人工修正入口。

Live2D 用分层二维纹理网格、参数变形和遮罩组织角色表情与姿态。运行时根据角度、眼睛、嘴形等参数插值顶点变形,并按层级和裁剪关系合成。它保留二维原画风格,但仍需要统一参数命名、变形范围、绘制顺序和移动端纹理预算。

组合修形必须和差值所在空间一致。先在绑定模型空间叠加嘴角差值,再蒙皮,和先蒙皮后叠加同一数值并不等价:后一条路径会让差值保持旧方向。若项目确实需要蒙皮后修形,就以该阶段姿态重新定义差值和驱动坐标。可把头部旋转 90° 后重放张嘴动作,观察修形是否随头部一起转动。

验证方法

  • 测试单目标极值、两两组合、口型切换和眼球跟随。
  • 改导出拓扑后检查所有形状目标的顶点对应。
  • 记录同时激活目标数、变形时间和内存。

相关主题

参考资料