テラシュールブログ

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

【Unity】LWRPでポストプロセスを使用しつつUIの手前にパーティクルを表示する

f:id:tsubaki_t1:20191009221926g:plain

PCを新しくしてからの初更新です。

環境:Unity 2019.2f8、LightWeight RP 6.9.1

LWRPはカメラのスタックができない

 いろいろと便利なLWRPですが、一つだけよく言われる致命的な問題があります。 カメラを複数使用して描画する事ができない という点です。 RenderTexture に描画結果を出力して後でまとめるといった事は可能なのですが、今まで使ってきた 複数のカメラを使って描画する事が出来ないのは、非常にもどかしいです。

 特に問題になりやすいのはUIとパーティクルの描画です。 よくある演出として UIの手前にエフェクトを表示する があります。これは大抵の場合「ゲームを描画するカメラ」「UIだけを表示するカメラ」の二つに分けて描画し、「UIだけを表示するカメラ」にパーティクルを描画させることで実現していました。  ただしLWRPになりカメラのスタックが出来なくなったので、専用カメラが使用できません。よって異なる方法を考える必要があります。

 難しいのが、まず ScreenSpaceOverlay は使えません。UIの手前にパーティクルを描画出来ない為です。   また ScreenSpace-Camera でも単純には上手くいきません。単純に処理すればUIがポストプロセスの影響を受けるので、特にカラーコレクションを使用すると盛大に色合いが変わってしまいます。またBloomやDOFの影響を受けるのはひどいです。同様にPlaneDistanceの設置でUIがステージにめり込む事もあり得ます。この設定をいくら小さくしても、手前で爆発するなど何らかの理由でUIよりステージオブジェクトが手前に描画される事があるのは問題でしょう。

f:id:tsubaki_t1:20191009223546p:plain
UIがポストプロセスの影響を受けてしまっているケース

f:id:tsubaki_t1:20191009223652p:plain
UIがステージにめり込んでしまっているケース。ScreenSpace-CameraだとPlaneDistance設定で起こりえる

PostProcessingの後にUIとパーティクルを描画する

 一番手っ取り早いアプローチは Custom Forward Render を使用して、UIとパーティクルを描画する事です。 このアプローチではUIをポストプロセスの影響を受けないようにしつつパーティクルをUIの手前に描画出来ます。また Screen Space Camera を使いつつもステージやキャラクターの後ろにUIが表示されるといった事も回避できます。
 この手順のアイディアは非常に単純で 任意のレイヤーに所属するオブジェクトを、ポストプロセスの後に描画しよう というものです。

 実際の手順はこんな感じです。

 まず最初にUIは ScreenSpace-Camera を使用する必要があります。 CanvasのRender ModeをScreen space-Cameraに設定します。またCanvas GameObjectのレイヤーはUIに設定します。パーティクルのGameObjectもUIに設定します。
 パーティクルをUIの手前に描画したいので、Order in Layerを使用してUIの手前にパーティクルを描画するように設定します。 UIの場合はCanvasに、パーティクルの場合はRendererにあります。

f:id:tsubaki_t1:20191009225200j:plain
Canvasの設定

f:id:tsubaki_t1:20191009225813p:plain
ParticleのOrder In layerを設定する場所

 レンダラー側の設定を行います。まずは Create > Rendering > ***Pipeline > Forward Renderer でCustom Forward Rendererアセットを作ります。その後、Lightweight Renderer Pipeline AssetのRender TypeをCustomに設定し、Custom Forward Rendererアセットを登録します。

f:id:tsubaki_t1:20191009230101p:plain
Custom Forward Rendererを作る

f:id:tsubaki_t1:20191009230506j:plain
Custom Forward Rendererを使用する設定

 次にCustom Forward Rendererの設定を行います。ここは少し手順が多いので、箇条書きします。

  1. Default Layer Mask から UI を外す。
  2. Render Features+ を押す。追加するパスは Rendere Object を選択
  3. NameUIに変更(任意)
  4. EventAfter Rendering に変更
  5. Filters > QueueTransparent に変更
  6. Filters > Layer MaskUI を選択
  7. Override > Depth にチェックを入れ、Depth TestDisabledに変更

