凹み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 ならデフォルトで有りそう…。

Maya LT でスキニングモデリングに挑戦して Unity で動かしてみた

はじめに

Maya LT でのモデリング練習記の続きです。前回はローポリキャラクタモデリングに挑戦してみました。

そこで触れていたように、今回はスキニングモデリングに挑戦してみました。制作にかかった日数は、仕事から帰ってきて毎日ポチポチと進めて大体 3 週間位でした。

成果

デモ

完成して出力したデモになります。

WASD で走って移動、SHIFT 同時押しで歩きになります。

Maya でのモデル

f:id:hecomi:20150308001542p:plain f:id:hecomi:20150308002255p:plain

長い道のりだった...

参考書

前回に引き続き、こちらの書籍の後半の章を参考にしています。

MAYA LT 3D‐CG キャラクター講座 (I・O BOOKS)

MAYA LT 3D‐CG キャラクター講座 (I・O BOOKS)

キャラクタのデザインもこちらのサンプルとして紹介されている子を参考に作成します。本ではそんなにページが割かれていないのですが、重要なモデリングの流れについては一通り紹介されていてとても分かりやすかったです。完成品のサンプルもダウンロードできるので、目を血眼にしながら自分の作成したモデルと比較してどこがおかしいかチェックできてとても便利です(そしてかわいい)。

f:id:hecomi:20150307160329p:plain

以下、今後やる方の参考になればと思い、本では触れられていなかったハマリポイントなどを交えながら流れを紹介したいと思います。

制作の流れ

モデリング

まずは顔から作成します。本ではポリゴンを張っていく方式ではなくてプリミティブを分割して形にしていく手順が紹介されています。主に「モデリングツールキット」で「シンメトリの軸」を設定して対称に操作できるようにしてから「接続」ツールを利用してポチポチ分割していきます。「接続」では頂点またはエッジの中心を結ぶ形で新たな面を作成できるのですが、選択のモードが「頂点」の時は頂点のみ、「エッジ」の時はエッジのみ、「オブジェクトモード」の時は頂点もエッジも選択可能になるので、基本的にはオブジェクトモードで選択してから「接続」をクリックし、ポチポチと面を貼っていきます。

f:id:hecomi:20150307143058p:plain

面を張り替えたいときはエッジを消去してから頂点を消去し、再度、接続で分割を行います。こんな感じで作成した頂点を色んな角度から見て移動しながら形を作っていきます。

f:id:hecomi:20150307145334p:plain

たまにシンメトリが維持できなくなってしまうのですが、その時は落ち着いて再度シンメトリの軸を設定し直します。気付かずに作業を続けてしまった場合は、片側のフェースを削除してミラーして再度シンメトリの軸を設定すれば変更も反映できます。後は手順通りにポチポチと根気強く作っていきます。

横着して正面図と側面図を用意しないで進めていたので、全然思うように形が出来ず、めちゃくちゃ時間かかりました。

顔に引き続き身体も手順に従って作成します。

ちなみにテクスチャを描くときやウェイトペイントした時にまた大幅に修正していますが、あとでも問題なく修正出来るのでそれっぽくなったら次に進めてしまって良い気がします。

UV 展開

UV 展開はそれほどつまるところはありませんでした。手順通りにしたがってカットして、それぞれの形に応じてマッピングで投影します。「UV テクスチャエディタ」の「ポリゴン > 最適化」を使うと、UV を綺麗に展開してくれるので、まずは自動でやってもらった後に手動で気になる部分を動かして修正する、という形で進めました。

テクスチャ

頑張ってテクスチャを描いていきます。前回同様、テクスチャはイラレでポチポチと描いています。最初はテクスチャを当てるとどう見えるのか確かめるために仮絵を描いて見てみましたが、顔が相当ひどかったのでかなり時間をかけて手直ししました。

引き続き身体も描いていきます。

最終的にはこんな感じのテクスチャになりました。

