Unity로 AR 게임 만들기

jennjenny·2021년 5월 18일
8

EwhaCanvas

목록 보기
1/1
post-thumbnail
post-custom-banner

AR 이란?

Augmented Reality 의 약자로 실제로 존재하는 환경에 가상의 사물이나 정보를 합성하여 마치 원래의 환경에 존재하는 사물처럼 보이도록 하는 컴퓨터 그래픽 기법

모바일 디바이스와 유니티로 AR 서비스를 만들 수 있다.

Unity에서 사용할 수 있는 AR SDK

AR Foundation

AR Foundation 공식문서

  • Unity 내에서 자체적으로 제공하는 증강현실 제작 인터페이스
  • AR 기능 자체는 구현하지 않기 때문에 다음의 추가적인 패키지를 import 해주어야 한다.
    -Andorid 경우 ARCore XR 플러그인
    -iOS 경우 ARKit XR 플러그인

Google AR Core SDK

ARCore 공식문서

Mapbox for unity

Mapbox for unity package 다운로드

  • 국내에 잘 알려져 있지 않지만 location based AR을 구현할 떄 정말 유용한 SDK 여서 소개한다😉

  • 웹사이트 및 애플리케이션을 위한 맞춤형 온라인 지도를 제공하는 업체인데 unity sdk 에서 위치 기반 AR 구현을 위한 기능을 제공하고 있다

  • AR foundation 설치 필요


  • Mapbox sdk 유니티에서 실행하기 (유니티 버전 2019.3.13 기준)

    mapbox sdk 임포트 오류 해결 방법

    내 경우 unity에 import하는 데에도 많은 에러가 생겼었다. 유니티 버전을 맞추면 다음 단계를 따르면 문제없이 import가 가능할 것이다.

    1. 유니티에서 새로운 3D 프로젝트를 생성
    2. 다운받은 mapbox unity package를 프로젝트의 asset폴더에 드래그 드롭 해서 import 시켜준다.(매우 오래걸림!)
    3. mapbox setup이 pop up되지 않거나, 상다바에 mapbox menu가 떠야하는데 아마 안뜨고 임포트 중간에 pause될 것이다.
    4. window-> packagemanager 에서 ar Foundation을 install 하면 다음과 같은 에러가 뜬다.
    5. 에러 메세지를 클릭해서 cs코드를 열고 여기의 코드로 바꿔준다
    그러면 마저 import가 진행되고 mapbox setup이 뜬다!
    6. 이제 mapbox.com에서 token을 가져와야한다. mapbox에 회원가입 후 account 페이지에서 create token을 하거나 public token을 복사해서 access token에 붙여넣기 후 submit 해준다.
    7. token인증 후 맵 prefabs가 활성화되고 원하는 map prefabs를 선택하면 된다.



게임형 AR 전시회, EWHA CANVAS 만들기

🌟AR Foundation + Ar Core + Mapbox 를 사용해서 게임형 AR 전시회 어플리케이션을 만들어보자🌟

목차
0. 게임 시나리오
1. MarkerAR & Markerless AR
2. SDK 충돌문제 해결하기
3. Mapbox 사용해서 Markerless AR(locoation based) 구현하기
4. AR core 사용해서 Marker AR 구현하기
5. AR 오브젝트 터치 기능 구현하기

0. 게임시나리오

  1. 이화여대 캠퍼스 내에 7개의 전시 구역(건물 위주)을 설정하고 구역 중 한 곳을 Menu에서 터치한다.

  2. 사용자가 선택한 구역에 해당되는 작가 설명과 정확한 위치사진을 알려준다.

  3. 유저는 그 위치로 간다.

  4. 해당 위치에 가면 GPS기반 (즉, Markerless AR)AR 작품들을 감상할 수 있다.

  5. 화면을 아무곳이나 터치하면 작품에 대한 설명들을 볼 수 있는데, 여기에 Marker의 위치에 대한 힌트가 있다.

  6. 힌트를 종합해서 숨겨진 Marker를 찾아낸다.

  7. Marker를 인식하면 AR 오브젝트로 아이템을 얻고 이 오브젝트를 터치하면 Clear.

  8. 해당 구역을 Cleargk하면 다시 Menu화면으로 돌아가 다른 구역을 관람한다.

1. Marker AR & Markerless AR

✔ Marker AR

AR을 구현하는 기술 중 가장 많이 상용화 된 기술이며 익숙한 기술일 것이다.
현실세계의 마커를 카메라로 인식하면 디바이스의 화면에 AR오브젝트를 띄우는 방식이다.


장점)

  • 많은 AR 라이브러리들이 마커인식 AR 방식을 편리하게 제공해주고 있다. (ex. Vuforia, ARcore)
  • AR오브젝트가 안정감있게 보여진다.

