Unity で NVIDIA FleX を使って、柔体・流体表現で遊んでみた
閉じる
閉じる

新しい記事を投稿しました。シェアして読者に伝えましょう

×

Unity で NVIDIA FleX を使って、柔体・流体表現で遊んでみた

2018-12-29 00:36
  • 3
以下の動画の解説です。



■NVIDIA FleX についておさらい

 NVIDIA FleX は、パーティクル(粒子)で物体の衝突・変形を表現する物理演算機構です。
粒子同士の結合力を強固にした剛体、フレキシブルにした柔体、個々のパーティクルを独立させつつ一定の“粘り気"を与えた流体などを表現できます。

 性能的なデモは公式のページを参照のこと。
 ざっとした導入手順は、先日ざっと書いた記事にあるので、ざっとご参照ください。

 従来 uFlex という有料アセットがあったのですが、7月頃に NVIDIA FleX for Unity BETA が公開されました。こちらには、流体用のシェーダーも附属しており、粒子の“粘り気"や光の屈折などを容易に表現できます。

■今回やったこと

 ・PCにつないだゲームパッドでキャラクターを操作
 ・通常のゲームキャラクター状態と、液状化した状態とを相互に切り替える
 
T-1000みてーなやーつ

 ただし、液状化とは言っても、流体(FleX Array Actor/Source Actor)ではありません。原型をとどめていられないほど柔らかい柔体(FleX Soft Actor)に、流体用のシェーダを与えて、ジェルのように表現しました。
 また、NVIDIA 公式のスクリプトのままだと実現できないことがあったため、ソースを若干改変しています。

■通常時のキャラクターについて
 
 特殊なことはしていません。
 Unityちゃんのプレファブを配下に置いたゲームオブジェクトに Character Controller コンポーネントを与え、ゲームパッドの左スティック入力にしたがって Move メソッドで移動させています。また、Animator にアイドル状態/歩く/走るアニメーションを付与し、 左スティックのアナログ入力値を元にステート遷移させています。
 Character Controller の設定値よりも低い天井や、狭い通路は通り抜けることができません。

 ゲームパッドの特定ボタンを押すことで、液状化します。このとき、Unityちゃんの体を表示している全ての SkinnedMeshRenderer 達の親と、顔を表示している MeshRenderer 達の親を SetActive(false)して消し、代わりに液状化キャラクターを出現させます。

■液状化時のキャラクター
 
 まず、アイドルモーション中に SkinnedMeshRenderer を BakeMesh したものを結合し、新規メッシュを作りました。


 これを元に FlexSoftAsset を作成し、非常に柔らかく設定します。パーティクル総数は 640、クラスター数は 81 で、かなり軽量です。(GTX 750Ti だと、とりあえず 5,000/500くらいまでは余裕です)


 これを Flex Soft Actor に設定し、Fluid チェックボックスをオンにし、Flex Fluid Renderer を追加します。こうしてゲーム開始すると、パーティクル群によってシミュレートされた液体(実際は柔体)が地面にびちゃっと落ちて、そのまま停止します。

 さて、これだけでは、その後パーティクル群を任意に移動させることはできません。
 仮に FleX Soft Actor をアタッチしたゲームオブジェクトの transform.position を変更しても、無意味です。パーティクルの挙動は FleX によりワールドスペースで計算され、その結果から transform.position / rotation が自動算出されます。ゲームオブジェクトを動かすのではなく、FleX機構に働きかけて、パーティクルを移動させなければなりません。

 前回記事のように固定パーティクルを作って、それを移動する(この場合は transform.position の移動でOK)ことによって、他のパーティクルを追随させようと思ったのですが、紐か何かに引っ張られているような見た目になり、好ましくありませんでした。

追随させるためのパラメータ値のせいで、原型が残っちゃうしダメ

 そこで、FlexContainer.ParticleData の SetVelocity メソッドで、個々のパーティクルに物理的な運動を与えることにしました。これにより、全てのパーティクルが一様に動くようになりました。また、障害物に阻まれて動けなくなったり、変形したりもします。
 しかし、与える力が一様なので、地面におちた水溜りの形を保ったまま移動することになってしまいます。また、壁に当たることで長細く変形したあと、壁を離れても、その形を保ってしまいます。これでは、意思を持ったキャラクターのようにはいまいち見えません。

 → 
壁に当たって戻るとき、牽引する「コア」があってほしい 
(左側が出っ張ったのは、床の凹凸でたまたまそうなっただけ)

 そこで、SetVelocity メソッドで運動を与える際、全パーティクルの平均位置に重力点のようなものを加え、運動量に加算することにしました。
 こうすることで、移動中ははぐれメタルのような半固形化、移動をやめると水溜りにカモフラージュ、というような挙動になりました。

 以上の処理を行なうスクリプトは、FleX プラグインの外側に書くことができませんでした。仕方ないので、FlexActor のソースを改変することで対処しました。

■遷移のための処理

 通常時の間は、Flex Fluid Renderer の enable を false にし、表示を消しています。
 また、通常時キャラクターの位置と FlexSoftAsset の初期位置から算出したワールドスペース座標に、各パーティクルを毎フレーム強制移動しています(これもソース改変で対応しました)。
 液状化への切り替え時に Flex Fluid Renderer を enable にして出現させ、強制移動を取りやめることで、その場にびちゃっと落ちます。
 もう一度通常時のキャラクターに戻る際は、パーティクルの強制移動を再開します。ただし、即時移動しないよう、フレームごとに段階を追って移動させています。移動し終わったのを見計らって、パーティクルと Unityちゃんの表示/非常時を交代します。

■課題

 カメラをキャラクターに追随させる際、通常時は問題ないのですが、液状化時にうまくいきません。パーティクル群の「中心位置」(平均位置)がイマイチ確定しないからです。安直に計算してもガクガクと揺れてしまい、見るに耐えませんでした。
 そこで、即時移動するのではなく、ゆっくり推移するようにしたのですが、これはこれでちょっと酔う仕様になっています。はて、どうしたものやら。

 また、液状化時から通常時に戻る際のパーティクルの移動が、安直です。本当は、Unityちゃんの形をした器に、下から注ぎ込まれ、最後に両手や頭が埋まるような形にしたかったのです。なんとなく方法は思いついているのですが、本稿を書いてる間に日付が変わってタイムアップ。もっと面白いことを思いついたときに、ついでにやろうと思います。
広告
×
失礼します。これはすごいですね。NvidiaFlexにこんな使い方があるとは想像もできませんでした。もし宜しければ、FlexContainerの何行目にどのようなコードを書き込みをすれば良いのかお教え頂ければ幸いです。気が向いた時にでも、ご検討いただけると嬉しいです。活動応援しています。失礼しました。
6ヶ月前
×
こんにちは。ひとまず、柔体のパーティクル群を「はぐれメタル化」する手順について、最新エントリにまとめましたので、ご覧ください。
Unityちゃんの姿に戻っている部分に関しては、サンプルとしてまとめるのが少し難しいので、また後日手が空いたときに出そうと思います。
5ヶ月前
×
>>2
ての字様、返信ありがとうございます。早速読ませていただきます。本当にありがとうございます!
5ヶ月前
コメントを書く
コメントをするには、
ログインして下さい。