# Requirements & Supports

### SDK 지원 사양

* Unity : 2020.3.25f 이상
* Support Platform

  * iOS / Android / MacOS / Windows

  💡 Windows과 MacOS는 유니티의 Editor만 지원 합니다.


# Setup Guide

유니티에서 MAXVERSE SDK 사용하기 위한 셋팅 방법을 설명합니다.

## 기본 개발 환경 설정

**요구사항**

* MAXST MAXVERSE SDK는 Unity 2020.3.25f  버전 이상을 권장합니다.
* Unity용 MAXST MAXVERSE SDK를 사용하기 위해서는 Unity 개발 도구와 Unity 개발에 대한 기본적인 지식이 필요합니다.
* Unity 개발 도구에 대한 자세한 정보는 [유니티 웹사이트](https://unity3d.com/)를 이용하시기 바랍니다.

## 동영상 간편 가이드

{% embed url="<https://www.youtube.com/watch?ab_channel=MAXST&v=pL1cZ6LoDro>" %}

{% hint style="info" %}
[00:32](https://www.youtube.com/watch?v=pL1cZ6LoDro\&t=32s) unitypackage 추가                 [00:49](https://www.youtube.com/watch?v=pL1cZ6LoDro\&t=49s) Package 추가\
[02:22](https://www.youtube.com/watch?v=pL1cZ6LoDro\&t=142s) Android 세팅                           [02:54](https://www.youtube.com/watch?v=pL1cZ6LoDro\&t=174s) XRData Load\
[03:08](https://www.youtube.com/watch?v=pL1cZ6LoDro\&t=188s) XRData atm, ant 에러조치      [03:19](https://www.youtube.com/watch?v=pL1cZ6LoDro\&t=199s) XRData POV생성\
[03:35](https://www.youtube.com/watch?v=pL1cZ6LoDro\&t=215s) VR 테스트                                [04:07](https://www.youtube.com/watch?v=pL1cZ6LoDro\&t=247s) AR테스트시 메쉬 검은현상 조치\
[04:36](https://www.youtube.com/watch?v=pL1cZ6LoDro\&t=276s) Occlusion 설정
{% endhint %}

## MAXST MAXVERSE Unity SDK 설치

1. **MAXVERSE SDK** 를 다운로드 합니다.
2. Unity Project 열거나 새로 생성하세요.
3. 새로 생성 했을 경우,  **MAXSTMAXVERSESDK\_\*.\*.\*.unitypackage** 를 다운 받아 유니티에 설치 하세요.
4. **XRData**를 다운 받아 위치에 맞는 XR 공간맵을 설치해 주세요.

{% hint style="info" %}
해당 파일은 <https://beta-developer.maxverse.io/products/sdk> 를 통해 다운 받으세요.
{% endhint %}

## Unity Setting

Unity의 File/Build Settings/Player Settings에 대한 설명 입니다.

{% hint style="danger" %}

* Android는 Other Settings의 Graphics APIs를 **OpenGLES3**만 선택되어야 합니다.
* Android는 **Multithreaded Rendering**의 체크를 해지해 주세요.
* Adnroid는 Publishing Settings에 **Custom Main Manifest**와 **Custom Main Gradle Template**가 설치 되어야 합니다.&#x20;
  {% endhint %}

해당 **Manifest**와 **Gradle** 셋팅은 아래의 Github 링크를 참고 바랍니다.&#x20;

| [AndroidManifest.xml](https://github.com/maxstdev/MAXVERSESDKUnity/blob/main/Assets/Plugins/Android/AndroidManifest.xml) |
| ------------------------------------------------------------------------------------------------------------------------ |
| [MainTemplate.gradle](https://github.com/maxstdev/MAXVERSESDKUnity/blob/main/Assets/Plugins/Android/mainTemplate.gradle) |

{% hint style="warning" %}
iOS는 **Camera Usage Description 과 Location Usage Description**에 문구를 추가해 주세요.
{% endhint %}

### Unity Project Setting

* **Package Manager**에서 git을 통해서 Source를 받기 때문에 **해당 컴퓨터에 git이 설치** 되어 있어야 합니다.
  * <https://git-scm.com/> 링크를 통해서 설치 하세요.
* 아래 코드와 같이 패키지가 추가 되어 있어야 합니다.&#x20;
* Package Manager에 대해서는 <https://docs.unity3d.com/kr/2020.3/Manual/upm-ui.html> 링크를 참고 하세요.

{% code title="manifest.json" %}

```json
{
    "dependencies": {
      ....
      "com.akb.knn": "https://github.com/Level3Manatee/KNN.git",
      "com.atteneder.ktx": "1.1.1",
      "com.unity.editorcoroutines": "1.0.0",
      ....
    },
    "scopedRegistries": [
      {
        "name": "Atteneder",
        "url": "https://package.openupm.com",
        "scopes": [
          "com.atteneder"
        ]
      }
    ]
  }
  
```

{% endcode %}

### Unity Error

Unity 2021.3.5 이상일 경우 아래와 같은 메시지가 나옵니다.

{% hint style="warning" %}
Library\PackageCache\\<com.unity.jobs@0.1.1-preview>\Unity.Jobs\IJobParallelForDefer.cs(176,85): error CS8377: The type 'U' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method 'NativeList\<T>'
{% endhint %}

해당 메시지에 대한 해결 방법은 아래와 같습니다.

Unity 상단 메뉴의 Edit->Project Settings->PackageManager를 선택하면 아래와 같이 나타납니다. PackageManer 의 **Show Dependencies를 check** 합니다.

![PackageManager](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FMpHxujsPiDATx9rSoA6Z%2Fimage.png?alt=media\&token=f90d69cb-a8c7-45f1-a2c1-53ecb15d74b6)

Unity 상단 메뉴의 Window->Package Manager를 클릭하면 아래와 같은 윈도우가 생성 됩니다.

![Package Manager](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2F1JcSFFVer2AM32jPkYAj%2Fimage.png?alt=media\&token=3a090147-d779-43a8-a0f3-6b3daf7508cc)

Jobs 찾아 Update를 합니다.

### XR SDK 공간맵 설치

* XR 공간맵은 해당 지역의 메쉬와 레퍼런스 이미지, 시뮬레이션 데이터를 포함합니다. XR 공간맵은 아래 그림과 같이 Unity Project 폴더와 동일 레벨에 XRData 폴더를 생성하고 XRData 하위에 저장되어야 합니다.

  MAXST에서 제공하는 [공간맵 파일(링크)](https://beta-developer.maxverse.io/products/map)을 Unity Project 폴더와 동일 레벨에서 압축을 해제하면 자동으로 XRData 폴더 하위에 XRMap 폴더와 XRSimulationData 폴더가 있고 두 폴더 하위에는 해당 맵 폴더가 생성됩니다.

![폴더 구조](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FRuornyo821YHMqh4xAO3%2Fimage.png?alt=media\&token=7e76441a-e786-4d9d-8c68-32583689550e)


# Unity Scene 구성

MAXST MAXVERSE의 Unity Scene 구성에 대해서 설명합니다.

## Scene 구성 개요&#x20;

MAXST MAXVERSE의 Unity Scene Hierarchy는 다음과 같습니다.

{% hint style="success" %}

* **XRCamera GameObject** : 트래킹 중인 카메라의 이미지와 자세를 처리합니다.
* **XRStudio GameObject** : XR 공간지도 데이터를 표합니다.
* **Trackable GameObject** : XR 공간지도 상에 렌더링하는 3D Object들의 Root Object입니다. (렌더링하려는 3D Object는 Root Object의 하위에 배치해야 합니다.)
* **SceneManager GameObject** : MAXST MAXVERSE SDK 작동을 컨트롤합니다.
  {% endhint %}

## XRCamera GameObject

![XRCamera Hierarchy](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FGIWQgav1rXvdUrJJlIJk%2Fimage.png?alt=media\&token=d8e5d0ab-ccfb-48f3-80ed-e2dd365eddcd)

{% hint style="info" %}
XRCamera는 사용자 기기의 카메라 **6자유도 자세(Position/Rotation)**&#xB97C; 반영합니다.&#x20;
{% endhint %}

**CameraBackground GameObject**

CameraBackground는 하드웨어 카메라로부터 얻은 이미지를 표시합니다.

## XRStudio GameObject

XRStudio는 XR 공간지도 데이터를 관리합니다.

![XRStudio](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FU2wcHwciKVOqv3br3HEn%2Fimage.png?alt=media\&token=9f3e134e-0e2d-4b26-b830-c94774cc23dd)

**XRStudio Controller 메뉴는 다음과 같습니다**

* XR Map 콤보 박스를 통해 XRData 폴더 하위에 저장된 XR 공간지도 리스트를 확인하고 원하는 지역을 선택할 수 있습니다.
* XR Simulation Data 콤보 박스를 통해 XRData/XRSimulationData/*your\_xr\_map* 하위에 저장된 시뮬레이션 데이터 리스트를 확인하고 원하는 시뮬레이션 데이터를 선택할 수 있습니다.
* Load XR Map버튼을 누르면 선택 지역에 대한 메쉬와 XRPov 카메라를 로드합니다.
* Clear버튼을 누르면 선택 지역에 대한 메쉬와 XRPov 카메라를 삭제 합니다.
* **ARMode** 를 선택하면 ARMode가 실행 되고 uncheck하면 VR 모드로 실행이 됩니다.

{% hint style="info" %}
XRPov는 3D Object 배치시 최적의 시점을 선택하여 배치할 수 있습니다.&#x20;
{% endhint %}

## Scene Manager

SceneManager는 XR 작동을 컨트롤합니다.

![](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2Fag1SIDbRp3bA3B23wtpZ%2Fimage.png?alt=media\&token=62a6e15f-21c2-4dae-878b-ad52dcd5d289)

* Disable Objects는 Unity Play시점에 disable할 GameObject들입니다.(XRStudio GameObject는 카메라 시점을 포함하기 때문에 disable해야 합니다.
* Occlusion Objects는 Unity Play시점에 Occlusion 처리를 할 Mesh들 입니다. 추가로 Occlusion이 필요한 Mesh가 존재한다면, 해당 부분에 추가 하면 됩니다.
* isOcclusion을 check를 하게되면 runtime에 Occlusion Objects에 포함된 메쉬에 Occlusion을 적용하게 됩니다.
* StartPov는 VR실행시에 시작하게되면 시점을 말합니다.
* Poi Prefab은 poi위치에 놓을 컨텐츠 입니다.
* Arrow Prefab은 네비게이션 경로에 놓을 컨텐츠 입니다.
* Arrow Visible Distance는 경로가 보일 최대 위치 거리를 말합니다.


# 3D Object 배치

Unity Scene View 상에서 렌더링할 3D Object를 쉽게 배치하고 XRPov를 통해 정교하게 위치 조정하며 마지막으로 시뮬레이션하는 방법 대한 설명입니다.

## Load XR Map&#x20;

저작하려는 XR Map을 XRStudio GameObject의 **XRStudioController**를 통해 실행 합니다.

![XRStudio GameObject](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FSMg7KB3ny8fPd5b2y6Lt%2Fimage.png?alt=media\&token=44226aeb-53d2-4c00-aad6-541b625da7fd)

XRStudio Load XR Map Button을 클릭하게 되면 아래의 그림과 같이 **Unity Scene View**에 선택한 Map이 표시 됩니다.

![XR Map 로드 후 Unity Scene View](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2F4SRPCpNHWTMdOzM7d0FE%2Fimage.png?alt=media\&token=282f95cb-7a0c-4fb1-bd41-aef6500b8946)

## XR Pov

XRStudio의 Load XR Map을 하게 되면 아래와 같이 Hierarchy에 맵이 추가 됩니다.

![](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2Fnaeo9AQjfh5CcDEIldd9%2Fimage.png?alt=media\&token=62c3e334-6d6e-40a2-9c43-48da806bab35)

XRPov를 클릭하면 아래와 같이 표시 됩니다.

![](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FEt8rzWKG2bcULBjzeLI8%2Fimage.png?alt=media\&token=b4c5272f-519a-491d-a9ca-ef3017cf8e31)

{% hint style="danger" %}

* Atm and Atn are not compatible!
  {% endhint %}

위와 같은 메시지나 나타날 경우 Pov Manager의 atm을 선택 합니다.

![](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2Flek1KjPBm8mdPzTR2N4y%2Fimage.png?alt=media\&token=1831dde6-76a7-4903-897e-825bf70e66b2)

선택한 atm의 atn을 지우고 Apply 버튼을 클릭 합니다.

![](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FOH0G1iD3NAPExAJUzHIZ%2Fimage.png?alt=media\&token=ca7ca996-d7b7-45ba-8998-e008259f3083)

atm 파일과 같은 atn파일을 선택하고 다시 Apply 버튼을 클릭 합니다.

![](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2Fq5FGOxU4mUKgu1Uol2wz%2Fimage.png?alt=media\&token=95c2405c-9608-4964-b8c1-8766883561a2)

셋팅이 다시 되면 아래와 같이 XRPov에 버튼이 생성 됩니다.

![](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2F97YFeWHj21kgc4pXK0v5%2Fimage.png?alt=media\&token=e28942e2-be03-4370-8d64-2abeb2547de1)

Create All POVs를 클릭하면 카메라 촬영시점의 POV가 생성 됩니다.&#x20;

다수의 POV가 생성 되어 Unity가 느려 질수 있습니다. Gizmo를 Disable 하면 속도가 개선 됩니다. 하단의 적색 박스가 Gizmo 입니다.

![](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FEAq4mH8DYicJIdAsXkx4%2Fimage.png?alt=media\&token=53672424-eed2-42e0-9e99-9e2361d56483)

## 콘텐츠 저작

콘텐츠의 배치는 Map의 **Mesh**의 위치를 기본으로 이루어집니다. **Mesh** 주위의 원하는 부분에 콘텐츠를 배치하고 주변의 **XRPov**의 하위 **Pov** 통해서 확인을 합니다.

![Mesh와 정합](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FoT0puHh9ScTe8xT4yDME%2Fimage.png?alt=media\&token=5eb0a0c2-f010-4e70-873c-7b96431678df)

![컨텐츠 주변의 POV 선택](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FeSYwrhMBc9VKgMOZmNui%2Fimage.png?alt=media\&token=57206484-b950-4ac1-97e3-8f879ae124d9)

![Pov 선](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FBN5rgJd9S7bBhI1Yl5hG%2Fimage.png?alt=media\&token=d5fe439e-a29d-4b5b-951e-7a4d365c4cbf)

* XRPov 하위의 Pov를 선택하면 Inspector에 위와 같이 표시가 됩니다. 선택된 Pov의 카메라 상태를 확인하려면, **Start From This Button**을 선택해서 해당 Pov의 화면으로 변경 할 수 있습니다.

{% hint style="warning" %}
Pov를 선택한 상태에서 컨텐츠의 위치를 변경하면 사용자가 원하는 위치를 맞출 수 있습니다.
{% endhint %}

## 시뮬레이션 데이터를 이용한 컨텐츠 저작 상태 확인

저작을 완료 하면 **XRStudio**의 **XR Simulation Data**를 통해서 확인 할 수 있습니다. 해당 지역의 Simulation Data로 OSX나 Windows에서 Play 시점에 확인 할 수 있습니다.

![Unity Game View](https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FXKBPjThBKMzhl31QaniD%2Fimage.png?alt=media\&token=275245e2-ed3c-4666-943c-3a14741e6147)

## Occlusion 처리를 위한 Mesh 설정

**Occlusion**(건물 메쉬에 의한 가려짐)에 대한 설명은 아래 페이지에 설명 되어 있습니다.

{% content-ref url="/pages/2LSxej1ZWBOmyff84rSh" %}
[Scene Manager 설명](/unity/scene-manager)
{% endcontent-ref %}


# Scene Manager 설명

SceneManager에 대한 설명입니다.

## SceneManager에서 필수 구성 요소 얻기&#x20;

아래는 SceneManager의 **필수 구성 요소**를 얻는 코드입니다.&#x20;

{% hint style="success" %}
**필수 구성 요소**

* XRManager
* XRCamera
* XRStudioController
* Trackable
  {% endhint %}

{% code title="MaxstSceneManager.cs" %}

```csharp
ARManager arManagr = FindObjectOfType<ARManager>();
if (arManagr == null)
{
    Debug.LogError("Can't find ARManager. You need to add ARManager prefab in scene.");
    return;
}
else
{
    arCamera = arManagr.gameObject;
}


VPSTrackable[] vPSTrackables = FindObjectsOfType<VPSTrackable>(true);
if (vPSTrackables != null)
{
    vPSTrackablesList.AddRange(vPSTrackables);
}
else
{
    Debug.LogError("You need to add VPSTrackables.");
}

foreach (GameObject eachObject in disableObjects)
{
    if(eachObject != null)
    {
        eachObject.SetActive(false);
    }
}

if (XRStudioController.Instance.ARMode)
{
    AndroidRuntimePermissions.Permission[] result = AndroidRuntimePermissions.RequestPermissions("android.permission.WRITE_EXTERNAL_STORAGE", "android.permission.CAMERA", "android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION");
    if (result[0] == AndroidRuntimePermissions.Permission.Granted && result[1] == AndroidRuntimePermissions.Permission.Granted)
        Debug.Log("We have all the permissions!");
    else
        Debug.Log("Some permission(s) are not granted...");

    cameraBackgroundBehaviour = arManagr.GetCameraBackgroundBehaviour();
    if (cameraBackgroundBehaviour == null)
    {
        Debug.LogError("Can't find CameraBackgroundBehaviour.");
        return;
    }

    foreach (VPSTrackable vPSTrackable in vPSTrackablesList)
    {
        vPSTrackable.gameObject.SetActive(false);
    }
}
else
{
    this.enabled = false;

    if(startPov != null)
    {
        startPov.StartPlace();
    }
}
```

{% endcode %}

{% hint style="info" %}
**XRStudioController**로 위치 인식을 위한 서버 이름을 얻습니다.
{% endhint %}

## Occlusion (건물 메쉬에 의한 가려짐) 구현

렌더링하고자 하는 3D 오브젝트가 건물 메쉬에 의해 가려지는 효과를 Occlusion effect라고 합니다. Occlusion은 runtimeBuildingMaterial를 렌더링시 적용함으로써 구현됩니다.

{% code title="MaxstSceneManager.cs" %}

```bash
foreach (GameObject eachGameObject in occlusionObjects)
{
    Renderer[] cullingRenderer = eachGameObject.GetComponentsInChildren<Renderer>();
    foreach (Renderer eachRenderer in cullingRenderer)
    {
        eachRenderer.material.renderQueue = 1900;
        eachRenderer.material = runtimeBuildingMaterial;
    }
}
```

{% endcode %}

## 카메라 시작 / 시뮬레이션 시작&#x20;

스마트폰과 스마트 글래스와 같은 모바일 기기 환경에서는 아래 코드를 통해 하드웨어 카메라가 시작됩니다. MAC OS X와 Windows 환경에서는 XRStudioController를 통해 선택한 시뮬레이션 데이터가 시작됩니다. 이를 통해 현장에 직접 나가지 않아도 앱 개발이 가능합니다.

{% code title="MaxstSceneManager.cs" %}

```csharp
if (Application.platform == RuntimePlatform.OSXEditor || Application.platform == RuntimePlatform.WindowsEditor)
{
    string simulatePath = vPSStudioController.vpsSimulatePath;
    if (Directory.Exists(simulatePath))
    {
        CameraDevice.GetInstance().Start(simulatePath);
        MaxstAR.SetScreenOrientation((int)ScreenOrientation.Portrait);
    }
}
else
{
    if (CameraDevice.GetInstance().IsFusionSupported(CameraDevice.FusionType.ARCamera))
    {
        CameraDevice.GetInstance().Start();
    }
    else
    {
        TrackerManager.GetInstance().RequestARCoreApk();
    }
}

```

{% endcode %}

## XR Tracker 시작

XR Tracker를 시작해야 AR이 작동하게 됩니다. XRAPI.cs의 SetPlaceIdAndSpotId 함수를 통해서 POI와 Navigation을 얻기 위한 정보를 획득 합니다.

{% code title="MaxstSceneManager.cs" %}

```csharp
TrackerManager.GetInstance().StartTracker();
```

{% endcode %}

## XR 트래킹 결과 얻기&#x20;

트래킹 결과는 UpdateFrame()과 GetARFrame()을 통해서 얻을 수 있습니다. GetARFrame()을 통해 얻은 ARFrame의 인스턴스에는 현재 트래킹 상태, 이미지, 6자유도 자세를 포함되어 있습니다.

ARFrame의 GetARLocationRecognitionState()를 통해서 현재 위치 인식 상태를 얻을 수 있습니다. 이 상태 정보에 맞춰 증강시킬 3D Object의 활성화 여부를 결정합니다.

{% code title="MaxstSceneManager.cs" %}

```csharp
void Update()
{
    UpdateVisibleArrow(arCamera);

    if (!XRStudioController.Instance.ARMode)
    {
        return;
    }

    TrackerManager.GetInstance().UpdateFrame();

    ARFrame arFrame = TrackerManager.GetInstance().GetARFrame();

    TrackedImage trackedImage = arFrame.GetTrackedImage();

    if (trackedImage.IsTextureId())
    {
        IntPtr[] cameraTextureIds = trackedImage.GetTextureIds();
        cameraBackgroundBehaviour.UpdateCameraBackgroundImage(cameraTextureIds);
    }
    else
    {
        cameraBackgroundBehaviour.UpdateCameraBackgroundImage(trackedImage);
    }

    if (arFrame.GetARLocationRecognitionState() == ARLocationRecognitionState.ARLocationRecognitionStateNormal)
    {
        Matrix4x4 targetPose = arFrame.GetTransform();

        arCamera.transform.position = MatrixUtils.PositionFromMatrix(targetPose);
        arCamera.transform.rotation = MatrixUtils.QuaternionFromMatrix(targetPose);
        arCamera.transform.localScale = MatrixUtils.ScaleFromMatrix(targetPose);

        string localizerLocation = arFrame.GetARLocalizerLocation();

        if (currentLocalizerLocation != localizerLocation)
        {
            currentLocalizerLocation = localizerLocation;
            foreach (VPSTrackable eachTrackable in vPSTrackablesList)
            {
                bool isLocationInclude = false;
                foreach (string eachLocation in eachTrackable.localizerLocation)
                {
                    if (currentLocalizerLocation == eachLocation)
                    {
                        isLocationInclude = true;
                        currentLocalizerPlaceId = eachTrackable.placeId;
                        break;
                    }
                }
                eachTrackable.gameObject.SetActive(isLocationInclude);
            }
        }
    }
    else
    {
        foreach (VPSTrackable eachTrackable in vPSTrackablesList)
        {
            eachTrackable.gameObject.SetActive(false);
        }
        currentLocalizerLocation = "";
    }
}
```

{% endcode %}


# POI 설명

Poi(point of interest)를 획득 하는 방법을 설명 합니다.

{% code title="MaxstSceneManager.cs" %}

```csharp
public void OnClickGetPOI()
{
    poiDatas.Clear();
    string accessToken = TrackerManager.GetInstance().GetAccessToken();

    if (!XRStudioController.Instance.ARMode)
    {
        VPSTrackable eachTrackable = vPSTrackablesList[0];
        
        POIController.GetPOI(this, accessToken, eachTrackable.placeId, success: (pois) => {
            poiDatas.AddRange(pois);
            GameObject poiGameObject = new GameObject();
            poiGameObject.name = "POI";
            poiGameObject.transform.position = new Vector3(0, 0, 0);
            poiGameObject.transform.eulerAngles = new Vector3(0, 0, 0);
            poiGameObject.transform.localScale = new Vector3(1, 1, 1);

            poiGameObject.transform.parent = arContent.transform;

            foreach (POIData eachPOI in pois)
            {
                GameObject eachPoiGameObject = Instantiate(poiPrefab);
                eachPoiGameObject.transform.position = eachPOI.GetVPSPosition();
                eachPoiGameObject.transform.parent = poiGameObject.transform;
                eachPoiGameObject.name = eachPOI.poi_name_ko;

                poiItems.Add(eachPoiGameObject);
            }

        },
        fail: () => {

        });
        return;
    }

    if (currentLocalizerPlaceId > 0)
    {
        POIController.GetPOI(this, accessToken, currentLocalizerPlaceId, success:(pois)=> {
            poiDatas.AddRange(pois);
            GameObject poiGameObject = new GameObject();
            poiGameObject.name = "POI";
            poiGameObject.transform.position = new Vector3(0, 0, 0);
            poiGameObject.transform.eulerAngles = new Vector3(0, 0, 0);
            poiGameObject.transform.localScale = new Vector3(1, 1, 1);

            poiGameObject.transform.parent = arContent.transform;

            foreach(POIData eachPOI in pois)
            {
                GameObject eachPoiGameObject = Instantiate(poiPrefab);
                eachPoiGameObject.transform.position = eachPOI.GetVPSPosition();
                eachPoiGameObject.transform.parent = poiGameObject.transform;
                eachPoiGameObject.name = eachPOI.poi_name_ko;

                poiItems.Add(eachPoiGameObject);
            }

        },
        fail:()=> {

        } );
    }
}
```

{% endcode %}

* POI를 호출하는 번호는 Trackable에 포함 되어 있습니다.
* POI는 placeId를 통해서 획득하게 됩니다.
* POIController.GetPOI()함수를 통해서 해당 위치의 POI를 획득 할 수 있습니다.

<figure><img src="https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FISnOhUV8yrIyRGY1qn55%2Fimage.png?alt=media&amp;token=b7428701-7fdf-4388-b6d0-fd8c1c2bc28e" alt=""><figcaption></figcaption></figure>

* 획득한 POI의 좌표를 이용하여 네비게이션에 활용 할수 있습니다.


# Navigation 설명

네비게이션을 사용하는 방법을 설명 합니다.

{% code title="MaxstSceneManager.cs" %}

```csharp
public void OnClickNavigation()
{
    RemovePaths();

    string accessToken = TrackerManager.GetInstance().GetAccessToken();

    if(XRAPI.Instance.spotData == null || XRAPI.Instance.placeData == null || XRAPI.Instance.placeData.place_unique_name == "" || XRAPI.Instance.spotData.vps_spot_name == "")
    {
        Debug.LogError("Can't Find Spot, Place Name");
        return;
    }
    
    if (!XRStudioController.Instance.ARMode)
    {
        VPSTrackable eachTrackable = vPSTrackablesList[0];
        NavigationController.FindPath(this, accessToken, XRAPI.Instance.spotData.vps_spot_name, arCamera.transform.position, XRAPI.Instance.spotData.vps_spot_name, new Vector3(11.82481f, 0f, 5.36951f), 2.0f, vPSTrackablesList.ToArray(),
            (paths) => {
                MakeNavigationArrowContent(paths);
            },
            () => {
                Debug.LogError("No Path");
            }, XRAPI.Instance.placeData.place_unique_name);
        return;
    }

    if (currentLocalizerLocation != null)
    {
        GameObject trackingObject = null;
        foreach (VPSTrackable eachTrackable in vPSTrackablesList)
        {
            foreach (string eachLocation in eachTrackable.localizerLocation)
            {
                if (currentLocalizerLocation == eachLocation)
                {
                    trackingObject = eachTrackable.gameObject;
                    break;
                }
            }
        }

        if (trackingObject != null)
        {
            NavigationController.FindPath(this, accessToken, XRAPI.Instance.spotData.vps_spot_name, arCamera.transform.position, XRAPI.Instance.spotData.vps_spot_name, new Vector3(11.82481f, 0f, 5.36951f), 2.0f, vPSTrackablesList.ToArray(),
            (paths) => {
                MakeNavigationArrowContent(paths);
            },
            () => {
                Debug.LogError("No Path");
            }, XRAPI.Instance.placeData.place_unique_name);
        }
    }
}
```

{% endcode %}

* 네비게이션 경로는 NavigationController.FindPath() 함수의 파라미터인 **place\_unique\_name**를 통해서 요청하게 됩니다. place\_unique\_name는 placeId를 통해서 획득하게 됩니다.
* 요청된 결과로 현재 사용자의 위치로 부터 목적지까지의 경로를 얻게 됩니다.
* MakeNavigationArrowContent() 함수로 컨텐츠 결과물을 확인할 수 있습니다.
* 네비게이션 검색 파라미터는 Trackable에 포함 되어 있습니다.
* 목적지에 대한 좌표는 POI를 통해서 획득 하거나, 메쉬의 주변부의 좌표를 획득해서 얻을 수 있습니다.

<figure><img src="https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FGwfo9ZX0h3uk8AazNmIp%2Fimage.png?alt=media&amp;token=ce9815fd-3c9f-4664-92e5-28723e975afd" alt=""><figcaption></figcaption></figure>


# 인증 정보 발급

인증 정보를 발급 받는 방법에 대한 설명 입니다.

## 인증 정보 발급&#x20;

* 인증 정보는 개발자사이트[(인증정보  관리)](http://developer.maxverse.io/my/authinfo) 에서 앱 이름과 앱 아이디정보를 등록한 후 발급 받을 수 있습니다.

&#x20;     <img src="https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2F8QLlCtPT3nhC0ARwGFls%2Fimage.png?alt=media&amp;token=5a1b22a1-7c8f-4f6f-b02f-1408dc1951e4" alt="" data-size="original">

* 아래와 같이 발급 받은 Client\_ID, Client\_SecretKey, ApplicationKey를 앱에서 사용 합니다.

<figure><img src="https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FE90LvlWiomo37d2GNrAY%2Fimage.png?alt=media&amp;token=7eee0f6c-3c7e-4078-b29b-d67679b6acfc" alt=""><figcaption></figcaption></figure>


# 인증 정보 적용

라이센스 사용 방법을 설명 합니다.

Unity Scene의 XRStudio GameObject를 선택합니다. 아래 그림과 같이 Inspector에 XRAPI를 찾습니다.

XRAPI에는 4가지 입력이 필요로 합니다.\
\- Client Id, Client SecretKey, Authorization URL, ApplicationKey

<figure><img src="https://2785293273-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FMZRlzYk2QjkbowxBTKUm%2Fuploads%2FZcOKGUGHZbqebVVhjwYG%2Fimage.png?alt=media&amp;token=3ae7b7d9-7cc3-4994-ab29-cbf8b65e791d" alt=""><figcaption></figcaption></figure>

* 앱 등록 사이트에서 발급 받은 Client Id와 Client secretKey, Authorization URL,Application Key를 위와 같이 입력합니다.
* 입력된 키로 token이 발급 되고 AR의 인식 및, POI, Navigation에서 사용됩니다.


# Release Note

## 0.10.4

* SSO(Ouath2) token 인터페이스 추가

```csharp
TrackerManager.GetInstance().SetSSOAccessToken("token");
```

* GPS 사용 최적화

## 0.10.0

* Navigation과 POI를 얻기 위한 placeId와 spotId 부분이 추가 되었습니다.
  * placeId와 spotId를 통해서 해당 API를 호출하기 위한 데이터를 확보합니다.

{% code title="MaxstSceneManager.cs" %}

```csharp
int placeId = trackable.placeId;
int spotId = trackable.spotId;
TrackerManager.GetInstance().SetPlaceIdAndSpotId(placeId, spotId);
```

{% endcode %}

* WebGL을 위한 Token API가 추가 되었습니다.


