見出し画像

VRChatのワールドで持てるオブジェクトの作り方 ~VRC_Pickupのあれこれ~

VRChatのワールド製作で持つことが出来るオブジェクトを作る際にはVRC_Pickupというコンポーネントが必要になります。

VRC_PickupはVRChat上でオブジェクトを持つこと(=ピックアップ)が出来るようにするためのコンポーネントです。ただし、単体では意味が無く、ColliderとRigidbodyという二つのコンポーネントを一緒に付ける必要があります。

そのため設定項目が多く、注意すべき点が複数あるので、この記事ではVRC_Pickupの設定方法や注意点などについて解説したいと思います。

幾つか事前知識が必要になるので、用語が分からない人は以下の単語をふわっとでもいいので理解しておくと読みやすいかもしれません。
(下線が引かれているものは以前私が解説記事を書いているので、その記事へのリンクを貼っています)
▼推奨
コンポーネント
コライダー(Coliider&Rigidbody)
▼必要に応じて
レイヤー 
・Udon
Unityの親子関係

基本的な設定方法について

まずはVRC_Pickupコンポーネントを付けると、自動的にRigidbodyコンポーネントも追加されますので、あとはColliderコンポーネントを付けます。

基本的にどんなゲームオブジェクトでも付けることができます。

VRC_Pickupを付けた時点でレイヤーがPickupになるので、レイヤーについてはそのままで大丈夫です。

ここから各コンポーネントの値をいじることで、ピックアップオブジェクトの特性を変えていくわけですが、まずは基本的な構成として以下の特性を持ったピックアップオブジェクトを作成しようと思います。
・他のオブジェクトに衝突しない(すり抜ける)
・ローカル(他の人に同期しない)
・重力落下しない(物理演算の影響を受けない)

赤枠で囲った部分が、各コンポーネントで初期値から変更した部分です。

それぞれ簡単に説明します。
①RigidbodyのIs Kinematicはチェックを入れると物理演算しなくなります。この時点で重力の計算はされなくなると思いますが、心配な人はUse Gravityのチェックを外したほうが良いと思います(私は念のためチェックを外す派です)
②ColliderのIs Triggerにチェックを入れると、コライダーがただの当たり判定として扱えるようになります。これにより他のオブジェクトに衝突しなくなります。

あとIs Kinematicを入れてると、投げようとしてもピタッと止まる挙動になります(物理演算が切れてるので)

基本的な設定方法は以上です。
あとは色々なケースについてそれぞれ説明していこうと思います。

▼グローバル(他の人に同期する)にしたい

追加でVRC_Object syncというコンポーネントを付けるのがスタンダードです。設定項目はほとんどなく、そのまま付けるだけで大丈夫です。後から来た人にも同期します。

ただしObjectsyncは高頻度で同期を取っているため、ネットワークの負荷が高いといわれています。Udonでのネットワーク通信量には上限が設けられているので、沢山ピックアップできるオブジェクトを置きたい場合は注意が必要です。

そのため、より軽量な同期ピックアップとして、いくつかの方法がユーザーによって提供されているので、同期による負荷で問題が出てきた場合にはそれらの方法を使うほうが良いかもしれません。以下にリンクを張っておきます。

▼重力落下させたい

Use Gravityにチェックを入れ、Is Kinematicのチェックを外します。

落下速度はRigidbodyのDragの値で調節してもいいですし、Edit→Project Settings→PhysicsのGravityをいじってもいいです(その場合プレイヤーの重力も変更されます)

この時、ColliderのIs Triggerにチェックを入れていると、地面や壁をすり抜けてしまいます。そのため、衝突するようにしたい場合は、Is Triggerのチェックを外しましょう。
(すり抜けて落ちてった場合、リスポーンする高さまで落下するとオブジェクトがリスポーンします)

Is Triggerのチェックを外したら、判定がなくなるのでは……?と心配する人もいるかもしれませんが、Is Triggerのチェックが無くても判定は行われます。

Is Trigger自体は『コライダーの壁としての役割をなくしますか?』といった感じのスイッチみたいだなと私は思っています。

