リアルタイム毛シミュレーション

2026年1月1日


2023年の時、学校からもらった課題のために、友達とゲームを制作しました。そのゲームの目的は、弓矢を使って巨像を倒すことです。 巨像には毛が生えているので、リアルタイムで毛をシミュレーションしようと考え、その部分を自分が担当しました。

以下は、Unityで録画したシミュレーションです:


まず、巨像のメッシュに適用した頂点シェーダーを使って、頂点の座標をバッファに保存します。

でも実は、頂点の座標ごとに各毛をインスタンス化するのは現実的ではありません。 なぜなら、メッシュの解像度が足りなくて、頂点数が少なすぎる、頂点の合間に巨像の表面が見えてしまい、 さらにメッシュの格子が目立ってしまうからです。

とはいえ、重心座標の おかげで頂点の合間に各毛をインスタンス化することができます。

C#スクリプト側で頂点の座標バッファを受けて、このデータを使っていくらでも各毛をインスタンス化します。 各毛の位置でメッシュ表面の法線を後で再構築するため、各毛ごとに重心座標と三角形の法線を保存します。
データの準備ができ次第、コンピュートシェーダーに送信して、毛のシミュレーションをそこで実行します。

| 「なぜ、新しいバッファでデータを送るより、むしろそのスクリプトで計算しないのですか?」

この段階ではまだCPU側なので、ここでシミュレーションを計算したら、実行速度が非常に遅くなる。 要するに、フレームごとに各毛の物理演算を逐次的に計算するということです。 この場合、各毛ごとに同じアルゴリズムを適用できます。このような処理はGPUが非常に得意としています。 GPUの並列処理を活用することで、数千本の毛を同時にシミュレーションすることができます。

このシミュレーションは簡単に説明できます。 各毛は、複数のバネの組み合わせとして計算します。 また、バネが伸縮しないように、各バネに長さの制約を適用します。 3つのバネを使用するため、4つの点を用います:



とはいえ、4つの点だけでは、毛の動きは滑らかになりません。 確かに、各毛が3つの線で構成されていることが目立ってしまいます。



この問題を解決するため、物理演算については性能を維持しつつ4点だけを使用しますが、各毛の頂点において、その4点から求心性Catmull–Romスプラインを生成し、滑らかに頂点座標を計算します。

各毛のメッシュ解像度を問わず、アルゴリズムが変わらないので、とても便利です。 頂点ごとに、UVのV成分を用いてCatmull–Romスプラインをサンプリングするだけです:



その結果、Catmull–Romスプラインを用いることで、各毛は数十点で構成されているように見えますが、計算上は4つの点のみを扱っています。

ところが、このサンプリング処理はコンピュートシェーダー側では行われません。なぜなら、コンピュートシェーダーは各毛のメッシュ解像度を何も知らないからです。


10頂点で構成された毛のメッシュ
10頂点で構成された毛のメッシュ
18頂点で構成された毛のメッシュ
18頂点で構成された毛のメッシュ

つまり、3つ目のシェーダーがあります。このシェーダーは各毛のメッシュに適用されます。頂点シェーダー側で、各毛がいつもカメラの方を向くようにしつつ、スプラインに沿って頂点座標を計算します。

以下は、頂点をカメラに向ける処理を行うコードです:

float3 forward = normalize(-UNITY_MATRIX_IT_MV[2].xyz);
// UNITY_MATRIX_IT_MV[2] is the direction of the camera.
float3 up = float3(0.0f, 1.0f, 0.0f);
float3 right = normalize(cross(forward, up));
up = normalize(cross(right, forward));
right = cross(up, forward);

そして、各毛の幅を表現するため、right 軸に沿って頂点をオフセットします。 その後、ピクセルシェーダーが各毛のレンダリングを行います。現時点では、単純な色のグラデーションだけです。^^

毛を生やすかどうかや毛の長さは、テクスチャによって制御されています。
左の画像は毛を生成するためのマスクで、右はその結果です:


毛を生成するためのマスク
毛を生成するためのマスク
マスクを使用して生成した毛
マスクを使用して生成した毛

各毛の幅や長さ、毛の数、重力や摩擦の強度は、マテリアルのパラメータによってリアルタイムで制御できます。

とはいえ、今後さらに改善したい点があります:

  • 毛のピクセルシェーダーを改善したいです。現時点では、各毛の根元から先端までの単純な色のグラデーションだけです。
  • 毛が巨像のメッシュと交差しないようにしたいです。
  • 各毛の形状をより面白くしたいです。現在は、フラットな法線を持つ長方形メッシュで表現しています。

読んでくれて、ありがとうございます!

興味があったら、こちらはゲームトレーラーです:


謝辞:

Avatar

Gaëtan Luitot 🌱

( ガガ )

テクニカルアーティスト

カテゴリ