본문 바로가기
Project

[유니티/MR] MR 손 오브젝트 부착하기

by 배애앰이 좋아 2024. 2. 22.
반응형

 

https://github.com/oculus-samples/Unity-TheWorldBeyond

유니티에서 공식적으로 제공해주는 프로젝트 기반으로 작성된 글입니다.

사용한 유니티 버전 : 2020.3.18f
사용한 VR 기기 : meta quest 3

 

먼저 위에서 제공되는 링크에서 Unity-TheWorldBeyond 프로젝트를 받아줍니다. oculus 및 유니티 버전 별 제공하는 패키지가 다를 수 있기 때문에 사용한 유니티 버전 및 해당 프로젝트를 받아서 수정하는 식으로 진행하는 것을 추천 드립니다. 추가적으로 기존 “현실 벽 파괴하고 3D 공간 등장 시키기” 프로젝트에 이어서 제작하는 프로젝트입니다.

 

hands.unitypackage
0.42MB

 

먼저 해당 프로젝트 손 오브젝트가 제공되지 않기 때문에 다른 곳에서 얻은 손 오브젝트를 import 해줍니다. 이때 스크립트는 빼고 import 해줍니다. 안 그러면 오류가 납니다.

 

 

참고로 improt 후 shader 가 깨져 있다면 위에 처럼 standard 로 바꿔줍니다.

 

아래 손 prefab을 각 손 위치에 배치 시켜줍니다.

 

animator에 들어 가보면 아래처럼 뜨고 이 중에서 grip 과 trigger 값을 조정해보면 손 모양이 어떻게 변하는지 확인할 수 있습니다.

 

 

기본 제공하는 스크립트는 아래와 같습니다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;


public class AnimateHandOnInput : MonoBehaviour
{
    public InputActionProperty pinchAnimationAction;
    public InputActionProperty gripAnimationAction;
    public Animator handAnimator;

    // Update is called once per frame
    void Update()
    {
        float triggerValue = pinchAnimationAction.action.ReadValue<float>();
        handAnimator.SetFloat("Trigger", triggerValue);

        float gripValue = gripAnimationAction.action.ReadValue<float>();
        handAnimator.SetFloat("Grip", gripValue);
    }
}

 

저 같은 경우는 참고만 하고 아래와 같이 스크립트를 만들어줬습니다.

각 현재 손 상태에 따라 애니메이션이 변할 수 있도록 해주었습니다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SettingHandAnimation : MonoBehaviour
{
    public Animator handAnimator;
    public bool isGrap = false;
    public bool isTrigger = false;
    public bool isNot = false;

    // Update is called once per frame
    void Update()
    {
        if(isGrap){
            handAnimator.SetFloat("Trigger", 1);
            isGrap = false;
        }

        if(isTrigger){
            handAnimator.SetFloat("Grip", 1);
            isTrigger = false;
        }

        if(isNot){
            handAnimator.SetFloat("Trigger", 0);
            handAnimator.SetFloat("Grip", 0);
            isNot = false;
        }
    }
}

 

설정은 다음과 같이 각 손 위치에 맞는 animator를 넣어주었습니다.

 

 

 

그 다음으로는 애니메이션 변화 상태를 넘겨주기 위한 스크립트 만들어주었습니다.

기존 프로젝트에서 썼던 SampleShooter를 변형했습니다.

참고로 grab 이라는 동작을 감지하기 위해, 여러 테스트를 위해 왼손 오른쪽 다른 방식으로 적용시켜보았습니다.

 

using UnityEngine;

public class SampleShooter : MonoBehaviour
{
    public GameObject _gunPrefab;
    public GameObject _bulletPrefab;
    public Transform _leftHandAnchor;
    public Transform _rightHandAnchor;
    public SettingHandAnimation settingHandAnimation_L;
    public SettingHandAnimation settingHandAnimation_R;
    public CanvasController canvasController;
    public OVRGrabber grabberL;

    GameObject _leftGun;
    GameObject _rightGun;

    void Start()
    {
        _leftGun = Instantiate(_gunPrefab);
        _leftGun.transform.SetParent(_leftHandAnchor, false);
        _rightGun = Instantiate(_gunPrefab);
        _rightGun.transform.SetParent(_rightHandAnchor, false);
    }

    // Update is called once per frame
    void Update()
    {
        // 왼손
        if (OVRInput.GetDown(OVRInput.RawButton.LIndexTrigger))
        {
            Vector3 ballPos = _leftGun.transform.position + _leftGun.transform.forward * 0.1f;
            Instantiate(_bulletPrefab, ballPos, Quaternion.identity);
            //settingHandAnimation_R.isTrigger = true;
            canvasController.ChangeText1("L Trigger");
        }
        // 오른손
        if (OVRInput.GetDown(OVRInput.RawButton.RIndexTrigger))
        {
            Vector3 ballPos = _rightGun.transform.position + _rightGun.transform.forward * 0.1f;
            Instantiate(_bulletPrefab, ballPos, Quaternion.identity);
            //settingHandAnimation_L.isTrigger = true;
            canvasController.ChangeText2("R Trigger");
        }
        // 오른손
        if (OVRInput.GetDown(OVRInput.Button.SecondaryHandTrigger))
        {
            settingHandAnimation_R.isTrigger = true;
            canvasController.ChangeText2("R Grap");
        }
        // 왼손
        // OVRInput.GetDown(OVRInput.Button.PrimaryHandTrigger) 원래는 이 코드인데 안 먹음
        // if(grabberL.grabbedObject.gameObject != null) grab 은 인식하나 그 뒤 공을 놓았을 때 grabberL.grabbedObject.gameObject== null 인식 안됨
        if (grabberL.grabbedObject != null) 
        {
            settingHandAnimation_L.isTrigger = true;
            canvasController.ChangeText1("L Grap");
        }
        // 오른쪽
        if(OVRInput.GetUp(OVRInput.Button.SecondaryHandTrigger) || OVRInput.GetUp(OVRInput.RawButton.RIndexTrigger)){
            settingHandAnimation_R.isNot = true;
            canvasController.ChangeText2("R Not");
        }
        // 왼손
        if(grabberL.grabbedObject == null){
            settingHandAnimation_L.isNot = true;
            canvasController.ChangeText1("L Not");
        }
    }
}

 

다음과 스크립트가 부착된 오브젝트 설정입니다.

 

여기까지 하면 끝납니다 다만 더 직관적인 확인을 위해서는 다음과 같이 canvas 를 손 옆에 부착해서 현재 동작을 표시해주는 텍스트를 띄워주면 좋습니다.

 

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class CanvasController : MonoBehaviour
{
    public GameObject spherePrefab;
    public Transform pose;
    static public CanvasController Instance = null;
    public Text text1;
    public Text text2;

    private void Awake()
    {
        if (!Instance)
        {
            Instance = this;
        }
    }

    public void ChangeText1(string text){
        text1.text = text;
    }

    public void ChangeText2(string text){
        text2.text = text;
    }

    public void ClickButton(){
        Instantiate(spherePrefab, pose);
    }
}

 

 

결과 영상 : 

 

 

읽어주셔서 감사합니다.

반응형

댓글