凹みTips

C++、JavaScript、Unity、ガジェット等の Tips について雑多に書いています。

Unity で格好いいパーティクル表現を作れる Particle Playground 2 を色々試してみた

  f:id:hecomi:20150321203439p:plain

はじめに

Unity Particle System である Shuriken を使ってパーティクルを作っている人が多いと思います。

ただより凝ったことをしたくなってくると、標準の機能だけでは色々と足りなく不満が出てきます。そこで Shuriken の拡張として開発されているアセットの Particle Playground を利用すると、標準では出来なかった様々な表現をすることが可能になります。

Particle Playground は Polyfied によって開発されているアセットで、Particle を生成するフレームワークを提供してくれています。特徴としては、Turbulence Manipulator による複雑なパーティクルの動き、動的なメッシュやテクスチャなどの様々なソースからの放出、イベントシステムによるインタラクティブなパーティクル、マルチスレッドによるパフォーマンス向上などが挙げられます。エディタ拡張による専用メニューが作りこまれていたり、プリセットがたくさんあったり、自分で作ったパーティクルを販売できたりといったところまで用意されています。

百聞は一見に如かずということで、以下のムービーを見ると雰囲気がつかめると思います。

お値段は $70 とちょっとお高めですが、格好いい表現をお手軽にやる用途にも、ゴリゴリとスクリプトから操作する用途にもどちらにも使えるので、凝ったパーティクル表現が好きでお金に余裕がある人はポチると捗ると思います。

そんな Particle Playground ですが、検索してもなかなか日本語の情報がないので、本エントリでは最初にどうとっついたら良いかなどを交えつつ、Particle Playground の雰囲気をご紹介できればと思います。

試した環境

  • Unity 5.0.0f4/b18 (Win / Mac)
  • Particle Playground 2.25

デモ

公式デモ

f:id:hecomi:20150321203122p:plain

上記はすべてサンプルに含まれているので設定を参考に色々試すことも出来ます。

個人デモ

f:id:hecomi:20150323003632p:plain

Perlin ノイズを乗せたパーティクルを魔法陣のテクスチャから取ってきた色付きで出しています。また、Manipulator を配置して吸収・放出っぽい感じを出し、Turbulence の強度をスクリプトから制御しているものになります。

f:id:hecomi:20150323003702p:plain

身体からオーラが出てる感じと移動した時に残像が残る感じの表現。そのタイミングのポーズでメッシュ位置が違うのが見て取れると思います。あと Perlin ノイズ付きで消すと格好いい。

ドキュメントについて

Particle Playground をインポートすると、Particle Playground > Documents > Manual.pdf にマニュアルが同梱されています。また、ウェブ上からも閲覧できます。

こちらを一通り読めば何が出来るか分かるのですが、正直読むのが大変だと思います。が、単に使うだけなら最初から読まなくても大丈夫だと思います(私はすっ飛ばしました)。後で引っかかってからドキュメントにアクセスしたほうが効率的です。

サンプルを見てみる

サンプルは非常にたくさん用意されていて、シーンを開いて見る方法と、プリセットをインポートする方法の2種類があります。まず一通り眺めてみると、何が出来そうなのか把握できるのと、どんなサンプルがあったかのインデックスが頭にできるので、あとでやりたい表現を思いついた時に短時間でサンプルにアクセス出来るようになって便利だと思います。

サンプルシーンを開く

  • Particle Playground > Examples > Example Scenes
  • Particle Playground > Examples > Example Scenes > Interactive
  • Particle Playground > Examples > Example Scenes > Splines
  • Particle Playground > Examples > Example Project > Particle Playground

にいくつかサンプルが同梱されています。Vimeo にも上がっているムービーは最後の Particle Playground シーンです。

f:id:hecomi:20150321202918p:plain

公式ブログのエントリも併せて御覧ください。

プリセットの利用

Window > Particle Playground で Particle Playground のウィンドウが開きます。

f:id:hecomi:20150322125324p:plain

沢山のプリセットが用意されていて、サムネイルをクリックだけで簡単にシーンにそのパーティクルが配置されます。

f:id:hecomi:20150322152825p:plain

他にもこのウィンドウでは 3rd Party 製のパーティクルが見れたり、自分のプリセットを登録したり出来ます。

Getting Started

ではいよいよ自分でパーティクルを作る方法について紹介します。

外観

先ほど同様、Window > Particle Playground で Particle Playground ウィンドウを開きます。ここで左上にある New Particle Playground System をクリックします。

すると噴水のように吹き出す白いパーティクルが追加されます。

f:id:hecomi:20150322153751p:plain