f:id:hecomi:20150307153619p:plain

リギング・ウェイトペイント

「キャラクタコントロール」ウィンドウを使った作業になります。

f:id:hecomi:20150307160555p:plain

ケルトンを作成して各ジョイントの位置を調整しながら作成したモデルに埋め込んでいきます。その後「スムーズバインド」で自動で計算してもらったウェイトをポチポチと修正していきます。モーキャプされたデータを読み込んで適当なポーズをさせ、破綻がないように(関節が自然に曲がったり、服を突き抜けたりしないように)塗っていきます。

f:id:hecomi:20150307161934p:plain

左側だけ塗って右側へは「ウェイトのミラー」で反転コピーするのですが、この時、一度「バインドポーズに移動」でバインドポーズにしてからコピーしないとうまく反映されないっぽいです。

塗り終わったら、他にもダンスしているモーキャプのデータ等を読み込んで動きがおかしくないかチェックします。

ブレンドシェイプ

ポリゴン数が少ないのでブレンドシェイプは比較的簡単でした。

組み合わせで色々な顔が出来るのが面白いです。

f:id:hecomi:20150307162800p:plain

ただ、最初シンメトリの軸を設定し忘れていて、フェースを半分選択・削除 → メッシュのミラーで作成した顔をブレンドシェイプとして適用したら、壊れてやり直したのだけハマりました。

f:id:hecomi:20150307162939p:plain

Unity への送信

前回同様「Unityに送信」で FBX を Unity へ送ります。

で、動かしてみるとなんと肩のポリゴンが足らず見栄えが微妙なのと肩のジョイントの位置を勘違いしていて脇が開いているみたいな状態になってしまいました。また、首のジョイントの位置も下過ぎて妙に首が伸びたりします...。

f:id:hecomi:20150307164012p:plain

そこで、いったん Maya へ戻って修正することにしました。

メッシュの追加・ジョイント位置の修正

「スキン > スキンされたジョイントの移動ツール」が用意されているのですが、これで移動するとバインドポーズにしたときにポリゴンが崩れてしまいました。そこで、一旦別ファイルで保存しておき、「スキンのデタッチ」でスキニングを解除した後、モデリングツールキットでポリゴンを増やしたりジョイントを増やして再スキニングします。そして保存しておいたファイルを「ファイル > 読み込み」からインポートして、コピー元、コピー先の順番で選択し、「スキン > スキンウェイトのコピー」でウェイトをコピーします。これでポリゴン追加・ジョイント移動したモデルへのウェイトのコピーが出来ます。後は気になるところを同じようにウェイトペイントしたりしながら調整します。

Unity で再確認

再度 Unity へ送信します。

f:id:hecomi:20150307170512p:plain

正面から見た肩の分割点を 2 個増やしたのと、ジョイントの位置を調整したおかげでマシな感じになりました。

Unity で動かす

まず、モデルはカリングが効いてしまっているので、カリングを OFF にしたシェーダを作成します。

Shader "Custom/StandardCullOff" {
    Properties {
        _Color ("Color", Color) = (1,1,1,1)
        _MainTex ("Albedo (RGB)", 2D) = "white" {}
        _Glossiness ("Smoothness", Range(0,1)) = 0.5
        _Metallic ("Metallic", Range(0,1)) = 0.0
    }
    SubShader {
        Tags { "RenderType"="Opaque" }
        LOD 200
        Cull Off
        ZWrite On
        
        CGPROGRAM
        // Physically based Standard lighting model, and enable shadows on all light types
        #pragma surface surf Standard fullforwardshadows

        // Use shader model 3.0 target, to get nicer looking lighting
        #pragma target 3.0

        sampler2D _MainTex;

        struct Input {
            float2 uv_MainTex;
        };

        half _Glossiness;
        half _Metallic;
        fixed4 _Color;

        void surf (Input IN, inout SurfaceOutputStandard o) {
            // Albedo comes from a texture tinted by color
            fixed4 c = tex2D (_MainTex, IN.uv_MainTex) * _Color;
            o.Albedo = c.rgb;
            // Metallic and smoothness come from slider variables
            o.Metallic = _Metallic;
            o.Smoothness = _Glossiness;
            o.Alpha = c.a;
        }
        ENDCG
    }
    FallBack "Diffuse"
}