단점)

  • 오버로드가 심하다.
  • 현실의 마커가 필요하므로 번거롭다.

✔ Markerless AR

마커인식 AR의 단점을 극복하기 위해 마커없이 AR 오브젝트를 띄우기 위한 다양한 방법이 있다.

  • 사용자가 AR오브젝트를 직접 움직이면서 위치시키기
    ex) 이케아 가구 배치
  • 위치기반 AR
    ex) 포켓몬고

Ewha Canvas는 marker 와 markerless 두가지 방식 모두를 사용하여 AR을 구현해볼 것이다.

2. SDK 충돌문제 해결하기

Mapbox SDK 💥 AR Core 💥 AR foundation

Mapbox package를 import하며 AR foundation을 설치하는 과정이 있었다. 이 때 ar foundation이 ar core를 부분적으로 이용하는데 marker ar을 구혀하기 위해 import한 ar core package와 충돌이 일어나는 문제가 발생하였다.
콘솔창 확인 결과 plugin 파일들이 겹쳐서 충돌이 일어났다.

해결방법은?


AR core 하위의 SDK 폴더안의 plugins 파일 중
google_ar_optional.aar, google_ar_required.aar, libarcore_unity_api.so, libarpresto_api.so 만 남기고 나머지를 지워준다.
(이유는 알수없음.. 직접 하나하나 다 지워봤다..!^^)

3. Mapbox 사용해서 Markerless AR(locoation based) 구현하기

Mapbox의 map prefabs 중 World Scale AR을 이용하여 location based AR 을 구현한다.

  1. Layersdp 8.ARGameObject, 9.Map, 10.Path, 11.Both 추가
  2. hierarcy 창에서 ArAlignedMap > Inspector > POINTS OF INTEREST에서
    AR오브젝트에 해당하는 Prefab을 넣어주고 Prefab Location부분에 Add location 하여 AR오브젝트를 위치시킬 위치의 좌표값을 넣어준다.

    결과

4. AR core 사용해서 Marker AR 구현하기

AR Core를 import하면 AR Session Origin이 heirarchy창에 추가되는데 이것을 WorldAlignmentKit 오브젝트 하위에 넣어준다. 그리고 두 AR 라이브러리가 동일한 AR 카메라를 공유하도록 설정해줘야한다. AR Sesssion Origin의 Camera가 별도의 ar camera로 초기 설정되어 있는데 이를 WorldAlignmentKit에서 사용하는 AR camera인 Main Camera 로 바꿔줘야 한다.

Multiple Marker, Multiple AR

Ar core에서 제공하는 마커인식 ar 기능은 AR Tracked Image Manager ReferenceImageLibrary를 이용한다.
하지만 기본적으로 제공하는 것은 마커 이미지는 여러개 사용가능하지만 그에 대응하는 AR 오브젝트는 하나밖에 설정할 수 없다.
일반적으로 marker : AR 은 1:1 이여야 하므로 추가적인 스크립트가 필요하다.

//MultiMarker.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.ARFoundation;

[RequireComponent(typeof(ARTrackedImageManager))]

public class NewBehaviourScript : MonoBehaviour
{
    [SerializeField]

    private GameObject[] placeablePrefabs;

    private Dictionary<string, GameObject> spawnedPrefabs = new Dictionary<string, GameObject>();
    private ARTrackedImageManager trackedImageManager;


    private void Awake()
    {
        trackedImageManager = FindObjectOfType<ARTrackedImageManager>();

        foreach (GameObject prefab in placeablePrefabs)
        {
            GameObject newPrefab = Instantiate(prefab, Vector3.zero, Quaternion.identity);
            newPrefab.name = prefab.name;
            spawnedPrefabs.Add(prefab.name, newPrefab);
        }

    }

    private void OnEnable()
    {
        trackedImageManager.trackedImagesChanged += ImageChanged;

    }

    private void OnDisable()
    {
        trackedImageManager.trackedImagesChanged -= ImageChanged;
    }

    private void ImageChanged(ARTrackedImagesChangedEventArgs eventArgs)
    {

        foreach (ARTrackedImage trackedImage in eventArgs.added)
        {
            UpdateImage(trackedImage);
        }

        foreach (ARTrackedImage trackedImage in eventArgs.updated)
        {

            UpdateImage(trackedImage);
        }

        foreach (ARTrackedImage trackedImage in eventArgs.removed)
        {
            spawnedPrefabs[trackedImage.name].SetActive(false);
        }

    }

