(2020/09/29 仮公開。少しずつ参考画像などを増やしていきます。)
VRChatでの揺れ物表現、その中のClothコンポーネントについての深堀りです。
公式ドキュメントはこちらですが、ご覧の通りほとんど説明らしい説明がありません。これだけで使いこなせというのはあまりに無茶なもの。他の情報源に当たるほかありません。
Unityは物理シミュレーションにPhysXを利用していますが、公式ブログからUnity 2019.1以前ではPhysX 3.4のPxClothを、Unity 2019.2以降ではPhysX 4.xのNvClothを使用していることがわかります。
Unity 2018 4.20f1を使用するVRChatではPxClothことPhsyX 3.4のClothモジュールを参照することになります。PxClothのドキュメントはこちらで見られます。
TL;DR
- Clothは布のリアルタイム演算のためのコンポーネント
- 1シーンに頂点数2000、**Solver Frequency 300(Hz)**で12個が目安
- Self-Collisionは演算時間の大部分を占める。
- 目安を守って正しい設定をすれば、リアルで高速な布シミュレーションができる。
前提
執筆時点の環境は以下のとおりです。
- Unity 2018 4.20f1
- VRChat 2020.3.3p1, build 994
VRChatでの揺れ物
Unityで髪の毛や尻尾、衣装などを揺らす揺れ物表現には様々な方法がありますが、VRChatで使えるものとなるとかなり絞られてきます。有料アセットであるDynamicBone、Unity標準のCloth。他にもJointを使った方法なども見られますがここでは触れません。
DynamicBoneは有料アセットながら様々なVRChat向けアバターに採用されており、動作の安定性や何より資料の豊富さが利点と言えます。一方でボーン単位の処理のために1次元的な構造となり、平面的な物体での衝突判定は不得手なようです1。例えばスカートと脚の接触では、大きく脚が動いた際にスカートを突き抜けてしまいます。
一方、Unity標準搭載(つまり無料)のClothコンポーネントは布に特化したリアルタイムシミュレーションを提供します。布らしく上下左右が繋がっており、相互に作用し合います。基本的にはコライダーが突き抜けることもありません2。しかしながら利用者が少ないのか資料が少なく、何よりUnity公式のドキュメントも明らかに説明が足りていません。そこで、Unity内部で利用されているPxClothのドキュメントやこれまで筆者が実験した結果をもとにClothコンポーネントの概要を記すことにします。
Clothは重いのか?
特にVRChatに関する情報では「Clothコンポーネントは重い」といった声がよく聞かれます。ですが、Clothはリアルタイムシミュレーションのためのコンポーネントであり、十分に軽量化されています。接触ありのスカートの表現においては、他の手法より軽量化が見込めることが示唆される実験結果3もあります。
Clothコンポーネントは一部のプロパティーが計算量に大きく影響し、またパラメーターの意味が十分に説明されていません。このため、本来の設計から外れた使い方によって「重いCloth」が発生しているのではないでしょうか4。
プロパティー
まずはClothコンポーネントの各プロパティーについてその概要を記します。Unity公式のドキュメントをもとに、PhysXのドキュメントで補完したものになります。
Stretching Stiffness / Bending Stiffness
直訳すると引張剛性と曲げ剛性で、伸びにくさと曲がりにくさを0~1で設定します。小さいほど柔らかく、大きいほど固くなります。1だとほとんど動きませんが、小さすぎると形が崩れてきます。どちらも0.8から始めると良さそうです。
PxClothにおけるDistance Constraintsを設定していると思われます。Stretching Stiffnessが縦横の接続、Bending Stiffnessが縦横ひとつ飛ばしの接続に対応するはずです。対角線からなるねじれに対するパラメーターは存在しないようです。
Use Tethers
テザー制約を有効化します。PxClothは省略されたシミュレーションのために必要以上に伸びることがあります。テザー制約はこれを防止するもので、計算量が非常に少ないものです。有効化すると頂点が元の位置から離れ過ぎないようになります。基本的にはTrueのままで使うべきでしょう。
Use Gravity
重力を有効化します。無重力世界に生きている人以外はTrueにしましょう。
有効にするとシーン(ワールド)の重力加速度が適用されます。無重力のシーンでは0に、反重力では上方向の力がかかります。
5これを無視したい場合は無効にし、External Accelerationを使用することもできます。
Damping
速度の減衰係数です。各頂点の揺れの収束が早くなる。高すぎるとコライダーについて行けずに突き抜けてしまいます。0.1~0.5程度で試すと良さそうです。
External Acceleration / Random Acceleration
固定か、ランダムな加速度(力)を加え続けます。特別な表現をする場合を除いて0にします。
World Velocity Scale / World Acceleration Scale
速度、加速度の影響量6を調整します。どちらも0にすればどんな激しい動きでもめくれ上がる事はありません。特にVRChatではワープのような移動が頻発するため、制御が難しいと感じたら0すると良いでしょう。布の質感に応じて0.1~1.0の範囲で調整すると良さそうです。
Friction
コライダーとの摩擦係数です。微妙な差ではありますが、引っかかりが気になるなら0に、ひかっけたいなら1にしましょう。
Collision Mass Scale
各頂点の質量を増やします。布の重さの表現に使うものと思われます。ドキュメントによれば、使う場合は20から試すと良いそうです。
Use Continuous Collision
連続的接触を有効化します。高速で動く物体に対しての接触判定の精度が上がります。計算量は2倍になります。
Solver Frequency
計算の頻度で単位はHzです。Clothの挙動と計算量に大きく関わります。この値を大きくすることで改善する挙動が多いですが、計算量に直結するため他の方法を用いるべきです。一般的には120~300です。計算量はこの値に比例して増えます。
Use Virtual Particles / Virtual Particle Weights
バーチャル・パーティクルによって衝突判定の密度を上げます。Solver Frequencyや頂点数を増やさずに突き抜けを防止する機能です。衝突時だけに周囲の3頂点から生成されます。基本はTrue、Weightsはそのままにするべきです。
バーチャル・パーティクルの位置はVirtual Particle Weightsで定義されていますが、Unity 2018 4.20f1では3重になっているようです。バグでしょうか。
Sleep Threshold
スリープ状態になる頂点速度のしきい値を設定します。目に見える変化は少ないですが、現在1に上げて運用中です。
Capsule Colliders / Sphere Colliders
布と接触するコライダーを設定します。利用できるコライダーはカプセル、スフィア、テーパーカプセル(スフィアのペア)の3種類です。カプセルはテーパーのないテーパーカプセルの簡易表現と考えられます。ClothのコライダーはRigidBodyのそれとは別の概念であり、その形状だけが使われます。他のRigidBodyへの影響を避けるためにIsTriggerを有効にするべきでしょう。また、テーパーカプセルは同じスフィアコライダーを共有して連続した形状を作成できます。PxClothはこれを使うように推奨しています。
Constraints
Cloth全体のパラメーターの他に、頂点ごとの制約を加えられます。Max DistanceとSurface Penetrationの2種類が利用できます。
これらはPxClothの上に実装されたUnity独自の機能でありながら、ドキュメントがほぼ存在しません。この仕様を探るには、コミュニティーフォーラムに投稿されたUnity5に関する解答が参考になります。(情報提供:いしだえいとさん)
画像:https://answers.unity.com/questions/956610/excluding-vertices-from-cloth-colliders-in-unity-5.html より引用
Max Distance
頂点が元の位置から移動できる最大の距離を設定します。単位はmで、0~無限大が設定できます。オブジェクトのスケールの影響を受けます。スカートのウェストなど、固定する部分は0にします7。その他の部分は挙動の調整に使われたりもします。0で固定されていても、コライダーの影響は受けます。
PxClothのMotion Constraintsを簡略化したものと考えられます。中心がメッシュの頂点座標、半径がMax Distanceに対応します。
Surface Penetration
複雑な割に解説が存在しない制約です。その上、使い方を間違えるとどこかで頂点座標がNaNになり、メッシュが消滅します。値は0~無限大で、単位はmだと思われます。
上記の画像を紐解くと、メッシュの「内側にめり込める距離」と考えられます。頂点の法線の反対方向に移動できる距離を制限します。法線方向には制限しません。片側に限定したMax Distanceとも言えます。
PxClothにはこれを直接実現する機能は存在していません。そのため、Separation Constraintsを使って頂点が侵入できない球を設置しています。この半径はMax Distanceの2倍で、その表面で最も近い点と頂点との距離がSurface Penetrationとなります。半径がMax Distanceに依存しているため、Max Distanceが初期値の無限大のときこの球の半径は無限大となり、頂点はどこにも存在できなくなります。このためNaNが発生すると考えられます。
Self Collision / Inter Collision
PxClothのドキュメントに
計算の大部分を占める可能性がある
とある通り、重い処理です。よくわからずに使うべきではないと思われるのでここでは省略します。
パフォーマンス(軽量化)
PxCloth、すなわちClothコンポーネントの計算量は頂点数とSolver Frequencyに比例8します。Continuous Collisionで計算量はさらに2倍になります。PxClothのドキュメントによれば2000頂点、Solver Frequency 300Hzが目安になり、12個までリアルタイムにシミュレーションできます。頂点数が多いほど、Solver Frequencyが高いほどリアルなシミュレーション結果に近づきますが、その分負荷も激増します。これらは可能な限り低く抑え、他のパラメーターで調整しましょう。
具体的な値は示されていませんが、Self CollisionとInter Collisionは他の計算よりかなり重い処理になります。
メッシュの頂点とClothパーティクル
ここまで頂点という表現を使ってきました。各ドキュメントを読んでいる方は違和感を覚えたことでしょう。Clothコンポーネントのシミュレーション対象はパーティクル(UnityのParticle Systemと混同を避けるため、以降はClothパーティクルとします)と表現されています。これは、内部で使用されているPxClothはメッシュと関係なく任意のClothパーティクルをシミュレーションの対象としているためです。この概念を利用すれば、レンダリング用の高解像度なメッシュとシミュレーション用の低解像度のClothパーティクルを組み合わせることができるはずです。しかし、UnityのClothコンポーネントはメッシュの頂点をすべてClothパーティクルにしてしまいます。結果としてメッシュ自体のモデリングにも頂点数の制限が課されてしまっています。資料の少なさに加えて、こういった制約がClothコンポーネントのハードルを高めているのかもしれません。
まとめ
ToDo: いかがでしたか?ってひつようですか?