原カバンは鞄のお店ではありません。

Unityを使ったゲーム制作のあれこれを綴っていきます。

【Unity】そうだ、Playable APIを使ってみよう

歓迎会

今年度の新人歓迎会に顔を出したら去年の新人に顔を覚えられていなかった影の薄い皆さんこんにちは。そりゃぁ普段、新人の子と顔を合わすような場所にはいませんが、一応忘年会などには顔を出してアピールしているはずなんですがね、おっかしいなぁ・・・

 

AnimatorControllerが面倒くさい

Unityで3Dモデルに対して何かしらのアニメーションを再生させたい場合、AnimatorControllerにAnimationClipを設定したState(状態)を定義し、それぞれのStateへの遷移条件を設定、スクリプト側で遷移条件に応じた処理を実施、という流れで実装する必要があります。
これはまぁ慣れてしまえばさっさと作ることができますが、再生したいアニメーション定義が増えていくと次第に目で追うのも大変になっていき、その後に改修作業が入ってくると遷移条件を把握するだけでも時間をとられたりします。また、逆に走ってジャンプしたいだけだとか、お試しで動かしてみたいだけだとか、そんな場合でもAnimatorControllerを一から作成して制御スクリプトを組むとなると少し面倒だったりします。

例えばアセットストアからキャラクターのアセットを購入したら結構多くのAnimationClipが付随していて有難いものの、ここからAnimatorControllerでステートマシンを組もうとすると結構時間が取られます。

こんな感じでAnimationClipが大量にあったり

なのでアニメーション制御をできるだけシンプルに実装するための手段の一つとして「Playable API」を導入してみることにしました。

 

Playable API

Playable APIはUnity2017あたりから搭載された機能でアニメーション、オーディオ、ビデオ、その他再生したいものをPlayableGraphというモジュールを介して制御・再生することができる機能です。有名どころではUnity Timelineはこの技術を使って実現されていたります。
最初に「再生したいものをPlayable Graphというモジュールを介して制御・再生する」と書きましたが、Playable APIを使うにあたってはこの概念が非常に重要で、Playable APIとは「再生したいもの=Input」を「再生するもの=Output」へ橋渡しをするための機能だと言えます。

例えばアニメーションの場合、AnimationClipをAnimatorを使って再生するので、AnimationClipがInput、AnimatorがOutputだと捉えることになります。
よってPlayable APIを使ってアニメーションの再生するには以下の手順を踏みます。

  1. PlayableGraphを作成する
  2. InputとなるPlayable(=AnimationClip)を作成する
  3. OutputとなるPlayable(=Animator)を作成する
  4. InputをOutputに接続する

手順が多いと感じるかもしれませんがスクリプト側の実装は非常にシンプルです。

[SerializeField] private AnimationClip MoveClip;
[SerializeField] private Animator TargetAnimator;
private PlayableGraph PenguinGraph;

private void Init_TestPlayabeGraph()
{
	// 1.PlayableGraphの作成  
	PenguinGraph = PlayableGraph.Create("TestGraph");
	// 2.Playable(インプット)の作成  
	AnimationClipPlayable playable = AnimationClipPlayable.Create(PenguinGraph, MoveClip);
	// 3.PlayableOutput(アウトプット)の作成  
	AnimationPlayableOutput output = AnimationPlayableOutput.Create(PenguinGraph, "AnimationOutput", TargetAnimator);
	// 4.PlayableOutputにPlayableを接続  
	output.SetSourcePlayable(playable);
}

上記の設定を行った後にPlayableGraphを使って再生します。

void Update()
{
	if (Input.GetKeyDown(KeyCode.S))
	{
		// 5.PlayableGraphを通して再生  
		PenguinGraph.Play();
	}
}

private void OnDestroy()
{
	// 6.使い終わったらPlayableGraphを破棄  
	PenguinGraph.Destroy();
}

実際の動作例として灰色のペンギンモデルに対して上記のスクリプトをアタッチして途中から別のアニメーションを再生してみます。

 

別レイヤーのアニメーションも再生する

先ほどのペンギンのモデルには動作のアニメーション以外にもキャラクターの表情を変えるアニメーションも付随しているので、そういった場合にはどちらも同時に再生したいものです。

表情を変えるAnimationClipたち

 