    private void UpdateImage(ARTrackedImage trackedImage)
    {
        string name = trackedImage.referenceImage.name;
        Vector3 position = trackedImage.transform.position;

        GameObject prefab = spawnedPrefabs[name];
        prefab.transform.position = position;
        prefab.SetActive(true);

        foreach (GameObject go in spawnedPrefabs.Values)
        {
            if (go.name != name)
            {
                go.SetActive(false);
            }
        }
    }



}

Tracked 된 이미지(marker) 가 바뀌면 그에 해당하는 AR오브젝트를 별도의 라이브러리에서 찾아와서 ReferenceImageLibrary에 제공하는 코드이다.

5. AR 오브젝트 터치 기능 구현하기

Marker 인식 후 발생한 AR오브젝트를 터치할 수 있도록 하여 Interaction을 높이고자 했다. 이 때 쓸 수 있는 유니티 라이브러리는 ARRaycastManager 이다. 쉽게 말해서 터치한 위치에서 ray를 쏘고, 오브젝트에 ray가 맞으면 이 오브젝트를 터치했다 라고 인식하는 원리이다.
이 때 조건은 오브젝트는 특정 위치에 고정되어있어야 한다는 것이다.

그런데, ARcore에서 제공하는 마커인식 AR의 경우 AR을 특정 좌표를 할당하여 고정시켜놓지 않는다. (Vuforia에서는 유니티에서 마커를 기준으로 AR오브젝트의 위치를 설정할 수 있다.) 따라서 AR터치가 불가능했다.

그 대신 interaction의 효과를 내기 위해, AR오브젝트는 tracked image위에 발생하니, tracked image를 터치할 수 있으면 AR오브젝트를 터치하는 것과 같은 경험을 유발된다. 즉, 아래의 코드는 정확히는 AR object를 터치하는 것 대신 tracked image를 터치하는 것이다.

//TouchImageTarget.cs

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.XR.ARFoundation;
using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEngine.EventSystems;

[RequireComponent(typeof(ARRaycastManager))]
public class TouchImageTarget : MonoBehaviour
{
    private ARRaycastManager arRaycastManager;

    [SerializeField]
    private Camera arCamera;

    private static List<ARRaycastHit> hits = new List<ARRaycastHit>();

    //public GameObject myPrefab;
    // Start is called before the first frame update

    private Vector2 touchPosition = default;

    void Awake()
    {
        arRaycastManager = GetComponent<ARRaycastManager>(); 
    }

    void Start()
    {
        
    }

    public void newObject(string objName)

    {
        Instantiate(Resources.Load("Prefabs/" + objName), new Vector3(0, 0, 0), Quaternion.identity);
    }


    // Update is called once per frame
    void Update()
    {

        if (Input.touchCount > 0)
        {
            Touch touch = Input.GetTouch(0);

            touchPosition = touch.position;

            if (arRaycastManager.Raycast(touchPosition, hits, UnityEngine.XR.ARSubsystems.TrackableType.Image)) //if you touch the Ar tracked image
            {

                string currentScene = SceneManager.GetActiveScene().name; //find the current scene and intantiate proper prefab
                switch (currentScene)
                {
                    case "LARGE":
                        newObject("Dae_ClearCanvas");
                        break;
                    case "MIDDLE":
                        newObject("Joong_ClearCanvas");
                        break;
                    case "ECC":
                        newObject("ECC_ClearCanvas");
                        break;
                    case "POSCO":
                        newObject("Posco_ClearCanvas");
                         break;
                    case "GSM":
                        newObject("GSM_ClearCanvas");
                         break;
                    case "LIBRARY":
                        newObject("Lib_ClearCanvas");
                         break;
                    case "MUSEUM":
                        newObject("Museum_ClearCanvas");
                        break;
                }
            }
        }
    }
}

터치한 이미지들을 해당 씬 이름으로 구분하고, 그 이미지에 해당하는 스테이지 클리어 prefabs를 initiate하도록 한 코드이다.

이상 게임형 AR 전시회, EWHA CANVAS 어플리케이션에 사용된 기술들의 소개였습니다. 더 자세한 코드들은 EwhaCanvas 깃헙에서 확인 가능합니다.😉

여기에서 apk 파일 다운로드 하실 수 있습니다.😊 이화여대가 근처라면 한번 관람해보세요!ㅎㅎ

profile
#백엔드 #Python #Go #BlockChain
post-custom-banner

3개의 댓글

comment-user-thumbnail
2021년 8월 17일

맵박스 setup 뜨게하는 과정에서 코드 수정하는 부분 링크 누르면 없네요ㅠㅠ 혹시 알려주실 수 있을까요..

1개의 답글
comment-user-thumbnail
2021년 11월 17일

감사합니다 MapBox 유니티 관련 자료가 별로 없었는데, 많은 도움 받았습니다.

답글 달기