これを身体側のマテリアルに適用すれば髪の裏側等も見えるようになります。

ブレンドシェイプは顔のオブジェクトからアクセスできます。

f:id:hecomi:20150307174310p:plain

適当にランダムにいい感じにブレンドされるスクリプトを書いてアタッチすれば複雑な表情を作ることが出来ます。

using UnityEngine;
using System.Collections;

public class MorphSetter : MonoBehaviour
{
    private SkinnedMeshRenderer skinnedMeshRenderer_;

    public enum State {
        None,
        Forward,
        Stay,
        Backward
    };
    private State state_         = State.None;

    public int   morphIndex      = 0;
    public float frequency       = 0.8f;
    public float forwardTime     = 0.1f;
    public float stayTime        = 0.0f;
    public float backwardTime    = 0.1f;
    public float maxWeight       = 1.0f;
    public float damping         = 0.1f;

    private float weight_        = 0.0f;
    private float targetWeight_  = 0.0f;
    private float elapsedTime_   = 0.0f;

    void Awake ()
    {
        skinnedMeshRenderer_ = GetComponent<SkinnedMeshRenderer>();
    }

    void Update()
    {
        switch (state_) {
            case State.None:
                if (Random.value < frequency * Time.deltaTime) {
                    state_ = State.Forward;
                    targetWeight_ = maxWeight * 100;
                    elapsedTime_ = 0.0f;
                }
                break;
            case State.Forward:
                if (elapsedTime_ > forwardTime) {
                    state_ = State.Stay;
                    elapsedTime_ = 0.0f;
                };
                break;
            case State.Stay:
                if (elapsedTime_ > stayTime) {
                    state_ = State.Backward;
                    targetWeight_ = 0.0f;
                    elapsedTime_ = 0.0f;
                };
                break;
            case State.Backward:
                if (elapsedTime_ > backwardTime) {
                    state_ = State.None;
                    elapsedTime_ = 0.0f;
                };
                break;
        }

        elapsedTime_ += Time.deltaTime;
        weight_ += (targetWeight_- weight_) * damping;
        skinnedMeshRenderer_.SetBlendShapeWeight(morphIndex, weight_);
    }
}

f:id:hecomi:20150307175608p:plain

アニメーションについては作るのが面倒なので、取り敢えず Ethan のサンプル(Assets > Import Package > Characters)を読み込み、そこに用意されている Animator や Character Controller を使いまわします。

他にもトゥーンシェーダにしてみたりと遊んでみると楽しいです。

冒頭のデモは Unlit Texture です。

辛かったこと

すごい落ちます。

特にスキニング始めたあたりからは良く落ちるようになりました。おそらく参照を持ったオブジェクトが消えたりすると落ちているのではないかと思います。保存時に落ちることが多く、落ちた時にそのファイルは基本的に壊れます。代わりに前回保存した時のファイルが hoge.mltaXXXXX(XXXXX は数字)という名前でバックアップとして出来ます。壊れたファイルを消去し、.mlt にバックアップファイルを改名すると復元できます。

おわりに

ローポリモデルと比べると相当疲れましたが、何かライフワークになった感じして楽しかったです。色々とどうやったらうまく行ってどうやったらダメなのかもなんとなく掴めてきたので、心に余裕ができたらまた別のモデル作ってみたいです。後は人間だけじゃなくてモンスターとかもやってみたいですね。

RealSense が届いたので Unity で出来ることなどを詳しく調べてみた

はじめに

RealSense 3D カメラの F200 が届きました。

f:id:hecomi:20150223220832j:plain