f:id:tsubaki_t1:20191009231723g:plain
手順

これでUIの手前にパーティクルを描画出来ました。

UIの間にパーティクルを挟む

 今回の手順では描画順は完全にOrder In Layer順になっています。なのでパーティクルの所属するOrder In LayerをCanvasの間に挟んでやれば、UIとUIの間にパーティクルを挟む事も可能です。

f:id:tsubaki_t1:20191009232807j:plain
UIとUIの間にパーティクルを挟む

注意点

 これはあくまでもパーティクルがTransparentを使用している前提の使い方なので成立しています(つまりDepth Testを使用していない事が重要)。もしUIの手前に複数のSubMeshを持つオブジェクトを描画するといった場合はRenderTextureをオフスクリーンで描画する方が理にかなっていると言えるかもしれません。

 今回の手順はURPでも使用できました。HDRPは不明です。

 ScreenSpace-Cameraを使用する関係上、編集する場合にはPrefabモードが便利です。ただし、その場合ScreenSpace-Overlayになるので(PrefabからScene上のカメラを参照出来ない為)描画順回りは少し混乱するかもしれません。

 カメラのスタックはロードマップには載っているみたいです。現状は未実装なので、このトリックが必要という感じで。

【Unity】Particle SystemにLODを適応してみる

何となく思いついて、LODをパーティクルに適応したところ、出来てしまいました。何の役に立つのかと思ってみましたが、これが思いの外有効そうです。

 

例えば複数の演出で成り立っているパーティクルの場合、距離に応じて演出を追加していくのもアリかもしれません。

下の場合、LOD0は7個のパーティクルから成り立っていますが、LOD1は4個、LOD2は2個のパーティクルまで削減しています。

f:id:tsubaki_t1:20180204013849g:plain

他のもいくつか使いみちがありそうですが、同時に機能しないどころかパフォーマンスを悪化させるケースもあります。

今回はソレについて紹介します。

 

目次

  • LODとパーティクル
  • Particle SystemにLODを設定してみる
  • で、パフォーマンスは?
    • 描画負荷は削減される
    • パーティクル自体のパフォーマンスはprocedural modeなら効率化
    • LODよりCullingGroupの方が良いかもしれない
  • 感想
  • 関連
続きを読む

【Unity】パーティクルをGPU Instancingで描画してみる & 対応シェーダーを自作してみる

f:id:tsubaki_t1:20180130011142g:plain

Unity 2018.1では、Instancing関係の機能が大幅に使い勝手良くなりました。

特にメッシュパーティクルの描画はCPUバッチングではなくGPU Instancingで行えるようになり、幾つかのケースでパフォーマンスが大幅に向上する事があります。

 

例えば、パーティクルを描画するとレンダースレッドのGfx.ProcessCommandsが凄い事になっているような場合、この項目を見直すと劇的に改善するかもしれません。*1

f:id:tsubaki_t1:20180130103133j:plain

f:id:tsubaki_t1:20180130103136j:plain

 

他にもUnity 2018ではInstancingに多くの改良点がありますが、今回はパーティクルの内容に絞って紹介します。

 

目次

  • パーティクルとバッチング
    • GPU Instancingとバッチング
  • パーティクルのGPUInstancingを使用してみる
    • 自作のシェーダーを使用する
    • 実際のコード
  • 関連

 

*1:この項目を計測する時はvsynkは無効にする

続きを読む

【Unity】Timelineで敵の”出現タイミング”や”動き”を制御してみる

今回はUnity Advent Calendar 2017 のネタで、「Timelineがカットシーンを作るだけのツールではない事を教えてやる!という妄想を書きなぐる」内容です。
要するに、TImelineでゲームの進行を管理してみようぜ!というお話

Timelineを動画作成以外に使用する

Timelineは所謂カットシーンエディタとして紹介されることが多いです。例えばAdamやUltimate Bowlのような高級デモ。もしくはドアや宝箱の解放といった特定ギミックアクションで。

f:id:tsubaki_t1:20171204090033p:plain

