yotiky Tech Blog

とあるエンジニアの備忘録

Unity (Oculus Quest) - SteamVR Plugin でレーザーポインターで物を掴む

目次

開発環境

  • Quest1
  • Oculus Link + SteamVR
  • Unity 2021.2.0b16.3733
  • Unity 2020.3.17f1
  • SteamVR Plugin 2.7.3

前提

Playerプレハブを使うので前回の記事で準備ができていること。

yotiky.hatenablog.com

実装

  • Playerプレハブを使用する
  • 床やCubeなどを適当に配置する
  • CubeにInteractableとRigidBodyを追加する

    • f:id:yotiky:20211021220526p:plain
  • LeftHandにLineRendererを追加する

    • f:id:yotiky:20211021220543p:plain
    • Positionsの1のZを10にする、Widthを0.01にする、Use World Spaceのチェックを外す
    • f:id:yotiky:20211021220557p:plain
    • Widthはヘッダ部分を横にスライドすると調整できる
    • f:id:yotiky:20211021220607g:plain
  • DistanceStayGrabスクリプトを作成する

[RequireComponent(typeof(FixedJoint))]
public class DistanceStayGrab : MonoBehaviour
{
    private FixedJoint joint;
    private GameObject targetObject;

    void Start()
    {
        joint = GetComponent<FixedJoint>();
    }
    void Update()
    {
        if (targetObject == null && Physics.Raycast(transform.position, transform.forward, out var hit, 10))
        {
            var interactable = hit.transform.gameObject.GetComponent<Interactable>();
            if (interactable != null)
            {
                targetObject = hit.transform.gameObject;
            }
        }

        if(targetObject != null)
        {
            if (SteamVR_Actions.default_GrabPinch.GetStateDown(SteamVR_Input_Sources.LeftHand))
            {
                joint.connectedBody = targetObject.GetComponent<Rigidbody>();
            }
            else if (SteamVR_Actions.default_GrabPinch.GetState(SteamVR_Input_Sources.LeftHand))
            {
                // 掴み中
            }
            else
            {
                joint.connectedBody = null;
                targetObject = null;
            }
        }
    }
}
  • DistanceStayGrabスクリプトをLeftHandに追加する
    • 一緒に追加されたRigidBodyのUseGravityのチェックを外し、IsKenematicのチェックを入れる
    • f:id:yotiky:20211021220644p:plain

f:id:yotiky:20211021220653g:plain

備考

  • SteamVR/ExtrasにSteamVR_LaserPointerが同梱されている
    • イベントに処理を紐付けて利用する
    • サンプルシーンでは処理が設定されてないのでポインターを表示してクリックすると色が変わるだけ
    • f:id:yotiky:20211021221756g:plain
  • 掴む処理に使うにはイベントが別れていて煩雑になりそう
  • UIをクリックするのには使えそう
  • 使い方はLeftHandなどにSteamVR_LaserPointerを追加して、他のスクリプトからイベントハンドラを登録する
  • イベントハンドラのサンプルコード
private SteamVR_LaserPointer laserPointer;

void Start()
{
    laserPointer = GetComponent<SteamVR_LaserPointer>();
    laserPointer.PointerClick += LaserPointer_PointerClick;
    laserPointer.PointerIn += LaserPointer_PointerIn;
    laserPointer.PointerOut += LaserPointer_PointerOut;
}

private void LaserPointer_PointerIn(object sender, PointerEventArgs e)
{
    // PointerのRaycastがHitした時に呼ばれる
    Debug.Log("In");
    targetObject = e.target.gameObject;
}

private void LaserPointer_PointerOut(object sender, PointerEventArgs e)
{
    // 直前にHitしていたオブジェクトがRaycastがHitしなくなった時に呼ばれる
    Debug.Log("Out");
    if (targetObject == e.target.gameObject)
    {
        targetObject = null;
    }
}

private void LaserPointer_PointerClick(object sender, PointerEventArgs e)
{
    // PointerのRaycastがHitしてる場合、ボタンを押して離した時に呼ばれる
    Debug.Log("Click");
    targetObject = e.target.gameObject;
}

参考