この場合、再生したいもの=Inputが複数のAnimationClip再生するもの=Outputが一つのAnimatorとなるので、Input側ではInput(Playable)を複合して格納するAnimationMixerPlayableへ接続し、OutputへはこのAnimationMixerPlayableを接続するようにします。
先ほどのソースと比べると少し複雑ですが変更点は「2.InputとなるPlayableを作成する」の部分だけで、その他は今まで紹介した手順と同じです。

[SerializeField] private AnimationClip MoveClip1;
[SerializeField] private AnimationClip MoveClip2;
[SerializeField] private Animator TargetAnimator;
private PlayableGraph PenguinGraph;
AnimationMixerPlayable MixerPlayable;

private void Init_TestPlayabeGraph()
{
	// 1.PlayableGraphの作成  
	PenguinGraph = PlayableGraph.Create("TestGraph");
	// 2.Playable(インプット)の作成  :2つのPlayableが入力として接続されるので引数に「2」
	MixerPlayable = AnimationMixerPlayable.Create(PenguinGraph, 2);

	AnimationClipPlayable movePlayable1 = AnimationClipPlayable.Create(PenguinGraph, MoveClip1);
	AnimationClipPlayable movePlayable2 = AnimationClipPlayable.Create(PenguinGraph, MoveClip2);

	MixerPlayable.ConnectInput(0, movePlayable1, 0);
	MixerPlayable.ConnectInput(1, movePlayable2, 0);

	// 3.PlayableOutput(アウトプット)の作成  
	AnimationPlayableOutput output = AnimationPlayableOutput.Create(PenguinGraph, "AnimationOutput", TargetAnimator);

	// 4.PlayableOutputにPlayableを接続  
	output.SetSourcePlayable(MixerPlayable);

	MixerPlayable.SetInputWeight(0, 1.0f);
	MixerPlayable.SetInputWeight(1, 1.0f);
}

上記のソースの一番最後の部分でAnimationMixerPlayableへ接続した二つのAnimationClipに対してアニメーションのブレンドをするための重みづけの設定を行っています
今回の場合、動作のAnimationClipと表情のAnimationClipはどちらも同時に再生するので、どちらにも「1.0f」のウェイトを設定しています。

 

実際の動作がこちら、灰色のペンギンが別アニメーションへ遷移するのと同時に表情も変わることが分かります。

 

今回のまとめ

Playable APIはアニメーションの再生に拘わらず汎用的に使える機能ですが多くの場合はアニメーションの制御に使用され、AnimatorControllerステートマシン地獄から脱出することができます。
また、Playable APIにはInputとOutputを定義する必要があり、Inputが複数あるケースにも対応しています。
ゲーム仕様を実装するための一つの手法として役立つのではないでしょうか。

◇プライバシーポリシー

●個人情報の利用目的

当ブログでは、メールでのお問い合わせ、メールマガジンへの登録などの際に、名前(ハンドルネーム)、メールアドレス等の個人情報をご登録いただく場合がございます。

これらの個人情報は質問に対する回答や必要な情報を電子メールなどをでご連絡する場合に利用させていただくものであり、個人情報をご提供いただく際の目的以外では利用いたしません。

●個人情報の第三者への開示

当サイトでは、個人情報は適切に管理し、以下に該当する場合を除いて第三者に開示することはありません。

・本人のご了解がある場合
・法令等への協力のため、開示が必要となる場合

個人情報の開示、訂正、追加、削除、利用停止
ご本人からの個人データの開示、訂正、追加、削除、利用停止のご希望の場合には、ご本人であることを確認させていただいた上、速やかに対応させていただきます。

アクセス解析ツールについて

当サイトでは、Googleによるアクセス解析ツール「Googleアナリティクス」を利用しています。

このGoogleアナリティクスはトラフィックデータの収集のためにCookieを使用しています。このトラフィックデータは匿名で収集されており、個人を特定するものではありません。
この機能はCookieを無効にすることで収集を拒否することが出来ますので、お使いのブラウザの設定をご確認ください。

●免責事項

当サイトからリンクやバナーなどによって他のサイトに移動された場合、移動先サイトで提供される情報、サービス等について一切の責任を負いません。

当サイトのコンテンツ・情報につきまして、可能な限り正確な情報を掲載するよう努めておりますが、誤情報が入り込んだり、情報が古くなっていることもございます。

当サイトに掲載された内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。

●プライバシーポリシーの変更について

当サイトは、個人情報に関して適用される日本の法令を遵守するとともに、本ポリシーの内容を適宜見直しその改善に努めます。

修正された最新のプライバシーポリシーは常に本ページにて開示されます。