본문 바로가기
etc./🕹️unity

VR 실습

by yewoneeee 2022. 6. 11.

실습에 오큘러스 퀘스트 2 기기를 사용했음

대여받은 상태로 진행했던 실습이라 따로 영상을 촬영해두지 않아 실습 영상은 없음,,

 

유니티에 오큘러스 라이브러리를 추가하면 기본으로 주어지는 scene과 코드를 사용해서

간단한 컨트롤러 동작등을 수행할 수 있음

# ControllerMove.cs

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

public class ControllerMove : MonoBehaviour
{
    void Start()
    {
        
    }

    void Update()
    {
        float x = ARAVRInput.GetAxis("Horizontal", ARAVRInput.Controller.LTouch);
        float z = ARAVRInput.GetAxis("Vertical", ARAVRInput.Controller.LTouch);
        transform.Translate(new Vector3(x, 0, z) * 5 * Time.deltaTime);
        float ry = ARAVRInput.GetAxis("Horizontal", ARAVRInput.Controller.RTouch);
        transform.Rotate(new Vector3(0, ry, 0) * 45 * Time.deltaTime);
        
        float v=OVRInput.Get(OVRInput.Axis1D.PrimaryIndexTrigger);
        Debug.Log($"Trigger: {v:f4}");

        if (ARAVRInput.GetDown(ARAVRInput.Button.IndexTrigger, ARAVRInput.Controller.LTouch))
        {
            Ray ray = new Ray(ARAVRInput.LHandPosition, ARAVRInput.LHandDirection);
            RaycastHit hitinfo;
            if (Physics.Raycast(ray, out hitinfo)==true)
            {
                GameObject obj = GameObject.CreatePrimitive(PrimitiveType.Sphere); // sphere의 기본 오브젝트로 만들어줘라 (오브젝트 생성)
                obj.transform.position = hitinfo.point; //ray가 닿은 위치에 오브젝트 위치
            }
        }
    }
}

 

# CustomGrap.cs

컨트롤러의 트리거를 사용해서 오브젝트를 그랩

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

public class CustomGrap : OVRGrabber
{
    [SerializeField]
    int m_grabObjectsInLayer = 0;
    [SerializeField]
    float m_maxGrabDistance;
    [SerializeField]
    float m_noSnapThreshhold = 0.05f;


    protected override void GrabBegin()
    {
        DistanceGrabbable closestGrabbable = null;
        Collider closestGrabbableCollider = null;

        Ray ray = new Ray(m_gripTransform.position, m_gripTransform.forward);
        RaycastHit hitInfo;
        int layer = (m_grabObjectsInLayer == -1) ? ~0 : 1 << m_grabObjectsInLayer;
        if (Physics.Raycast(ray, out hitInfo, m_maxGrabDistance, layer))
        {
            if (hitInfo.collider != null)
            {
                closestGrabbable = hitInfo.collider.gameObject.GetComponentInParent<DistanceGrabbable>();
                closestGrabbableCollider = closestGrabbable == null ? null : hitInfo.collider;
                if (closestGrabbable != null && closestGrabbable != m_grabbedObj)
                {
                    closestGrabbable.Targeted = true;
                }
            }
        }

        GrabVolumeEnable(false);

        if (closestGrabbable != null)
        {
            if (closestGrabbable.isGrabbed)
            {
                ((CustomGrap)closestGrabbable.grabbedBy).OffhandGrabbed(closestGrabbable);
            }

            m_grabbedObj = closestGrabbable;
            m_grabbedObj.GrabBegin(this, closestGrabbableCollider);

            m_lastPos = transform.position;
            m_lastRot = transform.rotation;

            Vector3 relPos = m_grabbedObj.transform.position - transform.position;
            relPos = Quaternion.Inverse(transform.rotation) * relPos;
            m_grabbedObjectPosOff = relPos;
            Quaternion relOri = Quaternion.Inverse(transform.rotation) * m_grabbedObj.transform.rotation;
            m_grabbedObjectRotOff = relOri;

            SetPlayerIgnoreCollision(m_grabbedObj.gameObject, true);
        }
    }

