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
  • DistancePullGrabスクリプトを作成する(参考サイトから拝借して修正)

public class DistancePullGrab : MonoBehaviour
{
    public Material defaultMaterial;
    public Material highlight;
    public Transform pointer;//the transform the laser starts at
    public LayerMask thingsWeCanGrab;//things we can grab

    Hand hand;//our hand
    bool isAttached = false;//do we have something in our hand?
    GameObject attachedObject = null;//what do we have in our hand
    GameObject hitObject;

    void Start()
    {
        hand = GetComponent<Hand>();//get our hand
    }

    void Update()
    {
        if (hitObject != null)
            hitObject.GetComponent<MeshRenderer>().material = defaultMaterial;

        //raycast and check if our hand is empty
        RaycastHit hit;
        if (Physics.Raycast(pointer.position, pointer.forward, out hit, 10f, thingsWeCanGrab) && hand.currentAttachedObject == null)
        {
            hitObject = hit.collider.gameObject;
            Interactable interactable = hit.collider.gameObject.GetComponent<Interactable>();
            SteamVR_Input_Sources source = hand.handType;
            //are we pressing grip and trigger?
            if (hand.grabGripAction[source].state == true && hand.grabPinchAction[source].state == true)
            {
                //does the interactable component exist?
                if (interactable != null)
                {
                    //move the object to your hand
                    interactable.transform.LookAt(transform);
                    interactable.gameObject.GetComponent<Rigidbody>().AddRelativeForce(Vector3.forward * 500, ForceMode.Force);
                    attachedObject = interactable.gameObject;
                    isAttached = true;
                    //attaching to hand is in the late update function
                }
            }

            hitObject.GetComponent<MeshRenderer>().material = highlight;
        }

        if (SteamVR_Actions.default_InteractUI.GetStateUp(SteamVR_Input_Sources.Any) && hand.currentAttachedObject == attachedObject)
        {
            hand.DetachObject(attachedObject);
        }
    }
    private void LateUpdate()
    {
        //did we get an object to our hand during this update?
        if (isAttached)
        {
            //attach the object
            hand.AttachObject(attachedObject, GrabTypes.Grip);
            //attachedObject = null;
            isAttached = false;
        }
    }
}

f:id:yotiky:20211021224355g:plain ポインターが当たるとハイライト表示される。 グリップとトリガーを同時に押すことで掴むことができる。

参考