动作融合
作者:互联网
只要有playercontroll的游戏都会有人物动作,比如idel、walk、run等,动画师只会针对每种动作做一系列动画,一组动画称为一组clips,里面k的每帧动画称为一个clip。
当我们按下方向键时,希望看到角色是从一个动作到另一个动作自然过度的,可是动画师并没有做过度动画,这时就需要“动作融合”。
动作融合,简单来说需要2步插值,第一步是两个动作每个clip分别插值,第二步是根据deltaTime在时间线上找到融合后的2个clip插值。
以“走”和“跑”2个动作融合为例
【准备】
1.动画师准备好walk-clips和run-clips。帧数需要一样,比如都是58帧,即58个clip,且间隔比例要一直;长度可以不同,比如walk一个循环是5秒,run开一个循环是10秒。
2.物理系统返回每帧deltaTime,例如1秒30帧,返回的deltaTime大概是0.33s。
【第一步】
当玩家按下跑步键,角色从走路变成跑步的过程中,物理系统返回speed会不断发生改变。
每次speed改变,都重新计算权重。
根据权重对动作AB的每个骨骼的58个clip分别做插值,插值的属性包括骨骼的translate/scale/rotation,translate和scale用线性插值lerp,rotation用四元数插值nlerp。
void AnimationPose::blend(const AnimationPose& pose) { for (int i = 0; i < m_bone_poses.size(); i++) { auto& bone_trans_one = m_bone_poses[i]; const auto& bone_trans_two = pose.m_bone_poses[i]; float sum_weight = m_weight.m_blend_weight[i] + pose.m_weight.m_blend_weight[i]; if (sum_weight != 0) { float cur_weight = pose.m_weight.m_blend_weight[i]; // 动作2权重 m_weight.m_blend_weight[i] = 1.0f - cur_weight; // 动作1权重 bone_trans_one.m_position = Vector3::lerp(bone_trans_one.m_position, bone_trans_two.m_position, cur_weight); bone_trans_one.m_scale = Vector3::lerp(bone_trans_one.m_scale, bone_trans_two.m_scale, cur_weight); bone_trans_one.m_rotation = Quaternion::nLerp( cur_weight, bone_trans_one.m_rotation, bone_trans_two.m_rotation, true); } } }
【第二步】
每帧输入deltaTime根据此刻的物理速度、权重,分别算出walk和run的deltaTime(或者算出融合后的deltaTime)。
根据deltaTime选取2个融合后的clip做插值。
至此,就能自然的表现从“走”到“跑”的过度了。
标签:动作,weight,插值,deltaTime,融合,trans,bone 来源: https://www.cnblogs.com/alphaGo/p/16559827.html