GameObject の構成としては、外側に Playground Manager というシーンに一つだけ存在する Particle Playground のパーティクルシステムを管理するオブジェクトがいて、その子として個別にパーティクルがある形になります。図では3つ配置した図です。

f:id:hecomi:20150322162932p:plain

Particle Playground ではエディタ拡張により専用のメニューが Inspector に表示されます。Playground Manager では共通の設定になっていて、子の Particle Playground System で各パーティクルシステムの設定を行います。インスペクタはこんな感じです。

f:id:hecomi:20150322162552p:plain

展開してポチポチ設定していく方式です。Shuriken に似せた作りになっているのであちらにある程度親しんだ方なら特に深く考えず触れると思います。簡単に主要な差分だけ以下解説します。

基本編

デフォルトのパラメタ

デフォルトは ForcesInitial Velocity が設定されていて上に吹き上がる力を指定しています。そして Constant Force で重力が指定されているので、この2つを自分のパラメタに変更します。

パーティクルの源

パーティクルをどこから出すか、という設定が Source になります。ShurikenShape の拡張のイメージです。詳細はドキュメントの P10 に書いてありますが、ここではざっくりと紹介します。

  • State
    • スタティックなメッシュやテクスチャから放出、複数登録して切り替え可能
    • メッシュの各頂点からそこに対応するテクスチャの色のパーティクルを放出
    • ※ テクスチャは Import Settings から Texture TypeAdvanced にして Read/Write Enabledtrue にする必要有
    • 魔法のデモのパーティクルはこれでやってます
  • Transform
    • 放出する点を指定
    • 例えば動くキューブがあってそこから放出したい場合には、そのキューブをドラッグ&ドロップで指定
    • リストで登録できるので新しい放出点が出来た時はここに追加していく
  • World Object
    • メッシュの頂点から法線方向にパーティクルを放出
    • 動的なメッシュも可能
  • Skinned Mesh Renderer
    • 名前のまま Skinned Mesh Renderer を指定
    • アニメーションしても追従する
    • 冒頭の Kyle くん(ロボット)はコレを利用
  • Script
    • 色々オーバーロードされた PlaygroundParticleC.Emit(...) を使って自前で放出
    • 12 個くらいあってドキュメントないですが補完見れば大体分かると思います
    • 後は後述するイベントシステムで利用します
  • Paint
    • コライダに絵を描ける感じ?
    • ぱっと触った感じ良くわからなかったので深く見てないです
  • Projection
    • テクスチャを投影?
    • こちらもすっ飛ばしました
  • Spline
    • ノードをポチポチと配置して描いたスプライン曲線上にパーティクルを生成
    • Splines に含まれるサンプルを見ると理解が深まります

指定したソースによって Inspector の UI が変化します。例えば State だとこんな感じです。

f:id:hecomi:20150322175330p:plain

Shuriken ではそれ自体の位置を動かしたり、位置を指定したいオブジェクトの子にしたりしますが、Particle Playground では位置は Transform コンポーネントをアタッチして指定することが多いです。ここはちょっと癖があります。

うねんうねんさせる

Forces タブで色々な力が Shuriken 同様指定できます。ドキュメントは P14 です。目玉は Turbulence です。

f:id:hecomi:20150322180512g:plain

ちょっとフレームレートが低くて分かり辛いかもですが、綺麗に荒ぶります。タイプは PerlinSimplex があり、どちらもイイ感じに複雑に拡散してくれますが、Perlin ノイズの方は全体がうねんうねんします。

引き寄せる / 反発する

Manipulators でパーティクルに対して引力や斥力を与える点を作成できます。ドキュメントは P18 です。Shuriken では Wind Zone で一定の力を与えるのみでしたが、色んな力場が用意されています。

  • Attractor
    • 引き寄せる(距離に対して線形っぽい?)
  • Attractor Gravitational
    • 重力的に引き寄せる(距離に対して二乗っぽい)
  • Repellent
    • 反力
  • Property
    • 色々な条件で引き寄せる(色とかサイズとか)
  • Combined
    • 複数の Manipulator の合成
  • Vortex
    • 渦巻状に引き寄せる

Manipulators には、各パーティクルシステム毎に設定するローカルな Manipulators と、Playground Manager にアタッチして全てのパーティクルシステムに作用する Global Manipulators の 2 種類があります。

魔法陣のデモではこんな感じで周りに Repellent、中心に Attractor を配置してます。

f:id:hecomi:20150322172214p:plain

応用編

パーティクルの生成順

f:id:hecomi:20150322191638g:plain

プリセットに含まれる Playground Matrix Cube が分かりやすいですので、これを元に説明します。

