Unity/AR

12. AR Foundation - Cloud Anchor (3) Cloud Anchor

๐Ÿ”ท Cloud Anchor

- local anchor๋ฅผ cloud anchor๋กœ ์˜ฌ๋ฆฌ๊ธฐ

 

๐Ÿ”ถ ๋งตํ•‘ ํ’ˆ์งˆ ๋งŒ์กฑํ•˜๋ฉด cloud anchor ์ƒ์„ฑ

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

// Google ARCore Extensions
using Google.XR.ARCoreExtensions;
using System;

public class CloudAnchorManager : MonoBehaviour
{
    // ์ƒํƒœ ๋ณ€์ˆ˜
    public enum Mode { READY, HOST, HOST_PENDING, RESOLVE, RESOLVE_PENDING };

    // ๋ฒ„ํŠผ
    public Button hostButton;       // ํด๋ผ์šฐ๋“œ ์•ต์ปค ๋“ฑ๋ก
    public Button resolveButton;    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ์กฐํšŒ
    public Button resetButton;      // ๋ฆฌ์…‹

    // ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ ํ…์ŠคํŠธ
    public Text messageText;

    // ์ƒํƒœ๋ณ€์ˆ˜
    public Mode mode = Mode.READY;
    // AnchorManager    // ๋กœ์ปฌ ์•ต์ปค๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ํด๋ž˜์Šค
    public ARAnchorManager anchorManager;
    // ArRaycastManager
    public ARRaycastManager raycastManager;

    // ์ฆ๊ฐ•์‹œํ‚ฌ ๊ฐ์ฒด ํ”„๋ฆฌํŒน
    public GameObject anchorPrefab;
    // ์ €์žฅ ๊ฐ์ฒด ๋ณ€์ˆ˜ (์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•œ ์šฉ๋„)
    private GameObject anchorGameObject;

    // ๋กœ์ปฌ์•ต์ปค ์ €์žฅ ๋ณ€์ˆ˜
    private ARAnchor localAnchor;
    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ๋ณ€์ˆ˜
    private ARCloudAnchor cloudAnchor;


    // Raycast Hit
    private List<ARRaycastHit> hits = new List<ARRaycastHit>();

    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ID ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ํ‚ค ๊ฐ’ (PlayerPregs.SetString("ํ‚ค", ๊ฐ’));
    private const string cloudAnchorKey = "CLOUD_ANCHOR_ID";
    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ID
    private string strCloudAnchorId;


    void Start()
    {
        // ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
        hostButton.onClick.AddListener(() => OnHostClick());
        resolveButton.onClick.AddListener(() => OnResolveClick());
        resetButton.onClick.AddListener(() => OnResetClick());
    }

    void Update()
    {
        if (mode == Mode.HOST)
        {
            Hosting();
            HostProcessing();
        }

    }

    void Hosting()
    {
        if (Input.touchCount < 1) return;

        Touch touch = Input.GetTouch(0);
        if (touch.phase != TouchPhase.Began) return;


        // ๋กœ์ปฌ ์•ต์ปค๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธ
        if (localAnchor == null)
        {
            // Raycast ๋ฐœ์‚ฌ
            if (raycastManager.Raycast(touch.position, hits, TrackableType.PlaneWithinPolygon))
            {
                // ๋กœ์ปฌ ์•ต์ปค๋ฅผ ์ƒ์„ฑ
                localAnchor = anchorManager.AddAnchor(hits[0].pose);
                // ๋กœ์ปฌ ์•ต์ปค ์œ„์น˜์— ์‚ฌ์Šด ์ฆ๊ฐ•์‹œํ‚ค๊ณ  ๋ณ€์ˆ˜์— ์ €์žฅ
                anchorGameObject = Instantiate(anchorPrefab, localAnchor.transform);
            }
        }
    }

    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ๋“ฑ๋ก
    void HostProcessing()
    {
        if (localAnchor == null) return;

        // ํ”ผ์ณํฌ์ธํŠธ์˜ ๊ฐฏ์ˆ˜ ๋ฐ ํ€„๋ฆฌํ‹ฐ ์ธก์ •
        FeatureMapQuality quality = anchorManager.EstimateFeatureMapQualityForHosting(GetCameraPose());

        string mappingText = string.Format("๋งตํ•‘ ํ’ˆ์งˆ = {0}", quality);

        // ๋งตํ•‘ ํ€„๋ฆฌํ‹ฐ๊ฐ€ 1 ์ด์ƒ์ผ ๋•Œ ํ˜ธ์ŠคํŒ… ์š”์ฒญ
        if (quality == FeatureMapQuality.Sufficient || quality == FeatureMapQuality.Good)
        {
            // 1์ผ์งœ๋ฆฌ ์•ต์ปคํฌ์ธํŠธ
            cloudAnchor = anchorManager.HostCloudAnchor(localAnchor, 1);

            if (cloudAnchor == null)
            {
                mappingText = "ํด๋ผ์šฐ๋“œ ์•ต์ปค ์ƒ์„ฑ ์‹คํŒจ";
            }
            else
            {
                // ์—ฌ๊ธฐ์„œ ํด๋ผ์šฐ๋“œ ์•ต์ปค ID ์ฐ์–ด๋„ ์•ˆ๋‚˜์˜ด
                // ์„œ๋ฒ„์—์„œ ์ž‘์—…ํ•˜๋Š” ์‹œ๊ฐ„์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—
                mappingText = "ํด๋ผ์šฐ๋“œ ์•ต์ปค ์ƒ์„ฑ ์‹œ์ž‘";
                mode = Mode.HOST_PENDING;
            }
        }

        messageText.text = mappingText;

    }

