【Unity】【Playables API】AnimationLayerMixerPlayableでAnimationClipPlayableにAvatarMaskを適用する

AnimationLayerMixerPlayableでAnimationClipPlayableにAvatarMaskを適用する方法です。

Unity2018.4.0

やりたいこと

Animator ControllerのLayer機能を使うと、上半身と下半身で別のモーションを適用できます。

f:id:halya_11:20190613221411p:plain

見た目はこんな感じになります。

f:id:halya_11:20190613221536g:plain

この記事ではこの機能を、Playable Graphを使って実現してみます。

ソースコード

いきなりですがソースコードです。

using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;

public class PlayableExample : MonoBehaviour
{
    [SerializeField]
    private AnimationClip _clip1;
    [SerializeField]
    private AnimationClip _clip2;
    [SerializeField]
    private AvatarMask _mask;

    private AnimationLayerMixerPlayable _mixer;

    void Awake()
    {
        var graph = PlayableGraph.Create("Example Graph");
        AnimationPlayableOutput.Create(graph, "Animation", GetComponent<Animator>());

        _mixer = AnimationLayerMixerPlayable.Create(graph, 2);
        graph.GetOutput(0).SetSourcePlayable(_mixer);

        // Playableを2つ生成してmixerに繋ぐ
        var playable1 = AnimationClipPlayable.Create(graph, _clip1);
        _mixer.ConnectInput(0, playable1, 0);
        var playable2 = AnimationClipPlayable.Create(graph, _clip2);
        _mixer.ConnectInput(1, playable2, 0);

        // 上のレイヤーにマスクを掛ける
        _mixer.SetLayerMaskFromAvatarMask(1, _mask);

        // InputWeightは両方とも1にしておく
        _mixer.SetInputWeight(0, 1);
        _mixer.SetInputWeight(1, 1);

        graph.Play();
    }
}

AnimationLayerMixerPlayableというLayerを実現するMixerが用意されているのでこれを使います。
これにAnimationClipPlayableを二つ繋いで、InputWeightは両方とも1にしておきます。
そして二つ目のレイヤーにはSetLayerMaskFromAvatarMask()でAvatarMaskを適用します。

これで、Animator ControllerでLayerを二つ作って上のレイヤーにMaskを適用したのと同じ状態が作れました。

f:id:halya_11:20190613223212p:plain

結果

上記にAnimationClipやAvatarMaskを設定して再生するとマスクされたモーションが再生されます。

f:id:halya_11:20190613221536g:plain

Playable Graphはこんな感じです。

f:id:halya_11:20190613223322p:plain

BlendingをAdditiveに

Animator ControllerのLayerにはBlendingという機能があります。
これをAdditiveにすると下のレイヤーとモーションがブレンドされます。

f:id:halya_11:20190613223832p:plain

これをPlayableGraphで実装するにはAnimationLayerMixerPlayable.SetLaerAdditive()を使います。

_mixer.SetLayerAdditive(1, true);

Maskを動的に差し替える

Maskを動的に差し替えることもできるようです。

using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;

public class PlayableExample : MonoBehaviour
{
    [SerializeField]
    private AnimationClip _clip1;
    [SerializeField]
    private AnimationClip _clip2;
    [SerializeField]
    private AvatarMask _mask;
    [SerializeField]
    private AvatarMask _mask2;

    private AnimationLayerMixerPlayable _mixer;

    void Awake()
    {
        var graph = PlayableGraph.Create("Example Graph");
        AnimationPlayableOutput.Create(graph, "Animation", GetComponent<Animator>());

        _mixer = AnimationLayerMixerPlayable.Create(graph, 2);
        graph.GetOutput(0).SetSourcePlayable(_mixer);

        // Playableを2つ生成してmixerに繋ぐ
        var playable1 = AnimationClipPlayable.Create(graph, _clip1);
        _mixer.ConnectInput(0, playable1, 0);
        var playable2 = AnimationClipPlayable.Create(graph, _clip2);
        _mixer.ConnectInput(1, playable2, 0);

        // 上のレイヤーにマスクを掛ける
        _mixer.SetLayerMaskFromAvatarMask(1, _mask);

        // InputWeightは両方とも1にしておく
        _mixer.SetInputWeight(0, 1);
        _mixer.SetInputWeight(1, 1);

        graph.Play();
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space)) {
            _mixer.SetLayerMaskFromAvatarMask(1, _mask2);
        }
    }
}

上半身マスクと下半身マスクを切り替えるとこんな感じです。

f:id:halya_11:20190613224051g:plain

動的にマスクを削除することはできない?

動的にマスクを削除することはできないようです。
SetLayerMaskFromAvatarMask()にnullを入れたらできるだろうと思ってやってみたらエラーを吐きました。

f:id:halya_11:20190613224258p:plain

動的にマスクを外したければ専用のAvatarMaskを用意してそれに差し替えるなどの対応が必要そうです。