RealSense は Intel による NUI 用のセンサ・SDK を扱うブランド名で、顔分析、手指・ジェスチャー検出、音声認識、背景除去、AR などが可能です。この前身として本ブログでも紹介したことのある Perceptual Computing という名称がありましたが、こちらを改めた形となるようです。

確かに「パーセプチュアル・コンピューティング」は技術視点な名前な気がするので、「リアル・センス」の方が短くコンセプト的なので分かりやすい改名だな、と思いました。

個人的にはインタラクションデモでの利用を想定していることから、Unity での活用を主軸に据えて調査してみました。本エントリでは、その調べた内容を共有したいと思います。

デモ

以前の空間図形認識モジュールを利用して魔法を描いてみました。

手のトラッキングを利用しています。例としては微妙かもしれませんが、RealSense 部分に関してはノンコーディングで出来ます。

背景

CES 2014 にて公開され、その後にも GDC 2014 や IFA 2014、都内のイベント等で発表されています。

RealSense モジュールを搭載したカメラとしては 3 種類準備しているようです。

今回届いたフロント用カメラの F200 の他に、タブレット用の Snapshot やリアカメラ用の R200 があるようです。Snapshot に関しては、先月発売の DELL Venue 8 7000(Android タブレット)に搭載していて、カメラ撮影時にデプス画も保存することで、Lytro のようにリフォーカスしたり、長さの計測などが撮影後に出来るようです。

また、SDK 自体は昨年にリリースされており、総額 100 万ドルの賞金のかかった App Challenge も行われていたようです。

未だ数は少ないですがアプリショーケースも公開されていて、いくつかのアプリを試すことが出来ます。

その他に RealSense でできることに関しては、Youtube にたくさん動画が上がっていますので、見ると何が出来そうなのか色々とつかめると思います。

スペック概要

見た目

F200 は PCSDK の頃のカメラ(Senz 3D)と同じく Creative 製で、Senz3D と比べると少し横に長いですが重さはそれほど変わりません。Leap Motion も並べて写真を撮ってみました。

f:id:hecomi:20150223221017j:plain

スペック

  • VGA(640x480 60fps) デプスカメ
    • 640x240 であれば 110 fps
    • 0.2 – 1.2 m の範囲
  • 1080p(30 fps) RGB カメラ
    • 848x480 以下は 60 fps

ラッキングについて

購入 / SDK のダウンロード / 開発に必要なスペック

購入

購入は以下から可能です。

価格は $99 で、送料は $24.81、総額 $123.81 で、Paypal で決済しました。キャンセルされていると勘違いして 2 個購入してしまったのですが、2個目は 2/3 に注文し、不在票が 2/20 に投函されていたので、2 週間ちょっとで届いた形になります。

必要マシンスペック

必要なスペックとしては、第4世代(Haswell)以降のインテル Core プロセッサ搭載の Windows 8.1 64bit PC が必要で、USB 3.0 ポートが必要です。また、Unity での開発には Pro 版が必要です。

SDKのダウンロード

SDK はこちらからダウンロードできます*1

ポチポチと進めていけば大丈夫ですが、1点、音声認識用に日本語用の辞書をチェックして入れておくことをおすすめします。

f:id:hecomi:20150223223313p:plain

これとは別に「F200 Depth Camera Manager」もダウンロード、インストールします。これをインストールしないと、デプス画が取得できません。

f:id:hecomi:20150223232738p:plain

サンプルの実行

Capture Viewer を起動すると、利用できるストリーム一覧が表示されます。

f:id:hecomi:20150224005921p:plain

Depth 640x240 110fps とか IR 640x480 300fps とかスゴイものたちも見えます。デプス画はこんな感じです。

f:id:hecomi:20150224010858p:plain

Intel RealSense SDK Sample Browser を起動すると、様々な言語のサンプルを試すことが出来ます。Unity のサンプルも含まれており、起動すると Unity のプロジェクトが立ち上がって動作させることが出来ます。以下は一例です。

