VR - Steam VR LaserPointer 스크립트 주석 달아보기
안녕하세요. 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이였습니다.