テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】Playable APIで幾つかの小技

昨日のPlayable APIで書ききれなかった事を少し追記します。

tsubakit1.hateblo.jp

複数のAnimatorに単一のPlayableを流し込む

PlayableGraphにOutputは実は複数作ることが出来ます。コレを利用すると、複数のオブジェクトを完全に同期した状態でアニメーションさせる事が出来ます。

f:id:tsubaki_t1:20170730124159j:plain

またOutputでアニメーションを流し込んだ場合でもアバターはAnimator毎に制御されているので、Humanoidならボーン構造の異なる物でもアニメーションが可能です。

アニメーションのコストがかかるのはスキニングの部分なので大した意味はありませんが、何かに使えるかもしれません。

f:id:tsubaki_t1:20170730123706g:plain

AnimationClipPlayableが共通化されているので、一つのAnimationClipPlayableを操作すれば一気に複数のアニメーションが制御出来るのは中々に面白いです。

逆を言えば、少しずつタイミングをズラしたようなアニメーションは出来ない点には注意が必要です。

f:id:tsubaki_t1:20170730124714g:plain

gist.github.com

アニメーションの出力先を切り替える

outputは出力先を切り替えることも出来ます。

例えばキャラクターが選択された際のモーション等があった時、キャラクター一人ひとりにPlayableGraphを作るのはナンセンスなので、PlayableGraphだけ作って出力先を切り替えてしまう訳です。

f:id:tsubaki_t1:20170730130343j:plain

なお、Output出力先を切り替えてもアニメーションは最初から再生される訳ではありません。最初から再生したい場合は、PlayableのTimeを0に戻す等の操作が必要そうです。

f:id:tsubaki_t1:20170730130658g:plain

gist.github.com

Additiveの再生

ギミックを動かす等を行う時、Additiveで動かせると一々親オブジェクトを用意しなくても良いので何かと便利です。

Playable APIの場合、AnimationLayerMixerPlayableにAdditiveのオプションがあるのでソレを使用します。

f:id:tsubaki_t1:20170730134049g:plain

gist.github.com

tsubakit1.hateblo.jp

【Unity】アニメーション制御に色々と良さそうな"Playable API"について云々

今回はUnity 2017.1で正式導入となったPlayable APIについてです。

PlayableAPIはAnimatorのLowLevel API(のようなもの)

まずPlayable APIとは何ぞやという話ですが、大雑把に言えばAnimationを再生する為の物です。

何が便利かと言えば、AnimationControllerを量産する事無くアニメーションを再生動的なアニメーションの追加、そしてアニメーション同士をブレンドする事が期待出来ます。

 

AnimationControllerは、どちらかと言えば全パターンを網羅した物を用意して「すべてを埋めない」に対して、Playable APIは逐次PlayableGraphに追加していくイメージです。

https://cdn-ak.f.st-hatena.com/images/fotolife/t/tsubaki_t1/20160615/20160615234430.gif

ちなみに、この技術はAnimatorだけでなくTimelineにも使用されており、オーディオやスクリプト制御にも応用が効く機能ではあります。
…パーティクルも一緒に制御してくれても良いのよ?

 

なお、Playable APIは余りセーフなAPIでは無いようで、開放忘れ等で簡単にUnityエディターをクラッシュさせます。Threadやstaticと同じように、十分に注意する必要がありそうです。

 アニメーションのブレンド結果をOutputに出力する

Playable APIを説明する場合、大きく分けて3つの要素があります。

Playable GraphPlayableOutput、そしてPlayableです。

 

Playableは、アニメーション再生やオーディオ再生を制御するためのコマンドです。ココでどのアニメーションを再生するのか、どういったブレンドを行うのかを制御します。

Playableの結果を出力する先はPlayable Ouputです。Ouputに出力された結果はバインドしたAnimatorに流し込まれます。

Playable Graphは複数のPlayableやOutputを持つグラフです。

f:id:tsubaki_t1:20170729221944j:plain

要するにoutputに何を流し込むかで、再生するアニメーションが変わります。

AnimatorをPlayable API的に見てみる

Playable APIスクリプトで基本的に作成します。その際、どういった形でグラフが構築されているのかをPlayableGraph Visualizerで確認する事が出来ます。

github.com

これでAnimatorを見てみると、下のようなグラフになります。

f:id:tsubaki_t1:20170729223526j:plain

 AnimationControllerでどのステートで再生するのかを決定、Layerでレイヤー単位のアニメーション加算・上書き合成を制御します。