    // MainCamera ํƒœ๊ทธ๋กœ ์ง€์ •๋œ ์นด๋ฉ”๋ผ์˜ ์œ„์น˜์™€ ๊ฐ๋„๋ฅผ Pose ๋ฐ์ดํ„ฐ ํƒ€์ž…์œผ๋กœ ๋ฐ˜ํ™˜
    public Pose GetCameraPose()
    {
        return new Pose(Camera.main.transform.position, Camera.main.transform.rotation);
    }


    private void OnHostClick()
    {
        mode = Mode.HOST;
    }

    private void OnResolveClick()
    {
        mode = Mode.RESOLVE;
    }

    private void OnResetClick()
    {
    }

}

 

 

 

- ์—ฐ๊ฒฐ

 

 

 

- Build & Run

- Host ๋ฒ„ํŠผ ํด๋ฆญ > ์‚ฌ์Šด ์ƒ์„ฑ

- Text ๋ณ€ํ•จ : ๋งตํ•‘ ํ’ˆ์งˆ > Cloud Anchor ์ƒ์„ฑ ์‹œ์ž‘

 

 

 

๐Ÿ”ถ cloud anchor ์ƒ์„ฑ

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

// Google ARCore Extensions
using Google.XR.ARCoreExtensions;
using System;

public class CloudAnchorManager : MonoBehaviour
{
    // ์ƒํƒœ ๋ณ€์ˆ˜
    public enum Mode { READY, HOST, HOST_PENDING, RESOLVE, RESOLVE_PENDING };

    // ๋ฒ„ํŠผ
    public Button hostButton;       // ํด๋ผ์šฐ๋“œ ์•ต์ปค ๋“ฑ๋ก
    public Button resolveButton;    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ์กฐํšŒ
    public Button resetButton;      // ๋ฆฌ์…‹

    // ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ ํ…์ŠคํŠธ
    public Text messageText;

    // ์ƒํƒœ๋ณ€์ˆ˜
    public Mode mode = Mode.READY;
    // AnchorManager    // ๋กœ์ปฌ ์•ต์ปค๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ํด๋ž˜์Šค
    public ARAnchorManager anchorManager;
    // ArRaycastManager
    public ARRaycastManager raycastManager;

    // ์ฆ๊ฐ•์‹œํ‚ฌ ๊ฐ์ฒด ํ”„๋ฆฌํŒน
    public GameObject anchorPrefab;
    // ์ €์žฅ ๊ฐ์ฒด ๋ณ€์ˆ˜ (์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•œ ์šฉ๋„)
    private GameObject anchorGameObject;

    // ๋กœ์ปฌ์•ต์ปค ์ €์žฅ ๋ณ€์ˆ˜
    private ARAnchor localAnchor;
    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ๋ณ€์ˆ˜
    private ARCloudAnchor cloudAnchor;


    // Raycast Hit
    private List<ARRaycastHit> hits = new List<ARRaycastHit>();

    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ID ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ํ‚ค ๊ฐ’ (PlayerPregs.SetString("ํ‚ค", ๊ฐ’));
    private const string cloudAnchorKey = "CLOUD_ANCHOR_ID";
    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ID
    private string strCloudAnchorId;