ただ、最近のUniteの講演動画を見てふと思いました。

別に、TImelineをカットシーン以外に使っても構わんだろう?f:id:tsubaki_t1:20171204085401p:plain

Timelineは時間を制御する

Timelineは時間を制御するシステムで、Playableは本質的には時間を与えたら結果を返してくれる機能です。
そのため、時間がある程度固定的な動きであればTimeline上から動作を制御することも可能なんじゃないか?と考えたわけです。

f:id:tsubaki_t1:20171204091639p:plain

思いついたので早速試作。

ではどんなゲームが良いか・・・となる訳ですが、ゲーセンにあるタイムクライシス的なゲームを考えましたが、今回はサクッと単純な、本当に単純なシューティングを作って見ました。

ゲームを再生せず動きをプレビュー

実際に作ってみたところ、敵の出現タイミングや動き、ちゃんと作り込めば弾幕の生成などの動きも含めてゲームを再生せずTimelineのヘッドを動かすだけでプレビューができました。

f:id:tsubaki_t1:20171204091537g:plain

本当はPlayableをガンガン拡張したものを紹介する予定でしたが、プロジェクトを日本に置きっぱなしにしてしまったので、先ほどサクッとプロジェクトを作成しました。

作ってみる

サクサクっと作ってみます。

  • 敵の出現と動き、および量産
  • 弾の発射
  • 倒さないと次に進めない敵

敵の移動はAnimation

まず敵の出現と移動です。

これは以前Tweenを使っていたものを自作しましたが、データが自宅なので今はAnimationTrackを使用した動きでサクッと作り直しました。
プレビューの動作も安定しているので、割と楽に使えます。

 

レコードボタンを押している時に対象を動かせば、対象を移動させることができます。もし動かす対象が既にアニメーション再生しているようならば、OverrideTrackを使うことになるかもしれません。

tsubakit1.hateblo.jp

f:id:tsubaki_t1:20171204092730g:plain

アニメーションカーブをAnimationClipに変換のススメ

作ったアニメーションは、AnimationClipに変換します。

これには3つの理由があります。

 

一つはAnimationClipを複数配置する為です。
多くのシューティングゲームでは同じような動きのユニットが存在します。もし複数のユニットの動きに一々キーフレームを打っていたら非常に面倒です。
なのでアニメーションクリップに変換し、ソレをコピーする事で複数のオブジェクトに同じ動きをさせます。

 

二つ目は位置調整がやりやすくなる為です。
今回は敵の出現パターンや位置は完全にTImeline側で制御しています。
その上で、敵の出現タイミングを数ミリ秒ズラしたい場合、キーフレームで制御していると非常に面倒です。特にTimelineのアニメーションエディタはDopesheetモードが使えないので非常に面倒です。

Clipに変換する事で、クリップの位置を調整するだけで出現タイミングがずらせます。

 

最後の一つはAnimationCurveを編集するのにAnimationWindowが使えるようになる点です。位置調整が超ラクになります。

f:id:tsubaki_t1:20171204093031p:plain
Convert to clip trackで変換

 

f:id:tsubaki_t1:20171204094337p:plain
動きを量産

 

f:id:tsubaki_t1:20171204094809g:plain
カーブエディタが使える&プレビューにも反映される

キャラクターの出現位置を変更する

アニメーションで移動を制御した訳ですが、このままだと同じ位置から同じようにユニットが移動します。できれば出現位置を変更したい所です。

f:id:tsubaki_t1:20171204101019g:plain

これにはClip Root Motion Offsetを使用します。

ここでアニメーションの開始位置や向きを調整してやると、同じアニメーションでも異なる位置から開始する事ができます。

f:id:tsubaki_t1:20171204101344p:plain

f:id:tsubaki_t1:20171204101633g:plain

補足

AnimationClipの変換ですが、いくつか把握しておくべきことがあります。

  • AnimationClipが保存されるタイミングは、File > Save Project (シーンの保存等も含むっぽい)のタイミングなので、それまでにクラッシュして落ちるとデータがパー。
  • クリップを複製(Ctrl+D)した場合、元のアニメーションとは異なるアニメーション扱い。元アニメーションをD&Dで登録した場合は同一アニメーション扱い。
  • 複製で作成したアニメーション・通常の手順で作成したアニメーションはOverideの座標系、元アニメーションをD&Dで登録したものはAdditiveの座標。バグっぽい

