アイテムをアバターから切り離しワールド固定にする方法(パーティクル不使用版)【VRChat技術情報】
物を置きたいよね
1:40あたりをシークしてください
アバターから切り離したり、独立して動いたりする、いわゆるワールド座標固定のオブジェクトと言えば今まではワールド座標シミュレーションのメッシュパーティクルが常識でした。
メッシュパーティクルはワールド座標に対する角度姿勢が固定(例えれば常に北を向くような動き)だったり、単一のメッシュしか描画できないなど制約が多くありました。
しかし新しく空のオブジェクトをワールド座標に固定する方法が発見され、急速に流行りつつあります。
たくさん作れるメッシュパーティクルに対して、オブジェクトそのものはあらかじめ作っておいたそのものしか扱えない弱点があるにはありますが、オブジェクトの中身はいくらでも複雑に構成でき、もちろんパーティクルを内包してもいいわけで、実質ほとんど上位互換の表現として働きます。
弱点としては物理演算を利用するので壊れやすいことと、同期が完全ではないこと。安定性と表現力の面で最強のシェーダー芸には劣りますが、コードを書く必要が無いので誰でも導入できるのが魅力です。
発想次第でいくらでも応用が利くので、覚えておくと何かのヒントになるかも知れません。
とりあえずやり方だけ教えてという人向け
まず実装方法だけ紹介します。
まず下の図のようにオブジェクトを追加してください。
構成:
アーマチュア内
┗hand.L(任意のボーンでよい)
┗hand.L-Grab_Sistem(引き剥がしたオブジェクトの戻り先)
アバターのルート直下
┗Detach_System(オブジェクトを切り離しワールドに固定するための空間)
┗Relese_Object(取り外しするオブジェクトの格納パッケージ)
┗Cube(ここでは例でキューブを入れているが入れるものは何でも良い)
まず、以下の3つ空のオブジェクトを作り、画像のように配置してください。
hand.L-Grab_Sistem
Detach_System
Relese_Object
以上の3つ。
名前はもちろん任意ですが、この記事を見ながら実装する場合はとりあえず揃えるとわかりやすいかも知れません。
次にHierarcyウィンドウを右クリックで3DobjectからCubeを作成し、Relese_Objectの中に格納します。Cubeは初期設定でコライダーが入っているので、オフか削除しておきましょう。重くなるだけでなく安定性が悪化します。
初期値だとサイズが大きすぎたり手の位置と合致していないので、Transformの値を調整して良い感じにしてください。
これでHierarcyウィンドウ上の構成は同じようになったはずです。あとはそれぞれにコンポーネントを追加すればほとんど設定終わりです。手っ取り早く画像を張るので、同様の設定にしてください。
hand.L-Grab_Sistem
Detach_System
Relese_Object
以上です。
この設定で「Release_Object」の「Rigidbody」の「Is Kinematic」のオンで切り離し、オフで引き寄せが行えるようになっています。
あとはアニメーションオーバーライドにIs Kinematicのオンをするアニメーションを追加すれば完了です。
アニメーションオーバーライドの設定は日本語の記事で他にたくさんあるのでそちらを参照してください。
瞬間移動ではなくバネのように引き寄せる方法
上記の方法だと引き寄せの時オブジェクトが瞬間移動してくるので、冒頭の動画のようにはなりません。
動画のバージョンはオブジェクトはそのものが独立した空間を内包しているのを利用して、上記のものよりさらに入れ子構造にし、複数のジョイントを交互に作用させることで実現させます。
この記事では詳細は説明しませんが、実際に作っていじってみると分かってくると思います。
構成
Release_Objectの下にSpling_Objectという空のオブジェクトを追加し、Cubeをその下に移動させました。
他の設定は同じなので省略。
Spling_Object
Configuration jointの設定はスプリングジョイントに回転方向のバネを追加した設定です。
X Drive、Y Drive、Z Drive、Angular X Drive、Angular YZ Driveを同値に設定します。
「Is Kinematic」のオフでバネが働き左手に引き寄せられます。
アニメーションとしては「Release_Object」と「Spling_Object」それぞれの「Is Kinematic」のオンオフを個別に変更する物を作りViveコントローラーで両手を使って任意に切り替える方法と、
操作を簡略化するため「Release_Object」の「Is Kinematic」をオンにするアニメーションと、「Release_Object」の「Is Kinematic」をオフ、「Spling_Object」の「Is Kinematic」をオフにするアニメーションを作る方法があると思います。
説明は足らないとは思いますがめんどくさいのであとは頑張ってください。触っていれば理解が進むので一石二鳥です。
しくみの解説
これのキモはDetach_Systemにあります。
Fixed Jointにかかわらず、Joint系のコンポーネントでConnedted Bodyを指定しない場合、Unityの仕様上そのオブジェクトはワールド座標に固定されます。(公式ページにも書いてある正しい仕様です)
これを利用して、Detach_Systemを仮想的なワールド座標として扱えるようにしています。
Release_Objectはワールド座標に存在することになりますが、Fixed Jointでhand.L-Grab_sistemに接続されているため初期状態では左手と全く同じ動きをするので初期姿勢の相対位置を保ち続けます。
Is Kinematicをオンにすると、物理演算から一時的に除外され所属する座標系にとどまるようになります。つまりRelease_ObjectのIs Kinematicをオンにすると、Detach_System内の仮想のワールド座標に固定できるわけです。
Is Kinematicを再びオフにすると、Fixed JointはIs Kinematicがオンになる前の相対位置に戻す働きをするので、元の左手の位置に引き寄せられる。というようになります。
Detach_Systemの仮想的なワールド座標とオブジェクトを独立した空間として利用するアプローチ、JointとIs Kinematicの相互作用は様々な応用が効くテクニックだと思います。これならコードが描けなくても面白い物をたくさん作れます。頑張って理解してください。
2017版で動作しなくなった場合の対処について
具体的には、 connected body を指定しない設定にしているFixed joint がある Game Object に、 Animator を追加して Apply Root Motion にチェックを入れるといけた(Controller には適当に空の AnimatorController を入れておく) pic.twitter.com/HArBkdwnc8
— あんころもち (@ankoro199) December 15, 2018