    void Start()
    {
        // ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
        hostButton.onClick.AddListener(() => OnHostClick());
        resolveButton.onClick.AddListener(() => OnResolveClick());
        resetButton.onClick.AddListener(() => OnResetClick());

        strCloudAnchorId = PlayerPrefs.GetString(cloudAnchorKey, "");
    }

    void Update()
    {
        if (mode == Mode.HOST)
        {
            Hosting();
            HostProcessing();
        }

        if (mode == Mode.HOST_PENDING)
        {
            HostPending();
        }

    }

    void Hosting()
    {
        if (Input.touchCount < 1) return;

        Touch touch = Input.GetTouch(0);
        if (touch.phase != TouchPhase.Began) return;


        // ๋กœ์ปฌ ์•ต์ปค๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธ
        if (localAnchor == null)
        {
            // Raycast ๋ฐœ์‚ฌ
            if (raycastManager.Raycast(touch.position, hits, TrackableType.PlaneWithinPolygon))
            {
                // ๋กœ์ปฌ ์•ต์ปค๋ฅผ ์ƒ์„ฑ
                localAnchor = anchorManager.AddAnchor(hits[0].pose);
                // ๋กœ์ปฌ ์•ต์ปค ์œ„์น˜์— ์‚ฌ์Šด ์ฆ๊ฐ•์‹œํ‚ค๊ณ  ๋ณ€์ˆ˜์— ์ €์žฅ
                anchorGameObject = Instantiate(anchorPrefab, localAnchor.transform);
            }
        }
    }

    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ๋“ฑ๋ก
    void HostProcessing()
    {
        if (localAnchor == null) return;

        // ํ”ผ์ณํฌ์ธํŠธ์˜ ๊ฐฏ์ˆ˜ ๋ฐ ํ€„๋ฆฌํ‹ฐ ์ธก์ •
        FeatureMapQuality quality = anchorManager.EstimateFeatureMapQualityForHosting(GetCameraPose());

        string mappingText = string.Format("๋งตํ•‘ ํ’ˆ์งˆ = {0}", quality);

        // ๋งตํ•‘ ํ€„๋ฆฌํ‹ฐ๊ฐ€ 1 ์ด์ƒ์ผ ๋•Œ ํ˜ธ์ŠคํŒ… ์š”์ฒญ
        if (quality == FeatureMapQuality.Sufficient || quality == FeatureMapQuality.Good)
        {
            // 1์ผ์งœ๋ฆฌ ์•ต์ปคํฌ์ธํŠธ
            cloudAnchor = anchorManager.HostCloudAnchor(localAnchor, 1);

            if (cloudAnchor == null)
            {
                mappingText = "ํด๋ผ์šฐ๋“œ ์•ต์ปค ์ƒ์„ฑ ์‹คํŒจ";
            }
            else
            {
                // ์—ฌ๊ธฐ์„œ ํด๋ผ์šฐ๋“œ ์•ต์ปค ID ์ฐ์–ด๋„ ์•ˆ๋‚˜์˜ด
                // ์„œ๋ฒ„์—์„œ ์ž‘์—…ํ•˜๋Š” ์‹œ๊ฐ„์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—
                mappingText = "ํด๋ผ์šฐ๋“œ ์•ต์ปค ์ƒ์„ฑ ์‹œ์ž‘";
                mode = Mode.HOST_PENDING;
            }
        }

        messageText.text = mappingText;

    }

    void HostPending()
    {
        string mappingText = "";
        if (cloudAnchor.cloudAnchorState == CloudAnchorState.Success)
        {
            mappingText = $"ํด๋ผ์šฐ๋“œ ์•ต์ปค ์ƒ์„ฑ ์„ฑ๊ณต, CloudAnchor ID = {cloudAnchor.cloudAnchorId}";
            // ์•ต์ปคID ์ €์žฅ
            strCloudAnchorId = cloudAnchor.cloudAnchorId;

            // ํด๋ผ์šฐ๋“œ ์•ต์ปค ID๋ฅผ ๊ณต์œ ํ•˜๋Š” ๋กœ์ง
            // ํฌํ†ค ๋„คํŠธ์›Œํฌ : RPC ํ˜ธ์ถœ
            // ํŒŒ์ด์–ด๋ฒ ์ด์Šค : ๋ฐ์ดํ„ฐ ์ €์žฅ
            PlayerPrefs.SetString(cloudAnchorKey, strCloudAnchorId);

            // ์ดˆ๊ธฐํ™”
            cloudAnchor = null;
            // ๊ธฐ์กด์— ์ฆ๊ฐ•๋œ ๊ฐ์ฒด๋ฅผ ์‚ญ์ œ
            Destroy(anchorGameObject);

            mode = Mode.READY;
        }
        else
        {
            mappingText = $"ํด๋ผ์šฐ๋“œ ์•ต์ปค ์ƒ์„ฑ ์ง„ํ–‰์ค‘...{cloudAnchor.cloudAnchorState}";
        }

        messageText.text = mappingText;
    }