FF がついたものが Front-Facing、前面カメラ用で、RF がついたものが Rear-Facing、背面カメラ用、DF がついたものが Dual-Facing で両面対応のサンプルになります。ここでは RF が

SDK の概要

概要

f:id:hecomi:20150223224914p:plain

SDK の構成としては、I/O や マルチモーダルな NUI 認識アルゴリズムのレイヤが最下層にあり、その上に C++ による SDK のインターフェースレイヤがあります。ユーザは、この SDK のレイヤを直接触るか、別の言語へのバインディングを通じて利用する形になります。

Unity の場合は、Web Player も考慮して、更に一層レイヤが積まれています。

f:id:hecomi:20150223225944p:plain f:id:hecomi:20150223230112p:plain

Web Player では Native プラグインの利用ができないので、JavaScript と同様にサーバ・クライアント方式で情報を取ってくるようです。Leap Motion とかと同じ一般的な方法ですね。

インターフェースには接頭辞として PXC[M] がついています。PXC はおそらく Perceptual(PX) Computing(C) の略で、M は Managed です。

f:id:hecomi:20150223225300p:plain

なお、デプスを利用しない一部の機能(顔検出や音声認識)については、F200 を持っていなくても利用できるようです。このアーキテクチャならプロ版じゃなくても出来そうですが...。

Unity Toolkit

上記の一層積まれたレイヤは、Unity Toolkit という層になっていて、Unity の Editor スクリプトの力を借りて RealSense SDK を簡単に扱えるようにした Script / Prefab 群になります。これについては後述します。

.unitypackage の場所

Unity Toolkit は、RealSense SDK をインストールしたディレクトリ下の RSSDK\framework\Unity にある RSUnityToolkit.unitypackage をインポートすることで自分のプロジェクトに加える事が出来ます。ここには Sample Browser で見た Unity のサンプルシーンが一通り含まれています。

なお、同ディレクトリにある Unity.PCStandalone.unitypackage は Unity Toolkit やサンプルを除いた C# バインディングの DLL(Native および Managed)、Unity.WebPlayer.unitypackage は Web Player 用の DLL(Managed)が含まれたパッケージになります。試してないですが、Web Player 用のパッケージを使えば Pro 版じゃなくても出来るかも...。

Unity でアプリを作ってみる

ではいよいよ Unity でのアプリを作成してみます。

Unity Toolkit の利用

Unity Toolkit は先述のように、最小限のコードのみで RealSense の機能を利用可能にできるよう、Unity のエディタ拡張を利用して便利にした Script / Prefab 群になります。Actions Triggerというものが用意されており、Trigger が手を検出した、トラッキングしてる、顔をロストした、みたいなイベントで、Actions がその結果として、GameObject を Active にしたり、動かしたりといったことをするものになります。Actions がスクリプト単位で分かれていて、ここにエディタ拡張で作られたメニューを通じてポチポチと Trigger と、その中に記述する Rule を設定していく形になります。

例えば、手のトラッキングのサンプル(Full Hand tracking-right Prefab)を見てみます。

f:id:hecomi:20150225005637p:plain

ルート要素には Activate ActionDeativate Action という Action がアタッチされています。これはその名の通り Trigger に応じて指定したオブジェクトの表示 / 非表示を担当するもので、Activate Action では Hand Detected Trigger によって hands joint を表示し、Deativate Action では Hand Lost Trigger で hands joint を非表示にするよう指定されています。Trigger の中を見ると、例えば Activate Action では、Which HandACCESS_ORDER_RIGHT_HANDS と右手が指定されており、Hand Index で 0 となっているので、最初の右手を見つけたら、という Rule が設定されています。

なんとなく掴めたと思いますので、同様に指のトラッキングを見てみます。

f:id:hecomi:20150225011748p:plain