またPickupを付けたときに自動的にレイヤーが{Pickup}になり、Pickupレイヤーはプレイヤーと衝突しない設定になっているため、Is Triggerのチェックを外しても、プレイヤーに衝突する恐れはありません。

▼持ったオブジェクトが手元に引き寄せられる挙動を止めたい

デフォルトだとオブジェクトを持った時に手元に引き寄せられてしまいます。

PickupコンポーネントのOrientationをGripまたはGunにするとその位置のままオブジェクトを持てます。ミラーとか手元で扱いたいオブジェクトはそのほうが便利なケースがあります。
(備考 : おそらくExact GunとExact GripがNone(未指定)になっているので、手元に引き寄せられずに持てるものだと推測)

▼デスクトップモードの時に、一度持ったらドロップボタンを押すまで持ち続けたい

Auto HoldをYesにすることで保持できます。Auto Holdはデスクトップユーザーのみ機能します。VRユーザーは特に関係ないです。

以下frou01さんから情報いただきました!これを見ると長く持ち続けることを想定するオブジェクトは、Auto HoldをYesにしておいたほうが良さそうですね……情報ありがとうございます!!

Auto Holdは一部コントローラーでは使えるようです。
特に静電容量感知系のコントローラーでは有効になっていないと持ち続けるのがつらいらしく有効にするよう頼まれたりします。

▼手に取る時に表示されるテキストを変えたい

Interaction Textに表示したい文字を記載すればOKです。

▼他人に奪い取られないようにしたい

基本的にはDisallow Theftをオンにすると奪い取れないです。
ただ、試したことないのでこれは憶測ですが、Udonでオーナーシップのやり取りをしてると、この設定でも奪い取れるかもしれません。

▼特定の時に持てないようにしたい

他にも方法はあると思いますが、私ならUdonかAnimationでColliderコンポーネントをオフにします。オフにすると判定が無くなるので、持てなくなります。

Twitter見てるとVRC_pickup自体はGetComponentで取れないらしいので、Colliderを切るのが一番良さそうかなとおもっています。

追記:VRC_PickupのPickupableをOFFにする形なら、Box Colliderの衝突判定を残したまま持てなくできるという情報を頂きました。衝突判定を残したい場合は便利そうです!

また、VRC_PickupはGetComponent出来るようです。やり方はコメント欄に詳しく書いていただいております。

