Programming in VRChat

VRChat でのプログラミングについて調べたことの書き溜め

Pickup

オブジェクトに VRC_Pickup コンポーネントを追加すると、アバターで拾い上げ操作ができるオブジェクトになる。

基本

  • 拾い上げる操作を付与したいオブジェクトに VRC_Pickup コンポーネントを追加する
  • アバターがオブジェクトを持ち続ける(Hold する)方法の違いで二つの動作設定がある
    • これは Auto Hold の設定によって決まる
    • Auto Hold 無効時:持ち続けるには拾い上げ操作を維持しつつづける必要がある
    • Auto Hold 有効時:操作無しにオブジェクトを持ったままになる
      • 「装備する(Equip)」とも表現される。
      • この使い方では、装備し続けた状態でそこから「使う」操作が可能。
      • (銃を装備してから、トリガーを引いて銃弾発射、のような使い方)

物理演算

  • VRC_Pickup コンポーネントを利用するオブジェクトは Unity の Rigidbody, Collider コンポーネントも備わっている必要がある
  • Rigidbody は備えていなければ自動的に追加される
  • Collider には Rigidbody のような Unity の編集状態でのケアは無いようだ。 ただし備えていないと実行時には hover が表示されず pickup 操作は行えない(ので実質必須)。
  • 以上により、必然的にこのオブジェクトは Unity の物理演算の機構に従うことになる。

操作とトリガー

VRC_Pickup は取り上げたり離したりするタイミングで処理を記述できるようにするトリガーを提供する。 ここでは操作を説明の軸にして、発生するトリガーを説明する。

  • 行いたい処理内容は VRC_Pickup ではなく VRC_Trigger コンポーネントに記述する。
    • (同じオブジェクトに VRC_Trigger コンポーネントを追加し、その中にトリガー設定を追加し、それぞれのタイミングで行いたい内容を設定する。)
  • 下記での hover はアプリケーションのシステム設定 SHOW TOOL TIPS を有効にしている場合に表示される操作案内
  • トリガーにある Interaction Text は意味がない模様
  • (動作仕様調査は 0.12.0p14 にて実施)

Auto Hold 無効時

持ち続けるには取り上げ操作を維持する必要がある使い方。

操作 トリガー名称 hover
取り上げる OnPickup "Hold to Grab"
離す OnDrop "Release to Drop"
投げる OnDrop "Hold/Release to Throw"(デスクトップモードのみ)
  • 「離す」と「投げる」操作はトリガーでは区別がない。
  • デスクトップモードでは投げ操作について明示的に案内される。(投げ操作自体は Auto Hold 有効時でも可能)
    • VR モードではオブジェクトを動かしている時に「離す」とその時の速度が残ることで「投げる」になる(実際の速度は VRC_Pickup の設定による)
  • デスクトップモードの投げる動作は(取り上げ操作であるマウス左の押し込みを維持したまま)マウス右クリック。
    • 押し込んでいる時間(溜め時間)を長くすると投げだし速度が大きくなる。(実際の速度は VRC_Pickup の設定による)

Auto Hold 有効時

取り上げ操作を維持せずに持ち続けられる“装備する”使い方。

操作 トリガー名称 hover
取り上げる OnPickup "Equip"
使用操作ボタンを押す OnPickupUseDown VRC_Pickup の Use Text
使用操作ボタンを離す OnPickupUseUp (無し)
装備を解除する OnDrop "Drop"
  • 装備した状態でさらに「使用(use)」操作ができる。
  • hover は表示されないが投げ操作も可能。(別記「Auto Hold 無効時」を参照)