どういった順番でパーティクルを生成するかは、Particle Settings > Lifetime で指定できます。例えば Linear だとパーティクルのインデックスの順に 0,1,2,....1000 の順番で毎フレームずらしながら生成するので、下からモワーッと上がってくる感じになり、Nearest Neighbor で真ん中あたりの位置(545 とか)を指定すると、真ん中からモワーッとなります。Lifetime Emission を調整するとどれくらいの早さでパーティクルを生成するかも指定できます。

ここで指定しているソースは Plane のメッシュなのですが、立方体になっています。これは、Particle Settings > Overflow Offset を指定すると、メッシュの数を越えてパーティクルが生成された時にオフセット分加味した位置に新たにパーティクルが生成される、という仕様を利用しているからです。つまり、10m 四方の 10x10 の頂点の Plane なメッシュからパーティクルを放出させる際、オフセットを (0, 1, 0) で指定して 1000 個パーティクルを生成、とやると、100 個毎に上に 1m 上に生成位置がズレて結果的に立方体が出来る感じです。

他には、冒頭のムービー中にあった心電図のような表現は Example Scenes > Splines > Playground Spline Example 01 で見れるのですが、これは Spline に従って Linear な順番でパーティクルを生成することで実現しています。他にも色々サンプルがあるので見てみてください。

発展編(スクリプト利用)

各パラメタへのアクセス

ParticlePlayground.PlaygroundParticleC クラスのインスタンスを取得して値を変更すれば、リアルタイムに設定を書き換えることが出来ます。例えば、冒頭の魔法陣のデモでは荒ぶり度を Sin 波で変化させたかったので以下のように設定しています。

using UnityEngine;
using System.Collections;
using ParticlePlayground;

public class PPG_ConstantForce_Changer : MonoBehaviour
{
    public float min = 0.1f;
    public float max = 0.5f;
    public float pitch = 3f;
    private float t_ = 0f;

    void Update()
    {
        var particle = GetComponent<PlaygroundParticlesC>();
        particle.velocityScale = min + (max - min) * (1f + Mathf.Sin(2 * Mathf.PI * t_ / pitch)) / 2f;
        t_ += Time.deltaTime;
    }
}

インスペクタ上から設定できる値は一通り出ていると思います。

イベントシステムの利用

Shuriken では Sub Emitter として用意されているものの拡張がイベントシステムのイメージです。

Particle Playground > Examples > Example Scenes > Interactive > Event Listener シーンを参考に見てみます。

f:id:hecomi:20150321220611g:plain

ここでは「衝突したら衝突パーティクルを生成する」「衝突された対象を回転させる」という 2 つのイベントが発生しています。このイベントの登録は、光線のように伸びているパーティクルの Inspector の Events から設定します。

f:id:hecomi:20150321222835p:plain

重要なのは TypeBroadcast Type の 2 つで、「いつ」「誰に」イベントを通知するかのタイプを指定します。

TypeCollision なので衝突を検知したら、というタイミングが設定されています(他には BirthTime などがあります)。Shuriken の Sub Emitter の設定項目がプルダウン方式になった形ですね。このとき Collision を有効にしておく必要があります。

f:id:hecomi:20150321223046p:plain

Broadcast Type では Both が指定されていて、これは自身(スクリプトのデリゲート経由)と Target へのイベント送信を意味しています。ここでは Target には別の Particle Playground のパーティクルシステム(Collision Particle Effect、細かい粒が下に落ちているヤツ)が指定されています。受け手側では SourceScript に設定することでイベントを受け取り、指定された位置にパーティクルを発生させています。

f:id:hecomi:20150321231019p:plain

自身に発行されたイベントについては、イベントをキャッチしたいオブジェクトからデリゲート経由で登録を行います。ここでは各キューブに以下の様なスクリプトをアタッチしています(公式サンプルは複雑すぎるのでシンプルに書き直しました)。

using UnityEngine;
using System.Collections;
using ParticlePlayground;

public class PlaygroundEventListener : MonoBehaviour 
{
    public PlaygroundParticlesC particles;
    private PlaygroundEventC playgroundEvent_;
    private float rotation_ = 0f;
    private float rotationSpeed_ = 0f;
    private const float rotationAmp_ = 20f;

    void Start() 
    {
        // 登録された最初のイベントを取得
        // (イベントは複数登録できるので)
        playgroundEvent_ = PlaygroundC.GetEvent(0, particles);

        // イベントを登録
        playgroundEvent_.particleEvent += ParticleEvent;
    }

