动画姿态混合
全库目录221
本文目录14
从走路切到跑步,直接播放另一个动画片段会让脚步和姿态跳变。姿态混合先对齐动作相位,再在局部TRS中合成基础、加法和骨骼层,最后累积层级。动作规则与根运动所有权保持明确,才能避免脚滑和重复位移。
基础姿态生成
动画片段采样
动画片段保存多个关节或属性随时间变化的轨道。运行时根据归一化时间找到相邻关键帧,对平移/缩放做 Lerp,对旋转做 Nlerp 或 Slerp。
动画片段需要明确:
- 采样率和是否循环;
- 根运动轨道;
- 事件与曲线;
- 起止姿态是否连续;
- 参考姿态和骨架版本。
高采样率不保证更好。源动画频率、压缩误差和最终动作速度共同决定所需采样密度。
状态机
状态机把 Idle、Walk、Run、Jump、Attack 等动作组织成状态和过渡。过渡一般依赖参数、事件、退出时间和优先级。
例如移动参数在阈值附近往复变化,Walk到Run的过渡尚未结束就被Run到Walk打断。若每次重置混合进度,角色会长期停在中间姿态。过渡需要定义打断时从当前合成姿态继续,还是回到原片段,以及速度阈值是否使用滞回区间。动画事件又反向修改同一玩法状态时,还需跟踪事件的来源片段,避免淡出片段重复触发切换。
复杂系统可把玩法状态与姿态生成分开。玩法决定意图和标签,Animation Graph 负责选择、混合和修正动作。
连续姿态组合
交叉淡入淡出
两个姿态的局部 TRS 按权重混合:
旋转通常用 Nlerp/Slerp。对共享固定局部平移、单位缩放的骨架,先混合局部旋转再累积层级,能够保持骨长。若轨道本身改变平移或缩放,混合结果也会改变长度,需要按动画契约限制或验证。
线性权重不一定产生自然速度。Ease 曲线能让过渡的起停更柔和,但打击动作可能需要短而明确的过渡。
还要处理两段动作的相位。例如同一只脚在走路片段中相对髋部向前0.3米,在跑步片段中向后0.3米;各取一半得到0,脚停在髋下,两个输入里的迈步都被抵消。可用同步 Marker 或归一化步态相位对齐脚步事件。
相位对齐之后再计算权重。例如走路和跑步都把左脚落地定义为相位零,当前步态相位为 0.25 时,各自在对应标记区间采样,不能简单让两个片段播放相同秒数。
Blend Tree
1D Blend Tree 根据速度在 Idle、Walk、Run 间插值。2D Blend Tree 根据前后和左右速度混合方向动作。
它适合连续参数,不适合用几十个离散动作强行铺满二维空间。共享顶点值一致时,三角形内的重心插值在公共边上保持连续;跨边时权重梯度可能改变。过瘦三角形还会放大参数变化对权重的影响,因此需要检查动作速度、参数覆盖和相位。
以二维参数点A=(0,0)、B=(1,0)、C=(0,1)为例,查询点(0.2,0.3)的重心权重为(0.5,0.2,0.3),和为一,且加权参数正好回到查询点。沿AB边移动时C的权重为零,相邻三角形若共享A、B的动作与时间相位,边上的姿态就保持一致。越出三角形会产生负权重,应先按项目规则投影到覆盖边界或选择其他三角形。
二维 Blend Space 常对样本点做 Delaunay Triangulation。运行参数落入某个三角形后,只采样三个顶点动画,并用重心坐标计算权重。这样能处理不规则样本分布,也避免每帧混合全部动画片段;三角形过瘦、样本覆盖不足和参数越界仍需专门处理。
运动匹配
运动匹配把动画数据库切成可检索帧,为每帧保存姿势特征和未来轨迹特征。运行时根据当前骨骼状态、期望速度与轨迹查找代价最低的候选,再跳转并混合到该片段。
特征需要归一化和加权,否则位置、速度、朝向等不同量纲会让距离失真。检索结果还要考虑姿态连续性、脚部接触、过渡代价 和最短驻留时间,避免频繁跳片与脚滑。数据库质量、标签约束和查询可视化通常比单纯更换最近邻算法更重要。
加法动画
Additive 动画片段保存相对参考姿态的差值,而不是完整姿态。
平移差值可以相加;旋转应用相对旋转:
常见用途:呼吸、瞄准、后坐力、受击、表情和局部姿势修正。参考姿态不一致会让角色突然偏移或扭曲。
加法旋转则必须约定乘法顺序:正文公式把相对参考的旋转右乘到基础姿态,因而作用在关节局部基底;换成左乘会改变旋转轴。把基础姿态先绕另一个轴转动,再添加瞄准偏移,可以直接暴露这个差别。
分层与骨骼遮罩
层可以让下半身保持移动,上半身播放持枪或攻击。骨骼遮罩决定哪些关节接收这一层。
边界不能生硬截断。只替换手臂而不处理胸椎和肩部,会在肩膀产生断裂。遮罩通常需要从骨盆/脊柱开始渐变,并处理 IK 目标和武器挂点的一致性。
根运动
根运动从动画根轨道提取位移和旋转,驱动角色实体。它能保持脚步与位移一致,适合攻击突进、翻滚和精确表演。
玩法驱动的移动由角色控制器决定速度,动画只跟随参数。它响应直接、网络预测更容易,但可能脚滑。
项目常混合使用:常规移动由代码驱动,特殊动作消费根运动。需要明确根运动在本地、服务器和重放中的权威来源,并处理碰撞阻挡后的剩余位移。
局部姿态求值
输入是两个相同骨架的局部姿态。平移与缩放线性插值,旋转使用最短弧 Slerp:
for (int joint = 0; joint < skeleton.JointCount(); ++joint) {
TRS a = SampleLocal(fromClip, joint, fromTime);
TRS b = SampleLocal(toClip, joint, toTime);
float progress = blendDuration > 0.0f
? Clamp01(blendElapsed / blendDuration) : 1.0f;
float alpha = SmoothStep01(progress);
localPose[joint].translation = Lerp(a.translation, b.translation, alpha);
localPose[joint].rotation = SlerpShortest(a.rotation, b.rotation, alpha);
localPose[joint].scale = Lerp(a.scale, b.scale, alpha);
}
BuildModelPose(localPose, skeleton.parents, modelPose);blendDuration 为零时直接使用目标姿态;正时长则先把进度限制到 [0,1]。片段在计算进度时处理这条分支。混合发生在局部空间,层级累积只执行一次。两个动画片段的时间推进策略、根运动和事件归属需要由状态转换明确决定。若先转成模型空间再逐关节混合,长骨链容易出现长度和轨迹异常;可用手臂快速摆动的转换检查末端轨迹是否连续。
验证方法
显示每层权重、动画片段时间与同步标记,检查左右脚相位和武器挂点。零时长过渡直接切目标,权重范围及骨架一致性在输入端核对。层级蒙皮主机制见骨骼动画与蒙皮。
实现状态:正文片段用于解释本页数据流与边界条件;完整宿主的编译、运行及性能测量尚未执行。可运行的独立模型以本页列出的具体测试为准。
相关主题
参考资料
- Unity 6000.0:Animation Blend Trees:归一化时间与脚部接触相位;本文局部姿态混合片段是 API 中立示例。