分かりにくいパラメタの調査結果

  • Orientation で持ち方を指定できる。
    • 現在(2018/1 0.12.0p3)の実装での選択肢は以下。
      • Gun (拳銃のような持ち方を想定?)
      • Grip (バイクのハンドルのような持ち方を想定?)
      • Any (その他何でも、という感じか)
    • 持った時に、手とオブジェクトの角度が異なるといった違いがある。以下の図を参照。(デスクトップモードでの表示)
      • TODO VRモードでは感覚的にまた違う位置のように感じる。要検証
    • (前提)実験に使ったオブジェクト
      • f:id:naqtn:20180104172111p:plain
      • 灰色のキューブに VRC_Pickup が付加してある。
      • 向きが分かるように x,y,z 各軸のプラスの方向に色を付けたキューブを接続してある
    • Gun の場合
      • f:id:naqtn:20180104172133p:plain:w300
      • -x 方向から +z を上にして掴む (Tポーズの右手で掴むイメージ?)
    • Grip の場合
      • f:id:naqtn:20180104172106p:plain:w300
      • -z 方向から -x を上にして掴む (x軸の棒を手を前に差し出して掴むイメージ?)
    • Any の場合
      • f:id:naqtn:20180104172123p:plain:w300
      • pickup 操作直前の、手を差し伸べた時のオブジェクトと手の角度の関係をそのまま保つ、となっている模様。
    • 以上の図は右手で pickup しているが、左手で pickup しても同じ向きになる。
    • GunGrip の二種類の違いの意図が分からない。手の形状(アニメーション)にも違いが無いようだ。)
  • Exact GunExact Grip はオブジェクトから見て hold 中に手の置かれる位置。省略した場合はそのオブジェクト自身。
    • こんな感じ:
    • Exact を図の位置に置くと: f:id:naqtn:20180104172116p:plain
    • Gun の場合にはこうなる: f:id:naqtn:20180104172127p:plain
    • Grip の場合にはこうなる: f:id:naqtn:20180104172059p:plain
  • Auto Hold は、取り上げ操作をやめた後もオブジェクトを保持し続けるかを指定する。有効な場合その取り上げ操作は「装備する(equip)」とも表現される。
    • Auto Detect にしておくと、Orientation に依存して Gun or Grip の場合に Auto Hold が有効になる模様。
    • なお、これを有効にすると指のアニメーションは握り状態から解放され、通常の指の動きが可能になる。
  • Use Text は、Auto Hold が有効である時に装備した状態での「使う」操作の案内文字列
  • Throw Velocity Boost Min Speed, Throw Velocity Boost Scale は投げる動作の速度に関係している。
    • 両方を 0 にすると投げられなくなる。(移動中に離しても初速が付かなくなる。回転は付く)
    • VR モードではオブジェクトを取り上げた(pickup)後に、オブジェクトを動かしている時に離す(drop)と投げ(throw)になる
      • (TODO Throw Velocity Boost Scale は影響がある。速度にこの数値がかけられるように見える。Min は意味があるのかないのか。 詳細要調査。)
    • デスクトップ(non VR)モードでは右クリックの長押し時間によって速度が変わる模様。
      • (TODO 名前からすると Min がすぐに押し込み解除した時の速度 Scale が時間に対してかかる係数のように見えるが、要調査)
  • Pickupable を無効にすると hover も表示されなくなる。
    • VRC_Pickup が存在していないと同じになるので役割不明。将来スクリプトで活用する布石か?
    • これと関係があるのか、VRC_Pickup はコンポーネントの active/deactive ができない
  • VRC_Pickup を追加すると LayerPickup になる。

未解明、不具合?

  • Physical Root はこの pickup によって制御される Rigidbody を指定するように見えるが、機能していないようだ

    • このため(?)複数のオブジェクトから構成されるオブジェクトを pickup 操作したい場合は、そのオブジェクト群の親子関係の最も親に VRC_Pickup を付加する必要があるようだ。応用例:移動可能な椅子の作り方
  • VRC_Pickup を付けたオブジェクトの子にさらに VRC_Pickup を付けた場合、マルチユーザー環境下で、 親オブジェクトを最後に取り上げたプレイヤーのみが子オブジェクトを取り上げられる、という現象が観察されている。

    • これは次のオブジェクトの ownership と関連しているように見える。
    • オブジェクトの owner については明確なドキュメントが無いが、VRC_ObjectSync の TakeOwnership と broadcast types に表れている。
    • オブジェクトをその時点で操作できるプレイヤーを意味しているようだ。
    • しかし VRC_ObjectSync の TakeOwnership が期待するように動作しないので詳細不明である。
    • 取り上げ動作はオブジェクトの owner を変化させるようだ。

Tips

  • Pickup しようとするオブジェクトを 静的オブジェクトにしてはならない。(インスペクタで Static のチェックを付けてはいけない)
    • (Pickup 出来るのならば動かせるわけで、意味的に当然ではあるが)
    • 指定した場合、(Rendererによる物体の)表示位置と VRChat が認識する位置がずれることがある。(この画像の例の場合 Rigidbody が use gravity, Is Kinematic 無効なので床に落下しつつ、表示は最適化によって場所を変えていないと思われる)

f:id:naqtn:20180406063103p:plain:w300

参考:Rigidbody の設定

  • (VRChat は関係なく Unity の物理演算の話題範囲だが有用と思うのでメモ)
  • VRC_Pickup をゲームオブジェクトに追加すると Rigidbody (日本語:剛体) も追加される
  • Is Kinematic のチェックを付けると手放した場所にそのまま留まるようになる
    • (VRC_Pickup の Throw の影響も受けなくなる)
  • Use Gravity のチェックを外すと重力の影響を受けず浮遊するようになる
    • Is Kinematic とは違い、手放した時の速度は残る
    • 重力の設定は Edit > Project Settings > Physics の Gravity
    • Use GravityIs Kinematic の両方をチェックすると Is Kinematic の方の振る舞いになる)

おまけ

  • アバターの頭と胴体にはデフォルトで Collider が仕込まれている模様。
    • 複数の Rigidbody を Joint で結合したものに VRC_Pickup を付加して、pickup した状態で自分自身を殴ると自分が吹っ飛んで行ったりする。
    • 手は反応しないので Collider設定が無いようだ。(操作性悪くなるからだろうか?)