面白いのが二つのAnimationMixerで、アニメーション切替のタイミングで下に以前再生していたAnimationClip、上に次に再生するAnimationClipを流し込み、アニメーションのブレンドを実現しています。

f:id:tsubaki_t1:20170729223929j:plain

Playable APIを実際に使ってみる

それでは実際にPlayable APIを使用してみます。

なお、日本語マニュアル(Unity 5.4)のサンプルコードは動作しません。最低でもUnity 2017.1のマニュアルが望ましいです

AnimationClipを動的にロードしてアニメーションを再生する

まずはAnimationClipを動的にロードしてアニメーションを再生してみます。

必要な物は5つ。

  • UnityEngine.PlayablesとUnityEngine.AnimationsのNamespace、
  • PlayableGraphの生成と破棄
  • 再生するAnimationを持つAnimationClipPlayable
  • 出力先のPlayableOutput
  • 流し込む先のAnimatorコンポーネント

これで動的に取得したアニメーションをAnimatorで再生する事が可能です。

gist.github.com

f:id:tsubaki_t1:20170729230126g:plain

複数のアニメーションの切替

アニメーションの切替はAnimationMixerPlayableを使います。

まぁOutputへ流し込むAnimationClipを切り替えても良いのですが、Mixerを使用した方がブレンドが出来て便利です。またAnimatorのInitializeも回避出来ます。

gist.github.com

f:id:tsubaki_t1:20170729231923g:plain

正確には切替というより、複数のAnimationClipPlayableのウェイトを変更する感じです。

複数のレイヤー制御

アニメーションを行う場合、表情や上半身・下半身でのレイヤー制御等を行いたくなる場合があります。そういった場合ではレイヤーの加算合成が使えます。

gist.github.com

f:id:tsubaki_t1:20170730004307g:plain

上手く使えばギミックをPlayableAPIで動かすことが可能です。ただし、編集にはAnimatorが必要なので、若干の片手落ち感はあります。

二つのAnimationClipPlayableを使いまわす

AnimationClipPlayableを全登録せず、随時追加・破棄していくパターンです。

gist.github.com

f:id:tsubaki_t1:20170730020401g:plain

基本的にはAnimationControllerで、必要な時だけAnimationClipを足す

ある程度AnimationControllerで制御したいが、(例えば宝箱をあけたり、畑を収穫したり等の)特殊イベント時に任意のアニメーションを足したい場合のアプローチです。

アニメーション終了後にPlayableを破棄します。

gist.github.com

f:id:tsubaki_t1:20170730030538g:plain

PlayableGraphをAnimatorから持ってくる場合は、AnimationControllerはAnimatorから抜いておく必要があります。

 

一応、既に再生中に割り込む方法もありましたが、どちらかと言えばAnimationControllerPlayableを使用したほうが安定する印象です。

tsubakit1.hateblo.jp

注意点

  • エディターで、ゲーム再生中にフォーカスが外れた状態で放置すると、再開時にアニメーション再生がゆっくりになる(ビルドした物はフォーカスが外れても大丈夫)
  •  PlayableGraphを開放忘れると落ちる事がある(ので、AwakeとOnDestroyで生成・開放を管理)
  • 開放漏れ等は「2回目の再生」で落ちる

【Unity】AssetBundleをマネージコードのStreamから取得する

f:id:tsubaki_t1:20170724220902j:plain

Unity 2017.2よりAssetBundle.LoadFromStreamとAssetBundle.LoadFromStreamAsyncが追加されました。

これで暗号化したAssetBundleをStreamから読み込んだり、独自圧縮したAssetBundleを読み込んだり…?うーん、出来るのかな

サンプルコード

下のようなコードでAssetBundleが取得出来ます。

gist.github.com

まぁコードに関してはスクリプトリファレンスの方が多分ちゃんとしてます。

Unity - Scripting API: AssetBundle.LoadFromStream

Unity - Scripting API: AssetBundle.LoadFromStreamAsync

色々な制限が

おお便利そう!と思いましたが、色々と制限が…

  • AssetBundleのデータはStreamの位置が0である必要がある
  • AssetBundleの値を読むときはSeekの位置が0になる
  • 他のプロセスが位置を変更しない前提
  • stream.CanReadはTrueを返す
  • stream.CanSeekはTrueを返す
  • Streamは別スレッドからアクセス可能であること

ただ、Streamを自作すれば結構色々と出来ます。ファイルを暗号化してみた結果がこちら

