티스토리 뷰

반응형

안녕하세요. Base Of Coding입니다.

AR을 벗어나.. 이직을 해서 현재 VR을 처음 손을 대면서 공부를 하고 있습니다.

그래서, Steam VR Sample에 나와있는 부분들을 코드 분석하고 있는데.. 역시 낯설어서 그런 지 많이 어려워보이네요ㅠ

 

일단 LaserPointer를 코드 분석을 해봤는데, 만약 보시다가 틀린 부분이 있거나 수정 할 부분이 있거나 가르쳐주실 내용이 있으시다면, 댓글로 많은 글 부탁드립니다!

 

 

//======= Copyright (c) Valve Corporation, All rights reserved. ===============

using UnityEngine;

using System.Collections;

 

 

// 짐작으로 작성하고 있는 코드 분석

namespace Valve.VR.Extras

{

    public class SteamVR_LaserPointer : MonoBehaviour

    {

        public SteamVR_Behaviour_Pose pose;             // 사용자의 포즈 관련 스크립트

 

        //public SteamVR_Action_Boolean interactWithUI = SteamVR_Input.__actions_default_in_InteractUI;

        public SteamVR_Action_Boolean interactWithUI = SteamVR_Input.GetBooleanAction("InteractUI");        // InteractUI란 액션, 즉 Delegate의 함수 이름을 대입?

 

        public bool active = true;              // active라는 bool값의 변수인데, 쓰이지 않는 듯 함.

        public Color color;                     // 기본 Pointer Color값

        public float thickness = 0.002f;        // Pointer의 두께

        public Color clickColor = Color.green;  // 클릭했을 때(Trigger)의 Color값

        public GameObject holder;               // Pointer Cube를 가지고 있는 부모 게임 오브젝트

        public GameObject pointer;              // 포인터 Cube

        bool isActive = false;                  // isActive, 그냥 false

        public bool addRigidBody = false;       // 포인터에 리지드바디를 붙이느냐 안 붙이느냐에 관련 된 bool값

        public Transform reference;             // reference, 참조라는 거 같은데 뭘 참조하는 지.. 참조할 수 있는 값도 없음. 필요없어 보이는 듯함.

        public event PointerEventHandler PointerIn;     // 포인터가 안에 들어왔을 경우 이벤트

        public event PointerEventHandler PointerOut;    // 포인터가 밖으로 빠져나갔을 경우의 이벤트

        public event PointerEventHandler PointerClick;  // 포인터로 클릭했을 때의 이벤트

 

        Transform previousContact = null;               // 이전의 충돌 된 오브젝트 변수

 

 

        private void Start()