    // MainCamera ํƒœ๊ทธ๋กœ ์ง€์ •๋œ ์นด๋ฉ”๋ผ์˜ ์œ„์น˜์™€ ๊ฐ๋„๋ฅผ Pose ๋ฐ์ดํ„ฐ ํƒ€์ž…์œผ๋กœ ๋ฐ˜ํ™˜
    public Pose GetCameraPose()
    {
        return new Pose(Camera.main.transform.position, Camera.main.transform.rotation);
    }


    private void OnHostClick()
    {
        mode = Mode.HOST;
    }

    private void OnResolveClick()
    {
        mode = Mode.RESOLVE;
    }

    private void OnResetClick()
    {
    }

}

 

 

 

- Build & Run

- Host ๋ฒ„ํŠผ ํด๋ฆญ > ์‚ฌ์Šด ์ƒ์„ฑ

- ํด๋ผ์šฐ๋“œ ์•ต์ปค ์ƒ์„ฑ ์„ฑ๊ณตํ•˜๋ฉด ์‚ฌ์Šด ์‚ญ์ œ๋จ

 

 

 

- ์š”์ฒญ ์ˆ˜ ์˜ฌ๋ผ๊ฐ„ ๊ฒƒ ํ™•์ธ

 

 

 

๐Ÿ”ถ Resolve

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

// Google ARCore Extensions
using Google.XR.ARCoreExtensions;
using System;

public class CloudAnchorManager : MonoBehaviour
{
    // ์ƒํƒœ ๋ณ€์ˆ˜
    public enum Mode { READY, HOST, HOST_PENDING, RESOLVE, RESOLVE_PENDING };

    // ๋ฒ„ํŠผ
    public Button hostButton;       // ํด๋ผ์šฐ๋“œ ์•ต์ปค ๋“ฑ๋ก
    public Button resolveButton;    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ์กฐํšŒ
    public Button resetButton;      // ๋ฆฌ์…‹

    // ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ ํ…์ŠคํŠธ
    public Text messageText;

    // ์ƒํƒœ๋ณ€์ˆ˜
    public Mode mode = Mode.READY;
    // AnchorManager    // ๋กœ์ปฌ ์•ต์ปค๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•œ ํด๋ž˜์Šค
    public ARAnchorManager anchorManager;
    // ArRaycastManager
    public ARRaycastManager raycastManager;

    // ์ฆ๊ฐ•์‹œํ‚ฌ ๊ฐ์ฒด ํ”„๋ฆฌํŒน
    public GameObject anchorPrefab;
    // ์ €์žฅ ๊ฐ์ฒด ๋ณ€์ˆ˜ (์‚ญ์ œํ•˜๊ธฐ ์œ„ํ•œ ์šฉ๋„)
    private GameObject anchorGameObject;

    // ๋กœ์ปฌ์•ต์ปค ์ €์žฅ ๋ณ€์ˆ˜
    private ARAnchor localAnchor;
    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ๋ณ€์ˆ˜
    private ARCloudAnchor cloudAnchor;


    // Raycast Hit
    private List<ARRaycastHit> hits = new List<ARRaycastHit>();

    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ID ์ €์žฅํ•˜๊ธฐ ์œ„ํ•œ ํ‚ค ๊ฐ’ (PlayerPregs.SetString("ํ‚ค", ๊ฐ’));
    private const string cloudAnchorKey = "CLOUD_ANCHOR_ID";
    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ID
    private string strCloudAnchorId;


    void Start()
    {
        // ๋ฒ„ํŠผ ์ด๋ฒคํŠธ ์—ฐ๊ฒฐ
        hostButton.onClick.AddListener(() => OnHostClick());
        resolveButton.onClick.AddListener(() => OnResolveClick());
        resetButton.onClick.AddListener(() => OnResetClick());

        strCloudAnchorId = PlayerPrefs.GetString(cloudAnchorKey, "");
    }

    void Update()
    {
        if (mode == Mode.HOST)
        {
            Hosting();
            HostProcessing();
        }
        if (mode == Mode.HOST_PENDING)
        {
            HostPending();
        }
        if (mode == Mode.RESOLVE)
        {
            Resolving();
        }
        if (mode == Mode.RESOLVE_PENDING)
        {
            ResolvePending();
        }

    }

