본문 바로가기
가상현실

[VR스쿨] VR 가상현실, 구글 카드보드의 마그네틱 스위치 인식과 오브젝트 선택 구현하기

by 세이박스 2016. 8. 29.
반응형

 

 

구글 카드보드의 마그네틱 스위치?

https://developers.google.com/cardboard/

 

마그네틱 스위치는 스마트폰의 자기력 센서의 변화를 측정해 입력하는 방식 입니다.
테스트 해보기 위해 구글플레이에서 "마그네틱 센스"로 검색후 앱을 다운로드

 

0f94f04c6dc53a08610b19af375f67a4_1456525
 

https://play.google.com/store/apps/details?id=imoblife.androidsensorbox

앱을 실행 후 자석을 스마트폰에 가까이 가져가면 자기장 수치가 변화는 것을 보실 수 있습니다.

 

즉, 자석을 이용해서 간단한 VR(Virtual Reality) 가상공간 속에서의 콘트롤러로 이용할 수 있습니다.

간단하게 메뉴를 클릭하거나 게임에서 무기를 발사하는 등의 기능으로 사용 가능 합니다.

 

스위치 인식하는 예제를 만들어 보겠습니다.

 

0f94f04c6dc53a08610b19af375f67a4_1456524 


CardboardMain오브젝트를 선택 하면 가장 오른쪽 Inspector창에 Cardboard 스크립트 컴포넌트가 추가되어 있는것을 알 수 있습니다.
마그네틱 스위치 입력은 Cardboard 스크립트에서 감지 하도록 되어 있습니다.

마그네틱 입력이 감지 되었는지 확인하기 위해 몇 번 입력이 감지되었는지 확인 할 텍스트를 배치 해 보겠습니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456526
 

 

하이어라키 창 빈 공간에 오른쪽 클릭을 해서 -> 3D Object -> 3D Text를 선택 해 주시고 Inspector창의 Text Mesh 컴포넌트의 변수들을 위 이미지와 같이 설정 해 주세요.
카메라가 텍스트를 볼 수 있는 위치에 배치 합니다.
다음은 트리거를 감지해서 카운트 값을 증가시키는 스크립트를 작성해 보겠습니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456526


우선 정리를 쉽게 하기 위해 Scripts 폴더를 만들어 주시고 Scripts 폴더 오른쪽 클릭 -> Create -> C# Script 를 선택 해 주세요.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456526 


스크립트 이름은 TriggerTextCtrl로 하겠습니다.
처음 스크립트를 생성 할 때 정해준 이름 대로 스크립트의 클래스 이름을 자동으로 생성 해 줍니다.
생성 후에 스크립트 이름을 변경 할 때엔 스크립트 안의 클래스 이름도 스크립트 이름으로 바꾸어 줘야 합니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456526 


위의 스크립트를 작성해 주세요
스크립트 해석하면 다음과 같습니다.

 

//MonoBehaviour 클래스를 상속 합니다. 유니티에서 오브젝트의 행동 양식을 결정하는 클래스 입니다.
public class TriggerTextCtrl : MonoBehaviour
{
    //결합할 텍스트 상수입니다.
    private const string TEXT = "TriggerCount : ";
    //접근 제어자를 public으로 하면 유니티 에디터에서 이 변수를 설정할 수 있습니다.
    public Cardboard cardBoard;
    //3DText의 글자는 TextMesh 컴포넌트에서 변경했기 때문에 TextMesh 컴포넌트를 가져와야 합니다.
    private TextMesh textMesh;
    //카운트 변수입니다.
    private int count = 0;
    //Update 메소드가 호출되기 전 단 한 번 호출 됩니다. 보통 변수들을 초기화 하는것을 여기에다 작성합니다.
   
    void Start()
    {
        //gameObject에는 본 컴포넌트가 추가된 게임 오브젝트가 들어가 있습니다. GetComponent<가져올 컴포넌트>(); 를 이용하면 컴포넌트를 가져올 수 있습니다.
        textMesh = gameObject.GetComponent<TextMesh>();
    }
   