        {

            if (pose == null)                   // Pose가 null값이면, 해당 스크립트를 가지고 있는 게임오브젝트에, SteamVR_Behaviour_Pose 컴포넌트를 부착

                pose = this.GetComponent<SteamVR_Behaviour_Pose>();

            if (pose == null)                   // 그래도 null값이라면, LogError 출력

                Debug.LogError("No SteamVR_Behaviour_Pose component found on this object");

 

            if (interactWithUI == null)         // interactWithUI가 null값이라면, LogError 출력

                Debug.LogError("No ui interaction action has been set on this component.");        

 

 

            holder = new GameObject();                      // holder, 빈 게임오브젝트로 생성한다. Pointer의 부모 오브젝트이다.

            holder.transform.parent = this.transform;       // 그리고 해당 holder의 부모는, 컨트롤러 최상위 부모 오브젝트이다.

            holder.transform.localPosition = Vector3.zero;  

            holder.transform.localRotation = Quaternion.identity;       // 포지션값과 회전값을 0,0,0으로 초기화

 

            pointer = GameObject.CreatePrimitive(PrimitiveType.Cube);   // MeshRenderer 및 해당 모형에 알맞는 Collider를 부착한 게임오브젝트를 만든다.

            pointer.transform.parent = holder.transform;                // 이 포인터의 부모는 holder이며

            pointer.transform.localScale = new Vector3(thickness, thickness, 100f);     // 앞으로 쭉 나와있는 얇은 두께를 가진 포인터로 크기를 만들어주고

            pointer.transform.localPosition = new Vector3(0f, 0f, 50f);                 // x,y,z 기준으로, z값을 50으로 한다.

            pointer.transform.localRotation = Quaternion.identity;                      // 회전값은 기본값인 0,0,0이다.

            BoxCollider collider = pointer.GetComponent<BoxCollider>();                 // 포인터에 BoxCollider 컴포넌트를 collider로 사용한다.

            if (addRigidBody)                                                           // 리지드 바디를 추가해야 된다면

            {

                if (collider)                                                            // 콜라이더가 있다면, 콜라이더의 isTrigger를 켜준다.

                {

                    collider.isTrigger = true;

                }

                Rigidbody rigidBody = pointer.AddComponent<Rigidbody>();                // 포인터에, 리지드바디 컴포넌트를 추가하고

                rigidBody.isKinematic = true;                                           // isKinematic을 켜준다.

            }

            else

            {

                if (collider)                                                   // collider가 있다면, collider 컴포넌트를 없앤다.

                {

                    Object.Destroy(collider);

                }

            }

            Material newMaterial = new Material(Shader.Find("Unlit/Color"));            // 새로운 메터리얼을 만들고, 해당 메터리얼은, Unlit/Color라는 쉐이더 종류로 만든다.

            newMaterial.SetColor("_Color", color);                                      // 컬러값, 즉 검은색을 메터리얼의 컬러값으로 만든다.

            pointer.GetComponent<MeshRenderer>().material = newMaterial;                // 그리고, Pointer의 MeshRenderer의, 메터리얼 쪽에 넣어준다.

        }

 

        public virtual void OnPointerIn(PointerEventArgs e)         // 포인터가 안에 들어오면

        {

            if (PointerIn != null)

                PointerIn(this, e);                                 // 해당 클래스와, 매개변수 e값을 넣는다? 아직 파악이 안됨.

        }

 

        public virtual void OnPointerClick(PointerEventArgs e)      // 포인터 클릭 시 이벤트

        {

            if (PointerClick != null)

                PointerClick(this, e);                              // 해당 클래스와, 매개변수 e값을 넣는다? 아직 파악이 안됨.

        }

 

        public virtual void OnPointerOut(PointerEventArgs e)        // 포인터가 밖으로 빠져나갔을 경우?

        {

            if (PointerOut != null)

                PointerOut(this, e);                                // 해당 클래스와, 매개변수 e값을 넣는다? 이것 또한 아직 파악이 안됨.

        }

 

 

        private void Update()