    void OnDestroy() 
    {
        playgroundEvent_.particleEvent -= ParticleEvent;
    }
    
    void ParticleEvent(PlaygroundEventParticle particle) 
    {
        // イベントは全てのキューブに対して発行されるので、
        // 自身に対してかのイベントをコライダが自身ののものか
        // どうかを通じて判定する
        if (particle.collisionCollider.gameObject == gameObject) {
            rotationSpeed_ +=  // パーティクルの情報を色々取れる
                particle.size * 
                particle.velocity.magnitude *
                rotationAmp_;
        }
    }

    void Update() 
    {
        rotation_ += rotationSpeed_ * PlaygroundC.globalDeltaTime;
        rotationSpeed_ *= 0.98f;
        transform.localRotation = Quaternion.Euler(new Vector3(0f, 0f, -rotation_));
    }
}

これでパーティクルが当たると回転するキューブが出来る形になります。他にも Particle から色々な情報が取ることができ、Shuriken よりも複雑なパーティクル表現が可能です。

ちなみに Collisionrigidbody を設定しているので、おそらく回転ジョイントを作れば回転するスクリプトは要らないんじゃないかな、と思います(ただスクリプトのほうが軽量だと思います)。

ただ、ここらの設計はちょっと複雑な感じもするので、もう少しシンプルになってくれると嬉しいなと思いました。

その他

他にも面白いサンプルがあったのでメモ書きだけ。

単に Attractor の ON / OFF をするだけでも格好いい感じのインタラクティブさを表現できます。例えば曲線に繋がれた輪っかを動かすサンプル(Transform Splines w Spline Targets (Interactive))では、ManipulatorObjectC.strengthManipulatorObjectC.size をマウス押下時にいじって輪っかに引きつけられるのを表現しています。

クリックすると泡が消えるサンプル(Manipulator Events)では、ManipulatorObjectC.KillAllParticles(); で Attractor に引きつけられたパーティクルを消去するとともに、小さな泡パーティクルを発生させてはじけた感を出してます。

こんな感じでインタラクティブデモを紐解いていくだけでも色々表現の幅が広がりそうです。

パフォーマンス

コードを覗くと、ParticleSystem.Particle を利用して自前でパーティクルの位置を計算しているように見えます。ParticleSystem.Particle を自前で生成するとパーティクルの情報を1つ1つ制御できるので、性能の良い PC であれば数万個なら問題なく 60 fps で動きます。以下サンプルです。

参考: Kinect for Windows SDK 2.0 Unity Pro Add-in でポイントクラウド風描画 - 自習室

Particle Playground ではこれを利用しつつ、PlaygroundC.RunAsync( () => { ... } ) というスレッドを生成する形式を利用して、位置などを計算する専用のスレッドを随時生成して計算しています(System.Threading.ThreadPool.QueueUserWorkItem のラッパー)。つまり、パーティクルの描画以外の処理は基本的に別スレッドで計算している(と思われる)ので、別スレッドで 1 フレームに計算しきる量なら他の処理に大きな影響を与えずに Shuriken と同じ速度で描画できる、という仕組みに思われます。定量的に比較はしてないですが、体感的に Shuriken と遜色ない速度で複雑なパーティクルが動いているように感じます。

また、最大スレッド数やパーティクルシステムへのスレッドの割り当てなどスレッド生成のルールについては、Playground ManagerAdvanced から細かく設定できます。

雑感

ゲームとかに使おうとすると、パーティクルシステムを子にしづらいのでちょっと面倒だと思います。特に Prefab から生成するオブジェクトに Particle をもたせるときに、いちいちマネージャーへ登録しないとなりません。ただし Turbulence を別スレッドで計算して...とか含めて考えると一元管理方式を取る設計になると思うので、ここはパフォーマンスとの兼ね合いを考えて割り切りが必要かなと思います。回避策としては、プリセットの Playground Burning Robot のように、Particle Playground System を含む Prefab を Playground Manager の子として Instantiate() するとかかな、と考えています(未だノウハウなくてすみません)。

その他のパーティクルシステムのフレームワーク

試してないですが、他のパーティクルフレームワークも色々あるようです。

追記(2015/03/24)

公式でチュートリアル動画が公開されているようです。

一つあたり 5 分前後で、11 編あります。

おわりに

大体の雰囲気が掴めたのではないでしょうか。Turbulence と Manipulator だけでも大分キレイな感じになって、これだけ使うのでもお手軽で便利ですし、デモのようにキャラクタにイイ感じにオーラを纏わせるとかも簡単です。スクリプトを組めば更に複雑な表現もできてとても面白いです。

...UE4 ならデフォルトで有りそう…。