    protected override void OffhandGrabbed(OVRGrabbable grabbable)
    {
        base.OffhandGrabbed(grabbable);
    }
}

 

# CustomLaser.cs

컨트롤러가 가리키는 방향으로 나오는 레이저 구현

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

public class CustomLaser : MonoBehaviour
{
    LineRenderer lineRenderer;
    public GameObject player;
    public OVRScreenFade fade;
    RaycastHit hitinfo;

    void Start()
    {
        lineRenderer = GetComponent<LineRenderer>();
    }
    void Update()
    {
        lineRenderer.SetPosition(0, ARAVRInput.RHandPosition); // 컨트롤러에서 나오는 레이저의 시작점 갱신
        Ray ray = new Ray(ARAVRInput.RHandPosition, ARAVRInput.RHandDirection);
        if (Physics.Raycast(ray, out hitinfo, 100, 1 << LayerMask.NameToLayer("Default")) == true) // << 숫자 1의 비트를 왼쪽으로 한칸만 이동
        {
            /*
            lineRenderer.enabled = true;
            lineRenderer.SetPosition(1, ARAVRInput.RHandPosition + ARAVRInput.RHandDirection * 100);
            // 컨트롤러가 시작하는 위치 + 컨트롤러가 향하는 방향 -> 컨트롤러 위치에서 컨트롤러가 향하는 방향으로 2미터
            lineRenderer.SetPosition(1, hitinfo.point); // 만약 큐브와 충돌시 마지막점을 충돌지점으로 두기 위해
            */
            lineRenderer.material.color = Color.green;
            if (ARAVRInput.GetDown(ARAVRInput.Button.IndexTrigger,ARAVRInput.Controller.RTouch)) // 충돌된 위치로 텔레포트
            {
                Vector3 pos = hitinfo.point; // hitinfo.transform.position 으로하면 그 영역의 중점으로 이동 -> 지정된 위치로만 이동이 가능
                // hitinfo.point하면 어느 위치든? 이동이 가능
                StartCoroutine(Teleport(pos));
            }
        } //어떤 물체에 부딪혔다면 부딪힌 곳까지만 ray
        else
        {
            //lineRenderer.enabled = false;
            lineRenderer.SetPosition(1, ARAVRInput.RHandPosition + ARAVRInput.RHandDirection * 10);
            lineRenderer.material.color = Color.red;
        } // 어떤 물체에 부딪히지 않았다면 컨트롤러가 향하는 방향으로 10미터
    }
    IEnumerator Teleport(Vector3 pos)
    {
        fade.FadeOut();
        yield return new WaitForSeconds(1.5f); // fadeOut하고 난 다음 위치이동
        player.transform.position = pos + new Vector3(0, 1, 0);
        fade.FadeIn();
    }
}

 

# CustomLaserPointer.cs

레이저와 충돌한 오브젝트의 테두리 변경 및 그랩 설정

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

[RequireComponent(typeof(LineRenderer))]
public class CustomLaserPointer : MonoBehaviour
{
    private LineRenderer lineRenderer; // 라인
    private RaycastHit Collided_object; // 충돌된 객체
    private GameObject currentObject; // 가장 최근에 충돌한 객체를 저장하기 위한 객체

    public OVRInput.Button clickKey = OVRInput.Button.Any;
    public Color normalColor = new Color(0, 195, 255, 0.5f);
    public Color selectColor = new Color(255, 255, 255, 0.5f);
    public float raycastDistance = 100f; // 레이저 포인터 감지 거리
    public LayerMask layerMask;

    void Start()
    {
        // 스크립트가 포함된 객체에 라인 렌더러라는 컴포넌트를 찾는다
        lineRenderer = gameObject.GetComponent<LineRenderer>();
        // 라인의 꼭지점은 2개가 필요
        lineRenderer.positionCount = 2;
        // 라인 그림자 표현끄기
        lineRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
        lineRenderer.receiveShadows = false;
        // 라인 굵기 표현
        lineRenderer.startWidth = 0.01f;
        lineRenderer.endWidth = 0.01f;

        // 라인이 가지게될 색상 표현
        Material material = new Material(Shader.Find("Standard"));
        material.color = normalColor;
        lineRenderer.material = material;
    }

