4 / 4 Skinned Meshの変形に追従する
生成時に選んだ表面の場所を保存し、位置と法線を毎フレーム取得して、毛をモデルの変形へ追従させます。
比較サンプルを確認する
Skinned Meshは、ボーンの位置や回転に応じて頂点が変形するメッシュです。
モデル全体をTransformで回す場合と異なり、足や胴体などの部分ごとに形が変わります。
第14回のウサギは静的なMeshなので、このページでは歩行アニメーションを持つChomperを使います。
Playを停止し、第14回のPackageに含まれるScenes/SkinnedSurfaceFur.unityを開いてください。
左のInitialize Onlyは生成時だけ位置と法線を取得し、右のUpdate Followingは生成後も取得を続けます。
本数・長さ・太さとSeedをそろえ、位置を取得する時点による違いを比較する構成です。
左は生成時の位置と向きを保った毛、右は変形後の表面から位置と法線を取得し続ける毛。歩行中のChomperを同じ条件で比較
Playし、足や胴体の動きを観察しましょう。
左の毛は生成時の場所に残ったままです。変形する表面との間にずれが生じます。
右では根元が表面と一緒に動き、毛の向きも変わります。
EditorのPauseとフレーム送りを使うと、小さなずれを確認しやすくなります。
実習ではSceneをSkinnedSurfaceFurPractice.unityとして複製します。
GraphのSkinnedSurfaceInitialize.vfxもSkinnedSurfacePractice.vfxへ複製し、左のモデルのBodyにあるVisual Effectへ割り当ててください。
右の完成見本は比較用に残します。
SkinnedMeshRendererをGraphへ渡す
静的なMeshでは、BlackboardのMesh型プロパティへMeshアセットを指定しました。
変形中の形を読むには、Scene上のSkinnedMeshRendererを参照します。
サンプルのSourceSkinnedMeshは、外部公開したSkinned Mesh Renderer型のプロパティです。
Hierarchyで左のモデルのBodyを選びます。
Visual EffectのSourceSkinnedMeshに、同じBodyのSkinnedMeshRendererが指定されていることを確認してください。
Graphを差し替えた後に参照が空になっていたら、BodyのSkinnedMeshRendererを指定し直します。
Graphでは、Sample MeshのSourceをSkinned Mesh Rendererにすると、Sample Skinned Meshとして扱えます。
見本はPlacement ModeをSurface、Surface CoordinatesをUniformとし、PositionとNormalを取得しています。
三角形の数は、同じ参照元のGet Skinned Mesh Triangle Countで取得してください。
Sample Meshの設定項目を参照してください。
サンプルではVisual EffectとSkinnedMeshRendererを同じGameObjectに配置し、パーティクルをLocal空間で扱います。
Skinned TransformはApply Local Root Transformです。
変形後の表面と毛の座標空間をそろえるため、実習中はこの設定を保ちます。
モデルのRead/Writeは有効にしてあります。
SkinnedMeshRendererのUpdate When Offscreenも有効にし、画面外でもサンプリング元の頂点を更新する設定です。
生成場所を保存する
同じ毛を同じ表面の場所へ追従させるには、どの三角形のどの位置から生えたかを保持します。
毎フレーム違う乱数で場所を選ぶと、毛の根元が表面を移動してしまいます。
配布GraphのBlackboardには、次のCustom Attributeを用意しています。
Custom Attributeは、パーティクルごとの保存領域です。
外部からGraph全体へ値を渡すプロパティとは区別して使います。
| Custom Attribute | 型 | 保存する情報 |
|---|---|---|
| triangleIndex | uint | 生成時に選んだ三角形の番号 |
| surfaceCoord | Vector2 | 選んだ三角形の内部で位置を求める二つの値 |
Initializeの先頭で、UInt型のRandomをtriangleIndexへ、Vector2型のRandomをsurfaceCoordへ保存します。
保存した値をGet Attributeで読み、Sample Skinned MeshのTriangleとSquareへの接続を確認してください。
三角形の選び方とSquareの意味は、14-2「Mesh の表面からパーティクルを生成」と共通です。
図を準備しています…
保存するのは、表面の場所を指定する情報です。
変形前のPositionだけを保存しても、ボーンが動いた後の位置は分かりません。
同じ三角形と面内座標から、その時点の位置を求め直します。
位置と法線をUpdateで取得する
複製したSkinnedSurfacePractice.vfxを開いてください。
Initializeには表面のPositionを使うSet Positionと、Normalを使うSet AxisYがあります。
Updateへ次の二つのBlockを追加します。
| UpdateのBlock | 接続元 | 更新するもの |
|---|---|---|
| Set Position | Sample Skinned MeshのPosition | 毛の根元 |
| Set AxisY | Normalを受け取るSafe Normalizeの出力 | 毛の伸びる向き |
まずSet Positionだけを追加し、Initializeでも使っているSample Skinned MeshのPositionを接続してください。
Playすると根元は表面に追従しますが、毛の向きは生成時のままです。
次にSet AxisYを追加し、既存のSafe Normalizeの出力を接続します。
Safe Normalizeでは法線の長さをそろえ、向きとして使います。
一つのSample Skinned Meshの出力を、InitializeとUpdateの両方へ接続できます。
同じノードでも、Initializeから使う処理は生成時に、Updateから使う処理は毎フレーム実行されます。
Updateでは新しい乱数を作らず、保存したtriangleIndexとsurfaceCoordを再利用してください。
毛のMesh、Scale、OutputのOrientは14-2と共通です。
位置のIntegration、寿命による消滅など、毛を固定するUpdateの設定も維持します。
表面の位置を直接設定するので、速度やForceによる移動を重ねる必要はありません。
追従を確かめる
練習用SceneをPlayし、左のモデルと右の完成見本を比較してください。
足が曲がる場面や、胴体が上下する場面でも、毛の根元と向きが表面に沿うかを確認します。
次に、UpdateのSet Positionだけを無効にした場合を予想しましょう。
Playを停止してBlockを無効にし、再度Playして表示を確かめてください。
根元は生成時の場所に残るため、動く表面との間にずれが生じます。
Playを停止してSet Positionを有効に戻し、今度はSet AxisYだけを無効にして再生します。
根元が動いても、毛の向きは更新されません。
比較後は両方のBlockを有効に戻してください。
この見本は、毛の根元と向きを表面へ追従させる構成です。
毛そのものの曲がりや、風による揺れは扱いません。
また、別のMeshへ差し替えると三角形の番号も変わるため、保存済みの場所をそのまま使わず、毛を再生成する必要があります。
- Meshアセットと、変形中のSkinnedMeshRendererの参照を区別できる。
- 保存した三角形番号と面内座標を使って、同じ表面の場所を取得できる。
- Updateで位置と法線を更新し、足や胴体の変形へ毛を追従させられる。