Tracking Action という Continuous Action が設定されています。Continuous Action には Start Event / Process / Stop Event の 3 種類の Trigger を設定する形になっていて、Start Event が起きたら Stop Event が起きるまで Process が周る形になります。ここでは近距離-遠距離間で(どこでも良いので)手が見つかったら開始して、ロストしたら終了する、という Trigger が設定されていて、 Process では Tracked Joint で指定した指の部位に応じて Transform を変化させる形になっています。すべての指にこれを設定することで手のひらが作れる、という形になっているわけですね。

なお、Tracking Action では Hand TrackingFace TrackingObject Tracing がプルダウンリストから選択でき、それぞれインスペクタの項目が変化します。

他にも色々な Action があるのでサンプルを見たり試してみると色々と遊べると思います。

f:id:hecomi:20150225025202p:plain

C# バインディングの利用

Unity Toolkit はおそらく好き嫌いがありそうだな、と思います(個人的にはゴリゴリスクリプト書きたいのでイベントハンドラだけ出して欲しかった)。Unity Toolkit でできること以外に色々やりたい場合には、生の PXCMHogehoge を触れば可能です。例としては映像ソースを取ってくるといったことが挙げられますが、こちらに関しては Image Prefab にアタッチされている DrawImage.cs などを見てみると参考になると思います。より踏み込んだ詳細は Reference をご参照ください。

冒頭の魔法発射デモ

人差し指の Tip の Action / Trigger / Rule を流用して、以前公開した空間図形認識モジュールをそのオブジェクトへアタッチすると魔法が使えるようになります。これが冒頭のデモになります。

参考サイト

Unity を使った先行事例としては、中村 薫さんが Unity での利用方法による詳解や、Unity ちゃんの顔を自分の顔に同期させるデモを紹介されています。

別途ツイートをまとめてくださっている Togetter も参考になります。

所感

性能について

手のトラッキングに関して言えば Leap Motion の方が高速でロストしない印象ですが、こちらは正対した状態や障害物が近くにあってもトラッキングができるので、有利な面も多いと思います。あと辺なステートに入り込まない感じもします。

f:id:hecomi:20150225002058p:plain

代わりにトラッキングは結構遅い感じがしました。速い動きに対して追従性が良くないので、軌跡を利用するようなアプリケーションに使うのは難しそうです。冒頭のデモでは結構重くフィルタをかけています。

デプスに関しては Kinect v2 の方が綺麗なのと遠距離も可能ですが、かなり近接させても平気なので、小さいものの 3D スキャンや、小さな変化を追うような用途には向いてそうです(レゴも認識できそうでした)。

音声認識音声合成、顔の詳細なトラッキング、Metaio を使った AR や物体認識も SDK で使えるので、マルチモーダルなインタラクションデモを作成する、といった点では良さそうです。

その他

Alienware 17 の昨年モデルを使っているのですが、相性が悪いのか、なかなか接続がうまく行かず苦労しました...(未だに未解決)。RGB 画は安定して取れるのですが、IR やデプス画を撮ろうとすると接続が切断される、といった現象です。ワークアラウンドとしては、タスクマネージャから RealSenseDCM.exe(Depth Camera Manager)を Kill したり、FF_HandsViewer.exe とかが動きやすいので、これをまず起動させて止めてから、Unity に移るとやると安定しました(謎)。

おわりに

これだけのセンサ・SDK が 1 万円ちょっとで利用できるのは本当にすごいと思います。今回紹介できなかったオブジェクト認識周りや音声認識も組み合わせて、研究からゲームまで色々な用途に使えると思います。ただ一方で、マルチモーダルなインタラクション設計は相当難しいと思いますので、果たして生活を便利にするようなインターフェースにつながるかは、まだ若干懐疑的です。色々な人がアイディアを出しあって活発に議論されて、いろんな使い道が発掘されたら良いなと思いますので、興味のある方で未購入の方は是非買って試してみてください。

*1:会社情報などの入力が必要です(私は個人としました)