みみーさん(https://twitter.com/mimyquality)ありがとうございます!

▼ピックアップ中にのみインタラクトできるようにしたい

インタラクトした後の挙動をUdonで作る必要があります。

ピックアップした状態でトリガーを押したときの処理はOnPickupUseDown()、トリガーを離したときの処理はOnPickupUseUp()で作ることが出来ます。

Interact()で作ると、ピックアップしてない時もインタラクト出来る状態になるので、使い分けするとよいと思います。

作成したUdonをゲームオブジェクトにつけた後、デスクトップユーザーがピックアップ後も操作できるようにAuto HoldをYesにしておく必要があります。

VRC_Pickup内のUse Textはピックアップ中に表示されるインタラクト用の文章です。

▼手に取った時・手を離したときに特定の処理をしたい

上記同様Udonで処理します。

ピックアップした時の処理はOnPickup()、手放したときの処理はOnDrop()で作ることが出来ます。

こちらはAuto Holdの設定はどちらでも問題ありません。

各種トラブルシューティング等

▼ピックアップしたオブジェクトが変形する

こういう現象です(若干見づらくて申し訳ない)

これはHierarchy上で親子関係にあるオブジェクトがあり、その子オブジェクトに対してVRC_Pickupを付けたときに、親オブジェクトのスケールの比率が1:1:1ではない時に発生します。
親オブジェクトのスケールの比率を1:1:1にしましょう。

ちなみにモデル(FBX)の原点(Pivot)位置が大幅にずれていると、凄い挙動をします。

Special Thanks : あっとさん(https://twitter.com/Atto_VRC)
(再現条件を教えてくださいました、感謝!)

▼なぜか判定だけが取れる

こういう現象です。

まずはVRC_PickupのついたオブジェクトのStaticにチェックを入れていないかどうか確認しましょう。ゲームオブジェクトを選択中に、Inspectorの右上にStaticのチェックボックスがあります。

ピックアップするオブジェクトは当然ながら動かす(=動的な)物体なのでStatic(静的な)オブジェクトではありません。Staticは基本的に入れないようにしましょう。

▼そもそも判定がない

Collider系を入れていない場合か、あとはMeshColliderを利用しているときに、Meshが指定されていないとこうなることがあるようです。
前者はCollider系を入れる、後者はMeshを指定してあげればOKです。

▼持つと荒ぶる

これの原因を私はつかめてなかったのですが、この記事の下調べの際に他の方のnoteにそれらしき情報が載っていました。感謝。

ちなみに私も1回この現象にあったことがあり、Object Syncを付けた同期オブジェクトだったのですが、他人視点からのみ荒ぶるという現象が発生してました。

その時のオブジェクトはUnity製のメッシュ結合をおこなうアセットで結合していたので、Pivotがズレたんだろうなと推測しています。

▼ピックアップオブジェクトだけ真っ暗

上で言った通りStaticにチェックが入れられないので、基本的にはライトベイクできませんので、リアルタイムライトを利用していない人はオブジェクトが真っ暗になって、『どうしよう……』ってなるかもしれません。

幾つか方法があるので列挙します。
①光源の計算をしないUnlit系のシェーダーに切り替える
②LightProbeでライトベイク結果を反映してあげる
③Pickupレイヤーにのみ、リアルタイムライトを当ててあげる。
丁寧にやるなら②ですが、①,③がお手軽かなと思います。陰影が要らないなら①で、必要なら③です。
沢山ピックアップオブジェクトがある場合は、③だとFPSが落ちて重くなってしまう可能性が高いので、その場合は①か②にしてあげると良いです。

ちなみに動かす物体でも無理やりベイクする方法はありますが、陰影が固定された状態になるのでお勧めはしません(Staticの右側のドロップダウンからContributed GIにのみチェックを入れてベイク)

▼なんか他のVRC_Pickupの記事にVRC_Triggerって出てくるんだけど何?

昔のVRChatでは、VRC_TriggerというコンポーネントとセットでVRC_Pickupを使用していました。

その頃は今使われているSDK3の前身である、SDK2が利用されていた時期です。今はSDK3への移行にともない、VRC_Triggerは廃止されているので注意が必要です。

今はVRC_Triggerの代わりとして、もっと自由度の高いUdonが提供されている形です。VRC_Triggerで出来てたことはUdonで出来ます。

VRC_Pickupの昔の記事を読む際に気にするべき点は、それくらいだと思います。VRC_Pickup自体の性質は私の把握している限りでは全く変わっていないはずなので、VRC_Trigger周りの話を読み飛ばせば、昔の記事でも問題ないと思います。

▼その他Pickup関係のUdonギミックのリンク

リンクを貼りますが、Udon関係はアップデートが頻繁に行われているので、きちんと動くことを私は保証しません。実際Pickup周りは複雑なので、個々人の環境によって動かないことも十分あります。
まぁ、こういうギミックがあるんだなーくらいに覚えといてもらえれば、きちんと動くギミックを探す時に便利かなと思います。

おわりに

思いつく限り書き出してみましたが、VRC_Pickup自体は昔からあるコンポーネントなので記事が沢山有り、それらの記事と重複する点は多いです。

細かい仕様まで検証されている記事だとnaqtnさんの記事はお勧めです。今回紹介しなかったパラメータについても、かなり詳しく載っています。
(ただし、記事の更新日自体は古いので、上に書いた通りVRC_Triggerの話とかはスルーすると良いです)

ワールドにピックアップオブジェクトを置く際にこの記事を役立てて頂けたら幸いです。
読了、お疲れ様でした。


おまけの実証結果
Pickup以外のレイヤーへの変更はOK、変更してもPickup可能。
コライダーの境界の内と外でレイキャストは遮断される。そのためコライダーの外側から、内側のピックアップを引き寄せることはできない。
ただし、内側から内側のピックアップを持つことは可能。つまり、コライダーの境界を邪魔にならないように、uGUIの操作やピックアップする場所に持ってこないことが重要。もしくはコライダー側にレイキャストを遮断しないMirrorReflectionレイヤーを使用するのも1手か。

この記事が気に入ったらサポートをしてみませんか?