弾の発射タイミングを制御する。できればスクリプトで。

次に弾の発射の制御系です。弾をバンバラ出していきます。
流石に弾の発射にAnimationEventを使う訳には行かないので、PlayableAPIで制御しましょう!

と思いましたが、、今回はITimeControlを使用します。

ITimeControlでコンポーネントをTImelineから動かす

tsubakit1.hateblo.jp

ItimeControlを使用すると、TImelineの時間を利用してコンポーネントを操作できます。
もし時間を渡したら弾の位置が(消えてなければ)わかる・・・みたいな実装になっている場合は、Timelineから弾のプレビューも可能になります。

今回は面倒だったので弾を発射するコンポーネントのON/OFFだけを行いました。

gist.github.com

撃ってるのはパーティクルです。本当にありがとうございました。

f:id:tsubaki_t1:20171204110108g:plain

ちなパーティクルは生成破棄を繰り返すのではなくEmitを呼び出してエフェクトを生成したりすると、かなり高速で動作します。というかパラメータが多いせいか生成破棄が

あとColliderも地味に高速です。スプライトアニメーションも(Animationと比べると)高速です。あれ、もうこいつだけでいいんじゃね?

倒さないと進行しない敵

最後に「倒さないと進行しない敵」です。

例えばボスやチュートリアルなど、何らかのアクションを行うまで操作を待つ・・・という事はよくあります。

ディレクターを止めろ! 

もし停止中にゲームもしくはTimelineが進行しない・・・といった場合は、Timelineをポーズしてしまうのがいちばん手っ取り早いかもしれません。

gist.github.com

f:id:tsubaki_t1:20171204113126g:plain

ただしPlyableDirectorが停止するので、PlayableDirectorが制御していたアニメーションやカメラワークがニュートラルに戻ります。
もし会話シーンの入力待ち等に使用する場合は、停止の前後でアニメーションのウェイトを減らして通常時のモーションに戻しておくと違和感がなくなります。

tsubakit1.hateblo.jp

タイムリープ

逆に、条件が達成されるまで同じ動作を繰り返す・・・といったケースもあります。こちらはボス戦とか。

このケースでは、TimelineのTimeを巻き戻してしまうのが楽かもしれません。

クリップの長さを求めて、その時間分巻き戻してやれば、クリップの中でループができます。最早脱出条件を揃えるまでエンドレスエイトです。

github.com

f:id:tsubaki_t1:20171204112432g:plain

ただこちらも一つ注意事項があります。というのも、どうやらTimeを巻き戻して移動した場合はExitやEnter系のコールバックが呼ばれない事があるというもので、もし入退場に何らかの重要な処理がある場合は、注意する必要があります。

まぁPlayableは入退場のコールバックがものすごく使いにくいのである意味問題ないのかもしr

見かけた問題

独自PlayableやControlPlayableで動かした場合、パラメータやActiveがリセットされない事が稀にあります。再現条件は不明ですが、ControlPlayableはActiveをリセット後戻さない事があるみたいです。

Timelineは基本的に「全てのアクセスするオブジェクトがロードし終わった状態」でしか動かせません。多彩なアセットや長いタイムラインを持つ場合、動的にアセットを追加・削除できるように間接的にTimelineで制御するようにした方が良いかもしれません。

負荷は?

エディターは遅い。プレイヤーは思ってたより早い

感想

色々と試しに作ってみました。

まぁ問題は色々とありますが、プレビューできて簡単に微調整できるのは強いですね。

 

次回は kaiware007氏が何かを書くそうです。

 関連

www.youtube.com

www.youtube.com

クリップの動作を細かく制御したいなら独自Playable。ただ作るのが超絶スーパーウルトラグレートデリシャスミラクルワンダフル面倒なので、テンプレから作るのおすすめです。

tsubakit1.hateblo.jp