    //매 프레임마다 호출되는 메소드 입니다. 여기서 게임 오브젝트의 변화를 설정합니다.
    void Update()
    {
        //카드보드에서 Triggered Getter는 트리거가 발생했는지 알 수 있습니다.
        if (cardBoard.Triggered)
        {
            //TextMesh 컴포넌트의 text를 변경합니다.

            count++;
            textMesh.text = TEXT + count.ToString();
        }
    }

 

 

0f94f04c6dc53a08610b19af375f67a4_1456527 


스크립트를 모두 작성 했으면 컴포넌트를 추가해야 합니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456527 


TriggerCount 오브젝트를 선택하여 Inspector 창의 아래에 Add Component로 Trigger Text Ctrl 스크립트를 추가해 줍니다.
Cardboard 스크립트 컴포넌트는 에디터에서 추가해 봅시다.
Trigger Text Ctrl 컴포넌트를 보면 에디터에서 설정 가능한 변수 목록이 보입니다.

하이어라키 창에서 Cardboard컴포넌트를 가지고 있는 CardboardMain을 마우스로 변수에 끌어다 놓으면
에디터에서 자동으로 CardboardMain이 가지고 있는 Cardboard 컴포넌트로 설정해 줍니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456527 

 

에디터에서 실행 한 후 터치를 해 보면 TriggerCount 값이 증가 하는 것을 볼 수 있습니다.
다음은 가운데 있는 오브젝트를 감지하는 기능을 추가 해 보겠습니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456539 

 

일단 하이어라키 창에서 3D Object -> Cube를 추가 해 보겠습니다.
그리고 저는 카메라 왼쪽에 큐브들을 배치 하였습니다.
큐브의 색깔을 바꾸는 스크립트를 작성해 보겠습니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456540 

 

Scripts 폴더 오른쪽 클릭 -> Create -> C# Script 를 선택 해 주세요.

스크립트 이름을 BoxCtrl 으로 만듭니다.


public class BoxCtrl : MonoBehaviour {

   private MeshRenderer meshRenderer;

 

    void Start () {

        //메쉬는 월드에 배치된 오브젝트의 모양입니다.
        meshRenderer = gameObject.GetComponent<MeshRenderer>();
    }

 

    void Update () {

    }

 

