Bakulog

獏の夢日記的な何か。

VRMに風っぽい効果を与える方法

技術記事です。GitHubにレポジトリを置いたので、それの紹介みたいな感じです。

  1. やりたいこと
  2. 先行事例
  3. 作ったもの、ポイント
  4. やってないこと

 

1. やりたいこと

「動的にロードしたVRMアバターの髪を揺らしたい」というのがモチベーションです。

拙作「VMagicMirror」の最新版(v0.9.3)で実際に動かしたのがコチラ。

 

ツイート中でも言及していますが、そもそもはAniCast Makerの取り組みを参考にして作っています。13:20あたりが該当箇所なので、あわせてご覧下さい。

learning.unity3d.jp

 

2. 先行事例

VRMSpringBonecenterを使った方法が試されています。

lasmi.booth.pm

これも良いんですが、個人的にはちょっと設定がトリッキーに感じて採用を見送りました。

 

3. 作ったもの、ポイント

GitHubはコチラです。

github.com

導入手順等についてはGitHubのほうを見て下さい。

こちらでは計算アプローチを紹介しますが、発想は非常にストレートフォワードです。

  • 風が吹くことを力の一種として表現することにする
  • キャラが持っている`VRMSpringBone‘を拾い集める
  • 集めたVRMSpringBoneのそれぞれについて、重力項のm_gravityDirm_GravityPowerから求まる力ベクトルに、風のベクトルを後乗せした値を書き込む
  • 風の強さを時間に応じて強弱させて、風っぽさを増す

コツは「最初から入っている重力+風で作った力」というのを常に与え続けることです。

//windItem: 時間に応じて風の向きと強さを計算している別の要素
Vector3 windForce = Vector3.zero;
for (int i = 0; i < _windItems.Count; i++)
{
    windForce += _windItems[i].CurrentFactor * _windItems[i].Orientation;
}

for (int i = 0; i < _springBones.Length; i++)
{
    var bone = _springBones[i];
    //NOTE: 力を合成して斜めに力をかけるのが狙い
    var forceSum = _originalGravityFactors[i] * _originalGravityDirections[i] + windForce;
    bone.m_gravityDir = forceSum.normalized;
    bone.m_gravityPower = forceSum.magnitude;
}

これも重力を曲げている点でたいがい胡散臭いんですが、それでも力として扱えると気がラクなので、私は好きです。

 

4. やってないこと

今回の実装ではVRMSpringBoneを無差別に拾うようになっています。

そのため、以下のような挙動は実現できません。

  • 髪だけ揺らしたい、スカートと胸は揺れて欲しくない
  • 髪とスカートを別方向に揺らしたい

これらに対応するためには、各VRMSpringBoneがアタッチされたボーンがHumanoidBonesのどのボーンの子なのか調べるのが良いと思います。

例えばHeadの子なら髪であると推定できますし、Hips付近の子ならばスカートの可能性が高いです。

この辺は大いに改善の余地があるので、各人の都合でいい感じにしてもらえればと思います。