        {

            if (!isActive)              // isActive가 false일 경우

            {

                isActive = true;        // isActive는, true로 만들고,

                this.transform.GetChild(0).gameObject.SetActive(true);      // 해당 스크립트가 있는 오브젝트에서, 첫 번째 자식의 오브젝트를 켜준다.

            }

 

            float dist = 100f;      // 거리

 

            Ray raycast = new Ray(transform.position, transform.forward);       // RayCast 생성, 정면으로

            RaycastHit hit;             // RaycastHit형 hit 변수 선언

            bool bHit = Physics.Raycast(raycast, out hit);      // Raycast를 만들어서, 정면으로 쏘고 hit가 되었는 지 안 되었는 지 판단하여, hit면, true, nonHit면, false

 

            if (previousContact && previousContact != hit.transform)            // 전에 충돌한 물체가 있고, 이전에 충돌한 물체와 충돌된 물체가 다르다면, 포인터가 밖으로 빠져나간 것

            {

                PointerEventArgs args = new PointerEventArgs();         // 구조체 동적할당

                args.fromInputSource = pose.inputSource;                // pose.inputSource를 fromInputSource에 대입

                args.distance = 0f;                                     // 거리는 0으로 초기화

                args.flags = 0;                                         // flag는 0, 이건 모든 이벤트 동일한 듯.

                args.target = previousContact;                          // target은, 이전에 충돌한 물체를 대입한다.

                OnPointerOut(args);                                     // OnPointerOut 함수 실행

                previousContact = null;                                 // 이전에 충돌한 물체는, 없으니 null

            }

            if (bHit && previousContact != hit.transform)               // hit가 되었고, 이전에 충돌한 물체가 충돌한 물체와 다르다면, 예 ) null != Sphere, 어떠한 물체와 부딪혔다는 뜻.

            {

                PointerEventArgs argsIn = new PointerEventArgs();       // 구조체 동적할당

                argsIn.fromInputSource = pose.inputSource;              // pose.inputSource를 fromInputSource에 대입

                argsIn.distance = hit.distance;                         // 거리는 충돌 된 거리로 변경

                argsIn.flags = 0;                                       // flag는 0, 이건 모든 이벤트 동일

                argsIn.target = hit.transform;                          // target은, 현재 충돌한 물체를 대입

                OnPointerIn(argsIn);                                    // OnPointerIn 함수 실행

                previousContact = hit.transform;                        // 이전에 충돌한 물체는 현재 충돌한 물체로 대입

            }

            if (!bHit)                  // hit가 되지 않았다면

            {

                previousContact = null;     // 이전에 충돌한 물체는 null값.

            }

            if (bHit && hit.distance < 100f)    // hit가 되었고, hit가 된 거리가, 100f보다 작다면

            {

                dist = hit.distance;            // 거리값은, hit가 된 거리로 변경

            }

 

            if (bHit && interactWithUI.GetStateUp(pose.inputSource))        // hit가 되었고, 트리거 클릭하고 뗄 경우, ( 누르고 있을 때 X )

            {

                PointerEventArgs argsClick = new PointerEventArgs();       // 구조체 동적할당

                argsClick.fromInputSource = pose.inputSource;              // pose.inputSource를 fromInputSource에 대입 

                argsClick.distance = hit.distance;                         // 거리는 충돌 된 거리로 변경 

                argsClick.flags = 0;                                       // flag는 0, 이건 모든 이벤트 동일

                argsClick.target = hit.transform;                          // target은, 현재 충돌한 물체를 대입

                OnPointerClick(argsClick);                                 // OnPointerClick 함수 실행

                previousContact = hit.transform;

            }

 

            if (interactWithUI != null && interactWithUI.GetState(pose.inputSource))        // 상호작용, 즉 트리거를 눌렀다 뗐을 때, Sphere와 충돌이 되면

            {

                pointer.transform.localScale = new Vector3(thickness * 5f, thickness * 5f, dist);       // 두께는, 기본 두께보다 x5배만큼 늘려준다. dist는, 충돌되었을 때의 거리로 변경이 된다.

                pointer.GetComponent<MeshRenderer>().material.color = clickColor;                       // 메터리얼의 Color값은, 클릭했을 때의 Color값으로 변경

            }

            else            // 상호작용이 안되었다면, 아무것도 충돌이 되지 않는다면

            {

                pointer.transform.localScale = new Vector3(thickness, thickness, dist);         // 기본 두께와 기본 거리만큼의 포인터로 변경이 되고

                pointer.GetComponent<MeshRenderer>().material.color = color;                    // 포인터의 Color값도 Black으로 변경한다.

            }

            pointer.transform.localPosition = new Vector3(0f, 0f, dist / 2f);                   // pointer의 지역 위치는, 0,0,거리/2로 만들어준다.

        }

    }

 

    public struct PointerEventArgs

    {

        public SteamVR_Input_Sources fromInputSource;

        public uint flags;

        public float distance;

        public Transform target;

    }

 

    public delegate void PointerEventHandler(object sender, PointerEventArgs e);

}

 

 

글에 도움이 되셨거나, 고쳐야 될 부분이 있다면, 댓글로 글 남겨주세요! 감사합니다.

지금까지 Base Of Coding이였습니다.

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/05   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함