tsubakit1.hateblo.jp

そして未来へ…

それは兎も角、AssetBundleの今後の予定されてる破壊的変更の前には、この程度のことは無いに等しい…

詳しくは、見れば分かるさ…見ればな…

www.slideshare.net

www.youtube.com

 

ちなみに、複数のCacheフォルダを持ったり、指定Cacheを削除したりは既に出来ます。

docs.unity3d.com

関連

docs.google.com

https://forum.unity3d.com/threads/preview-of-2017-2-features.481949/

【Unity】SpriteMaskでSpriteにマスクを掛ける演出が色々と面白い

Unity 2017.1より追加されたSpriteMaskの機能が意外と面白いので、少しメモします。

SpriteMask

SpriteMaskはSpriteを利用してSpriteRendererにマスクをかける機能です。
画像をSpriteの形にくり抜いたり、逆にSpriteをくり抜いたり出来ます。

f:id:tsubaki_t1:20170721003252j:plain

機能的には現状存在するSpriteに対してマスクを掛ける…程度の機能ではありますが、意外とコレは利用の幅が広そうです。

 

操作方法

使い方に関しては正直マニュアルが詳しいです。

docs.unity3d.com

壁に穴を開ける

壁に穴を空けてみます。これはUnityTipsに上がっていたものを自分なりに解釈したものです。

f:id:tsubaki_t1:20170721003328g:plain

まず最初の状態がコレです。

SpriteMask等は何も設定していないので、キャラクターの前面に地面が表示されています。

f:id:tsubaki_t1:20170721003954j:plain

次にSpriteMaskをキャラクターの子GameObjectに追加し、キャラクターの前面の地面のSpriteRendererにはMaskIntaraction Visible Outside Masksを設定します。

SpriteMaskをキャラクターの子GameObjectに設定するのは、そのほうが柔軟にマスクする範囲を決められるからです。

f:id:tsubaki_t1:20170721004310j:plain

f:id:tsubaki_t1:20170721004301j:plain

 

後はマスクで抜いた先の背景も設定しておきます。
背景はキャラクターよりOrderInLayerが奥のSpriteを用意しておき、そのMask Interactionはnoneに設定しているだけです。

これでマスクでくり抜いたら背景がいきなり空…みたいな事は回避出来ます。

f:id:tsubaki_t1:20170721004558j:plain

同様に、SpriteMaskを使用してシルエットを表示させる事も可能といえば可能です。ただしシルエット色を変えられる以外のメリットが無いので、ソレをするならStencilでやった方が良いんじゃないかなという気はします。

Spriteの消滅演出をSpriteMaskで

マスクはアルファのカットアウト(アルファブレンドではない!)で、SpriteMaskのα値を変えればスプライトの消滅演出を追加したり出来ます。

例えば下の場合、簡単なルール画像を用意すれば実現出来ます。

f:id:tsubaki_t1:20170721010817g:plain

For You さんのページよりルール画像を入手して、ルール画像の透明度ルールはFrom Grayscaleに変更。

後はSpriteMaskのAlpha Cutoutを設定すれば、うまい感じに切り抜いてくれます。

ただ、ルール画像によっては最後まで綺麗に切り抜いてくれない事があるので、そのあたりが出たらルール画像を調整する必要があるかもしれません。

f:id:tsubaki_t1:20170721011116j:plain

実はパーティクルのマスクも出来る

もう一つ面白いのが、実はSpriteだけではなくParticleSystemにもマスクが使えるという点です。例えば下のように、パーティクルの生成をマスクの形でカットしています。

f:id:tsubaki_t1:20170721010048g:plain

f:id:tsubaki_t1:20170721011935j:plain

ただひとつ問題になるのがSpriteMaskが複数合った場合です。
例えば下の図では、右下の赤いパーティクルと左上の黄色いパーティクルが、お互いのマスク範囲内に混ざってしまっていることが確認出来ます。

f:id:tsubaki_t1:20170721011612j:plain

これはSortingGroupで解決出来るみたいです。てっきりSprite用かと思ってましたが、意外と使えるもんです。

親にSortingGroup、子にSpriteMaskとParticleを配置すると、上手い感じにパーティクルをマスクしてくれます。

f:id:tsubaki_t1:20170721011845g:plain

f:id:tsubaki_t1:20170721083548j:plain

tsubakit1.hateblo.jp

関連

tsubakit1.hateblo.jp

halcyonsystemblog.blog.fc2.com

tsubakit1.hateblo.jp