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();
        }
    }
}
posted @ 2021-11-26 11:49  弹吉他的小刘鸭  阅读(232)  评论(0编辑  收藏  举报