Unity的PlayableGraph切换AnimationClipPlayable时关于RestPose的思考
问题
是这样的,我有这么个简单的应用场景,一个PlayableGraph,只有一个output为AnimationPlayableOutput,然后直接连接一个AnimationClipPlayable。现在我的需求是,Editor下,使用脚本,把它的播放状态换成我一个新的Animation Clip。
一开始我的代码是这么写的:
public class Test : MonoBehaviour
{
public AnimationClip clip;
public AnimationClip clip2;
PlayableGraph graph;
// Start is called before the first frame update
void Start()
{
// 创建一个PlayableGraph
graph = PlayableGraph.Create("AnimationClipPreviewer");
graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
// 基于playableGraph创建一个动画类型的Output节点,名字是Animation,目标对象是物体上的Animator组件
AnimationPlayableOutput playableOutput = AnimationPlayableOutput.Create(graph, "Animation", this.GetComponent<Animator>());
AnimationClipPlayable clipPlayable = AnimationClipPlayable.Create(graph, clip);
playableOutput.SetSourcePlayable(clipPlayable);
graph.Play();
}
// Update is called once per frame
void Update()
{
// 按T的时候, 直接切换到clip2
if (Input.GetKeyDown(KeyCode.T))
{
// 切换播放的Clip
var output = graph.GetOutput(0);
graph.DestroyPlayable(playableOutput.GetSourcePlayable());
AnimationClipPlayable clipPlayable = AnimationClipPlayable.Create(graph, clip2);
clipPlayable.SetTime(0);
playableOutput.SetSourcePlayable(clipPlayable);
graph.Play();
}
}
}
这样写,能切换动画,但是有问题,问题在于,它从ClipA切换到ClipB的时候,不是从Rest Pose切换到B的,而是从A的对应时间的Pose切换到B的,这样可能A的动画改变了部分关节数据,B又没有改动到它们,就会出问题。
解决思路
我想到Playable API可以模拟Unity的Animation组件,应该不至于要我去手动切换动画的时候Reset Pose,所以我尝试着用MixerPlayable,
使用这行代码mixer.SetInputWeight(0, 0f);
,我发现角色被Unity Reset了Pose
所以我的代码如下,结果是对的,这下不用自己写Reset Pose的代码了,舒服了:
public class Test : MonoBehaviour
{
public AnimationClip clip;
public AnimationClip clip2;
PlayableGraph graph;
private AnimationMixerPlayable mixer;
// Start is called before the first frame update
void Start()
{
// 创建一个PlayableGraph
graph = PlayableGraph.Create("AnimationClipPreviewer");
graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
// 基于playableGraph创建一个动画类型的Output节点,名字是Animation,目标对象是物体上的Animator组件
AnimationPlayableOutput playableOutput = AnimationPlayableOutput.Create(graph, "Animation", this.GetComponent<Animator>());
AnimationClipPlayable clipPlayable = AnimationClipPlayable.Create(graph, clip);
mixer = AnimationMixerPlayable.Create(graph, 1);
graph.Connect(clipPlayable, 0, mixer, 0);
mixer.SetInputWeight(0, 1);
// 基于本组件已经索引好的AnimationClip创建一个AnimationClipPlayable
// 将playable连接到output
playableOutput.SetSourcePlayable(mixer);
// 播放这个graph
graph.Play();
}
// Update is called once per frame
void Update()
{
// 按T的时候, 直接切换到clip2
if (Input.GetKeyDown(KeyCode.T))
{
// 切换播放的Clip
var output = graph.GetOutput(0);
mixer.SetInputWeight(0, 0f);
graph.DestroyPlayable(mixer.GetInput(0));
AnimationClipPlayable clipPlayable = AnimationClipPlayable.Create(graph, clip2);
graph.Connect(clipPlayable, 0, mixer, 0);
mixer.SetInputWeight(0, 1);
clipPlayable.SetTime(0);
// 播放这个graph
graph.Play();
}
}
}