Unity的PlayableGraph切换AnimationClipPlayable时关于RestPose的思考

这篇博客讲述了如何在Unity编辑器中利用PlayableGraph和AnimationMixerPlayable实现两个AnimationClip之间的平滑切换,避免了从一个动画直接跳转到另一个导致的Pose不匹配问题。通过设置Mixer的输入权重为0,再连接新的AnimationClipPlayable并设置权重为1,成功实现了从RestPose过渡到新动画的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题

是这样的,我有这么个简单的应用场景,一个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();
        }
    }
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值