    void Update()
    {
        // 라인 시작점
        lineRenderer.SetPosition(0, transform.position); // 첫번째 시작점 위치
        //Debug.DrawRay(transform.position, transform.forward * raycastDistance, Color.green, 0.5f);

        // 충돌 감지시
        if (Physics.Raycast(transform.position, transform.forward, out Collided_object, raycastDistance, layerMask))
        {
            // 라인 끝점
            lineRenderer.SetPosition(1, Collided_object.point);

            //// 충돌 객체의 태그가 Button인 경우
            //if (Collided_object.collider.gameObject.CompareTag("Button"))
            //{
            //    if (OVRInput.GetDown(OVRInput.Button.One))
            //    {
            //        // 버튼에 등록된 onClick 메소드를 실행한다.
            //        if (Collided_object.collider.gameObject.GetComponent<Button>())
            //            Collided_object.collider.gameObject.GetComponent<Button>().onClick.Invoke();
            //    }
            //    else
            //    {
            //        if (Collided_object.collider.gameObject.GetComponent<Button>())
            //            Collided_object.collider.gameObject.GetComponent<Button>().OnPointerEnter(null);
            //        currentObject = Collided_object.collider.gameObject;
            //    }
            //}
        }
        else
        {
            // 충돌이 감지되지 않으면 라인 초기 설정 길이만큼 길게 만든다
            lineRenderer.SetPosition(1, transform.position + (transform.forward * raycastDistance));

            //// 최근 감지된 오브젝트가 Button인 경우
            //// 버튼은 현재 눌려있는 상태이므로 이것을 풀어준다.
            //if (currentObject != null)
            //{
            //    if (currentObject.GetComponent<Button>())
            //        currentObject.GetComponent<Button>().OnPointerExit(null);
            //    currentObject = null;
            //}
        }
    }

    private void LateUpdate()
    {
        // 버튼을 누를 경우
        if (OVRInput.GetDown(clickKey))
        {
            lineRenderer.material.color = selectColor;
        }
        // 버튼을 뗄 경우
        else if (OVRInput.GetUp(clickKey))
        {
            lineRenderer.material.color = normalColor;
        }
    }
}

 

# PhysicsButton.cs

컨트롤러로 버튼을 눌렀을 때

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

public class PhysicsButton : MonoBehaviour
{
    public ConfigurableJoint join;
    public float beginClick = 0.5f;
    public float endClick = 0.3f;
    public UnityEvent onPressed;
    public UnityEvent onReleased;

    bool isPressed = false;
    Vector3 startPos;
    
    void Start()
    {
        startPos = join.transform.localPosition;
    }
    void Update()
    {
        float distance = Vector3.Distance(startPos, join.transform.localPosition) / join.linearLimit.limit;
        if (isPressed == false)
        {
            if (distance >= beginClick) // 처음 버튼이 눌리지 않은 상태에서 30퍼이상 눌렸을 때
            {
                isPressed = true;
                Debug.LogWarning("Pressed");
                onPressed.Invoke(); // onPressed안에 들어있는 이벤트 전체가 실행됨
            }
        }
        else
        {
            if (distance <= endClick)
            {
                isPressed = false;
                Debug.LogWarning("release");
                onReleased.Invoke(); // onReleased안에 들어있는 이벤트 전체가 실행됨
            }
        }
    }
}

ARAVRInput.cs
0.01MB

 

 

ARAVRInput은 기본적으로 제공해주는 코드에 추가적으로 작성한 코든데

전체 코드가 너무 길기도 하고 코드 분석 내용도 주석으로 적어놔서 일단 파일로 첨부함 

 

0727.txt
0.00MB

수업 내용 정리

'etc. > 🕹️unity' 카테고리의 다른 글

VR 개인 프로젝트  (0) 2022.06.11
VR UI 설정  (0) 2022.06.11
2D Shooting  (0) 2022.06.11
3D FPS  (0) 2022.06.11
unity shader, effect, light & 지형 만들기  (0) 2022.06.11

댓글