    void Hosting()
    {
        if (Input.touchCount < 1) return;

        Touch touch = Input.GetTouch(0);
        if (touch.phase != TouchPhase.Began) return;


        // ๋กœ์ปฌ ์•ต์ปค๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ํ™•์ธ
        if (localAnchor == null)
        {
            // Raycast ๋ฐœ์‚ฌ
            if (raycastManager.Raycast(touch.position, hits, TrackableType.PlaneWithinPolygon))
            {
                // ๋กœ์ปฌ ์•ต์ปค๋ฅผ ์ƒ์„ฑ
                localAnchor = anchorManager.AddAnchor(hits[0].pose);
                // ๋กœ์ปฌ ์•ต์ปค ์œ„์น˜์— ์‚ฌ์Šด ์ฆ๊ฐ•์‹œํ‚ค๊ณ  ๋ณ€์ˆ˜์— ์ €์žฅ
                anchorGameObject = Instantiate(anchorPrefab, localAnchor.transform);
            }
        }
    }

    // ํด๋ผ์šฐ๋“œ ์•ต์ปค ๋“ฑ๋ก
    void HostProcessing()
    {
        if (localAnchor == null) return;

        // ํ”ผ์ณํฌ์ธํŠธ์˜ ๊ฐฏ์ˆ˜ ๋ฐ ํ€„๋ฆฌํ‹ฐ ์ธก์ •
        FeatureMapQuality quality = anchorManager.EstimateFeatureMapQualityForHosting(GetCameraPose());

        string mappingText = string.Format("๋งตํ•‘ ํ’ˆ์งˆ = {0}", quality);

        // ๋งตํ•‘ ํ€„๋ฆฌํ‹ฐ๊ฐ€ 1 ์ด์ƒ์ผ ๋•Œ ํ˜ธ์ŠคํŒ… ์š”์ฒญ
        if (quality == FeatureMapQuality.Sufficient || quality == FeatureMapQuality.Good)
        {
            // 1์ผ์งœ๋ฆฌ ์•ต์ปคํฌ์ธํŠธ
            cloudAnchor = anchorManager.HostCloudAnchor(localAnchor, 1);

            if (cloudAnchor == null)
            {
                mappingText = "ํด๋ผ์šฐ๋“œ ์•ต์ปค ์ƒ์„ฑ ์‹คํŒจ";
            }
            else
            {
                // ์—ฌ๊ธฐ์„œ ํด๋ผ์šฐ๋“œ ์•ต์ปค ID ์ฐ์–ด๋„ ์•ˆ๋‚˜์˜ด
                // ์„œ๋ฒ„์—์„œ ์ž‘์—…ํ•˜๋Š” ์‹œ๊ฐ„์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—
                mappingText = "ํด๋ผ์šฐ๋“œ ์•ต์ปค ์ƒ์„ฑ ์‹œ์ž‘";
                mode = Mode.HOST_PENDING;
            }
        }

        messageText.text = mappingText;

    }

    void HostPending()
    {
        string mappingText = "";
        if (cloudAnchor.cloudAnchorState == CloudAnchorState.Success)
        {
            mappingText = $"ํด๋ผ์šฐ๋“œ ์•ต์ปค ์ƒ์„ฑ ์„ฑ๊ณต, CloudAnchor ID = {cloudAnchor.cloudAnchorId}";
            // ์•ต์ปคID ์ €์žฅ
            strCloudAnchorId = cloudAnchor.cloudAnchorId;

            // ํด๋ผ์šฐ๋“œ ์•ต์ปค ID๋ฅผ ๊ณต์œ ํ•˜๋Š” ๋กœ์ง
            // ํฌํ†ค ๋„คํŠธ์›Œํฌ : RPC ํ˜ธ์ถœ
            // ํŒŒ์ด์–ด๋ฒ ์ด์Šค : ๋ฐ์ดํ„ฐ ์ €์žฅ
            PlayerPrefs.SetString(cloudAnchorKey, strCloudAnchorId);

            // ์ดˆ๊ธฐํ™”
            cloudAnchor = null;
            // ๊ธฐ์กด์— ์ฆ๊ฐ•๋œ ๊ฐ์ฒด๋ฅผ ์‚ญ์ œ
            Destroy(anchorGameObject);

            mode = Mode.READY;
        }
        else
        {
            mappingText = $"ํด๋ผ์šฐ๋“œ ์•ต์ปค ์ƒ์„ฑ ์ง„ํ–‰์ค‘...{cloudAnchor.cloudAnchorState}";
        }

        messageText.text = mappingText;
    }