    public void Select()
    {

        //meshRenderer의 재질 (material)을 가져와 색깔을 파란색 (R = 0, G = 0 , B = 1)으로 변경합니다.
        meshRenderer.material.color = new Color(0, 0, 1f);
    }
}


 

 

0f94f04c6dc53a08610b19af375f67a4_1456540 

 

다음은 쉽게 색이 바뀌는 박스인지 확인할 수 있게 해당 오브젝트의 태그를 설정하겠습니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456540 

 

Inspector창의 Tag옆의 드롭다운 메뉴에서 Add Tag...를 선택합니다. 

 

0f94f04c6dc53a08610b19af375f67a4_1456541 

 

그럼 태그를 설정하는 창으로 바뀌는데 여기서 +버튼을 눌러 Box 태그를 추가합니다. 

 

0f94f04c6dc53a08610b19af375f67a4_1456541 

 

 

그리고 SelectBox의 태그를 Box로 설정합니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456541 

 


박스를 여러개 만드려고 하는데 하이어라키에서 복사 붙여넣기 하는 방법도 있지만 프리팹을 이용해 보도록 하겠습니다.
프리팹은 월드에 배치된 오브젝트를 그대로 파일로 만드는 것 입니다.
하이라키 창의 SelectBox를 Prefabs폴더를 만들어 거기에 끌어다 놓으면 쉽게 프리팹을 만들 수 있습니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456541
 

만든 프리팹으로 월드에 몇 개 배치해서 적당한 위치로 옮겨 주세요

 

 

0f94f04c6dc53a08610b19af375f67a4_1456541 

 

그다음엔 눈의 가운데를 표시할 크로스 헤어를 만들어 보겠습니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456541 


캔버스를 이용하여 만듭니다.
캔버스는 플로팅된 UI를 만들 때 사용합니다.
하이어라키 창에서 오른쪽 클릭하여 UI -> Canvas를 선택합니다.
다음 만들어진 캔버스 오른쪽 클릭하여 이미지를 추가합니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456541 


Inspector창에서 적당히 수정합니다.
기본 이미지를 이용하겠습니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456542

 


기본적으로 캔버스는 메인 카메라를 기준으로 Overlay되어 있습니다.
VR의 카메라는 두개 이므로 각각 카메라를 기준으로 떠 있도록 해야 합니다
Canvas를 선택하여 Canvas 컴포넌트의 Render Mode를 Screen Space - Camera로 바꾸어 줍니다.
그러면 아래 매개 변수들이 바뀌는데 RenderCamera를 CardboardMain->Head->MainCamera의 자식 Main Camera Left 를 끌어다 놓습니다.
그리고 하이어라키 창에서 Canvas를 선택하여 Ctrl + D를 누르면 Canvas가 복제 됩니다.
그럼 복제된 Canvas의 Canvas 컴포넌트 Render Camera에 Main Camera Right를 끌어다 놓습니다.

 

 

0f94f04c6dc53a08610b19af375f67a4_1456542 


이제 트리거가 발생 했을 때, 화면 가운데에 있는 오브젝트가 무엇인지 감지하여 그 오브젝트가 박스라면 색깔을 변경하도록 하겠습니다.
TriggerTextCtrl에서 코드를 추가하도록 하겠습니다.


화면 가운데에 있는 오브젝트가 무엇인지 감지 할 때엔 RayCast라는 것을 사용합니다.
간단하게 RayCast가 무엇인지 설명 하면 레이저를 쏴서 이 레이저에 맞는 오브젝트를 감지하는 것 입니다.
screenCenter = new Vector3(Camera.main.pixelWidth / 2, Camera.main.pixelHeight / 2);
Vector3는 3개의 float형 변수를 계산할 때 이용이 되며
화면의 픽셀 개수는 Camera.main.pixelWidth , Camera.main.pixelHeight 를 가져와 반으로 나누면 가운데 위치를 가져 올 수 있습니다.
Ray ray = Camera.main.ScreenPointToRay(screenCenter);
메인 카메라를 기준으로 screenCenter 위치에서 발사한 레이를 가져옵니다.
Physics.Raycast(ray, out hit, 500f)
ray에 맞은 500f 범위 안에 있는 적중 정보를 hit에 저장합니다.

맞은 오브젝트의 태그가 Box라면 맞은 오브젝트의 BoxCtrl 컴포넌트를 가져와 Select() 메소드를 호출합니다.

 

 

 

public class TriggerTextCtrl : MonoBehaviour
{
    private const string TEXT = "COUNT : ";
    public Cardboard cardBoard;
    private TextMesh textMesh;
    private int count = 0;
   private Vector3 screenCenter;

    void Start()
    {
        textMesh = gameObject.GetComponent<TextMesh>();
      screenCenter = new Vector3(Camera.main.pixelWidth / 2, Camera.main.pixelHeight / 2);
    }

    void Update()
    {
        if (cardBoard.Triggered)
        {
            ++count;
            textMesh.text = TEXT + count.ToString();           
          Ray ray = Camera.main.ScreenPointToRay(screenCenter);
          RaycastHit hit;
          if(Physics.Raycast(ray, out hit, 500f))
          {
              if (hit.collider.gameObject.tag == "Box")
              {
                  BoxCtrl boxCtrl = hit.collider.gameObject.GetComponent<BoxCtrl>();
                  boxCtrl.Select();                    
              }
          }

        }
    }
}

 



결과 화면입니다.

 

 

작성자 : 이경용

 

반응형