    void Resolving()
    {
        if (PlayerPrefs.HasKey(cloudAnchorKey) == false) return;
        messageText.text = "";
        // ํด๋ผ์šฐ๋“œ ์•ต์ปค ID ๋ฐ›์•„์˜ด. (ํฌํ†ค, ํŒŒ์ด์–ด๋ฒ ์ด์Šค)
        strCloudAnchorId = PlayerPrefs.GetString(cloudAnchorKey);

        // ํด๋ผ์šฐ๋“œ ์•ต์ปค ID๋กœ CloudAnchor ๋กœ๋“œ
        cloudAnchor = anchorManager.ResolveCloudAnchorId(strCloudAnchorId);

        if (cloudAnchor == null)
        {
            messageText.text = "ํด๋ผ์šฐ๋“œ ์•ต์ปค ๋ฆฌ์กธ๋ธŒ ์‹คํŒจ";
        }
        else
        {
            messageText.text = $"ํด๋ผ์šฐ๋“œ ์•ต์ปค ๋ฆฌ์กธ๋ธŒ ์„ฑ๊ณต : {cloudAnchor.cloudAnchorId}";
            // id๋งŒ ๊ฐ€์ ธ์˜จ ๊ฒƒ
            // ํ”ผ์ณํฌ์ธํŠธ๋ฅผ ํ›„์†์œผ๋กœ ๊ฐ€์ ธ์˜ด
            mode = Mode.RESOLVE_PENDING;
        }
    }

    void ResolvePending()
    {
        if (cloudAnchor.cloudAnchorState == CloudAnchorState.Success)
        {
            messageText.text = "๋ฆฌ์กธ๋ธŒ ์„ฑ๊ณต";

            // ๊ฐ์ฒด ์ฆ๊ฐ•
            anchorGameObject = Instantiate(anchorPrefab, cloudAnchor.transform);
            mode = Mode.READY;
        }
        else
        {
            messageText.text = $"๋ฆฌ์กธ๋น™ ์ง„ํ–‰ ์ค‘...{cloudAnchor.cloudAnchorState}";
        }
    }


    // MainCamera ํƒœ๊ทธ๋กœ ์ง€์ •๋œ ์นด๋ฉ”๋ผ์˜ ์œ„์น˜์™€ ๊ฐ๋„๋ฅผ Pose ๋ฐ์ดํ„ฐ ํƒ€์ž…์œผ๋กœ ๋ฐ˜ํ™˜
    public Pose GetCameraPose()
    {
        return new Pose(Camera.main.transform.position, Camera.main.transform.rotation);
    }


    private void OnHostClick()
    {
        mode = Mode.HOST;
    }

    private void OnResolveClick()
    {
        mode = Mode.RESOLVE;
    }

    private void OnResetClick()
    {
        if (anchorGameObject != null)
        {
            Destroy(anchorGameObject);
        }
        cloudAnchor = null;
        localAnchor = null;
        messageText.text = "์ค€๋น„์™„๋ฃŒ";
        mode = Mode.READY;
    }
}

-

 

 

 

- Build & Run

- ํด๋ผ์šฐ๋“œ ์•ต์ปค ์ƒ์„ฑ

- Resolve ๋ฒ„ํŠผ ํด๋ฆญ : ํด๋ผ์šฐ๋“œ์—์„œ ์•ต์ปค๋ฅผ ๊ฐ€์ ธ์™€์„œ ์‚ฌ์Šด์„ ์ฆ๊ฐ•์‹œํ‚ด

- Reset ๋ฒ„ํŠผ : ๋‹ค์‹œ hostํ•  ์ˆ˜ ์žˆ๋Š” ์ƒํƒœ๋กœ reset

'Unity > AR' ์นดํ…Œ๊ณ ๋ฆฌ์˜ ๋‹ค๋ฅธ ๊ธ€

11. AR Foundation - Cloud Anchor (2) Local Anchor  (0) 2021.09.21
10. AR Foundation - Cloud Anchor (1) Setting  (0) 2021.09.20
09. AR Foundation - Occlusion culling  (0) 2021.09.18
08. AR Foundation - ์–ผ๊ตด ์ธ์‹  (0) 2021.09.17
07. AR Foundation - ์„ค์น˜  (2) 2021.09.16