EasyAR4.0使用說明(Unity3D)(七)----稀疏空間地圖

稀疏空間地圖的對應用環境的要求和平面圖像識別可以比照理解,周圍環境需要足夠豐富,不能有大片的單色區域,透明區域。此外,光照,角度都會對建立地圖和定位產生影響。

官方給出了建立地圖和定位地圖的建議。https://help.easyar.cn/EasyAR%20Sense/v4/Guides/EasyAR-Sparse-Spatial-Map.html

總體說明

稀疏空間地圖的基礎是運動跟蹤,所有在場景種首先要有運動跟蹤的全套遊戲對象包括設置。然後主要的是 SparseSpatialMapWorker 和 SparseSpatialMap 這兩個遊戲對象。

總體說明

SparseSpatialMapWorker 遊戲對象相關

SparseSpatialMapWorker遊戲對象相關

  • Locailzation Mode 屬性在建立地圖的時候通常選“UntilSuccess”,在定位的時候,通常選“KeepUpdate”。
  • Use Global Service Config 選項可以設置是否使用全局定義的稀疏空間地圖信息。
  • BuilderMapController.Host(…)方法是保存地圖的方法,需要輸入的參數是地圖的名稱和地圖的縮略圖,縮略圖可以輸入“null”。
  • BuilderMapController.MapHost 事件用於返回地圖保存情況的事件。事件有 3 個參數,是地圖保存成功後的名稱,ID,是否保存成功的狀態,還有錯誤信息。
  • Localizer.startLocalization()和 Localizer.stopLocalization()方法是用來啓動和停止本地稀疏空間定位的方法。如果 SparseSpatialMap 遊戲對象設置了地圖的 ID 和名稱的時候,默認會自動啓動地圖定位。

SparseSpatialMap 遊戲對象相關

SparseSpatialMap 遊戲對象是稀疏空間地圖在 Unity 中的載體,每個稀疏空間地圖在定位的時候對應一個 SparseSpatialMap 遊戲對象,同一個場景可以同時有多個稀疏空間地圖。希望在某個稀疏空間地圖中放置的虛擬物體,將其對應的遊戲對象放置到對應的 SparseSpatialMap 遊戲對象下成爲其子游戲對象即可。

SparseSpatialMap遊戲對象相關

  • Source Type 屬性用於設置稀疏空間地圖的作用,即是用於建立地圖“Map Builder”還是用於定位“Map Manager”。
  • Map Worker 屬性必須關聯對應的 SparseSpatialMapWorker 遊戲對象。通常不需要設置。
  • Show Point Cloud 選項可以設置是否點雲的效果。在建圖的時候,顯示點雲的效果能幫助使用者更好的建立稀疏空間地圖。
  • MapLoad 事件是指定的稀疏空間地圖從服務器端下載到本地觸發的事件。
  • MapLocalized、MapStopLocalize 事件是地圖實現定位和停止定位的事件。MapLocalized 可以被觸發多次,或者理解爲可以不斷修正位置。

建立地圖

  • 設置場景中的 Main Camera 的 Clear Flags 屬性爲 Solid Color。
  • 將 EasyAR/Prefabs/Composites 目錄下的 EasyAR_SparseSpatialMapWorker 預製件拖到場景中。

建立地圖

  • 將 EasyAR/Prefabs/Primitives 目錄下的 WorldRoot 預製件拖到場景中。
  • 選中 EasyAR_ SparseSpatialMapWorker 遊戲對象,將 WorldRoot 遊戲對象拖到 World Root Controller 屬性中爲其賦值。

建立地圖

  • 將 EasyAR/Prefabs/Primitives 目錄下的 SparseSpatialMap 預製件拖到場景中。

建立地圖

在 SparseSpatialMap 遊戲對象下再添加用於分辨方向的模型,用形狀來和 WorldRoot 遊戲對象下的進行區分。

建立地圖

添加界面和腳本。界面中有保存按鈕和顯示反饋信息的文本框。

建立地圖

腳本說明:
保存完地圖需要將獲取的ID和Name保存下來。官方沒有提供稀疏空間地圖訪問的API。

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

public class BuildMapController : MonoBehaviour
{
    //稀疏空間地圖相關對象
    private ARSession session;
    private SparseSpatialMapWorkerFrameFilter mapWorker;
    private SparseSpatialMapController map;
    /// <summary>
    /// 保存按鈕
    /// </summary>
    private Button btnSave;
    /// <summary>
    /// 顯示文本
    /// </summary>
    private Text text;

    void Start()
    {
        //稀疏空間地圖初始
        session = FindObjectOfType<ARSession>();
        mapWorker = FindObjectOfType<SparseSpatialMapWorkerFrameFilter>();
        map = FindObjectOfType<SparseSpatialMapController>();
        //註冊追蹤狀態變化事件
        session.WorldRootController.TrackingStatusChanged += OnTrackingStatusChanged;
        //初始化保存按鈕
        btnSave = GameObject.Find("/Canvas/Button").GetComponent<Button>();
        btnSave.onClick.AddListener(Save);
        btnSave.interactable = false;
        if (session.WorldRootController.TrackingStatus == MotionTrackingStatus.Tracking)
        {
            btnSave.interactable = true;
        }
        else
        {
            btnSave.interactable = false;
        }
        //初始化顯示文本
        text = GameObject.Find("/Canvas/Panel/Text").GetComponent<Text>();
    }

    /// <summary>
    /// 保存地圖方法
    /// </summary>
    private void Save()
    {
        btnSave.interactable = false;
        //註冊地圖保存結果反饋事件
        mapWorker.BuilderMapController.MapHost += SaveMapHostBack;
        //保存地圖
        try
        {
            //保存地圖
            mapWorker.BuilderMapController.Host("LearnMap" + DateTime.Now.ToString("yyyyMMddHHmm"), null);
            text.text = "開始保存地圖,請稍等。";
        }
        catch (Exception ex)
        {
            btnSave.interactable = true;
            text.text = "保存出錯:" + ex.Message;
        }
    }

    /// <summary>
    /// 保存地圖反饋
    /// </summary>
    /// <param name="mapInfo">地圖信息</param>
    /// <param name="isSuccess">成功標識</param>
    /// <param name="error">錯誤信息</param>
    private void SaveMapHostBack(SparseSpatialMapController.SparseSpatialMapInfo mapInfo, bool isSuccess, string error)
    {
        if (isSuccess)
        {
            PlayerPrefs.SetString("MapID", mapInfo.ID);
            PlayerPrefs.SetString("MapName", mapInfo.Name);
            text.text = "地圖保存成功。\r\nMapID:" + mapInfo.ID + "\r\nMapName:" + mapInfo.Name;
        }
        else
        {
            btnSave.interactable = true;
            text.text = "地圖保存出錯:" + error;
        }
    }

    /// <summary>
    /// 攝像機狀態變化
    /// </summary>
    /// <param name="status">狀態</param>
    private void OnTrackingStatusChanged(MotionTrackingStatus status)
    {
        if (status == MotionTrackingStatus.Tracking)
        {
            btnSave.interactable = true;
            text.text = "進入跟蹤狀態。";
        }
        else
        {
            btnSave.interactable = false;
            text.text = "退出跟蹤狀態。" + status.ToString();
        }
    }
}

打包以後在設備上運行。進入以後,會顯示點雲效果。稀疏空間地圖SparseSpatialMap遊戲對象和運動跟蹤WorldRoot遊戲對象兩者的原點方向都是一致的。當掃描完周圍空間以後,點擊保存按鈕,就可以將地圖保存到服務器。在提示文本中會顯示地圖的ID和名稱。

建立地圖

本地化地圖

  • 將建立地圖場景另存爲作爲本地化的場景。
  • 選中SparseSpatialMapWorker遊戲對象,修改Localization Mode屬性爲Keep Update。

本地化地圖

  • 選中SparseSpatialMap遊戲對象,修改Source Type屬性爲Map Manager。

本地化地圖

修改界面,設置界面裏有2個輸入框,分別用於輸入地圖ID和地圖名稱,有一個文本框顯示提示內容,2個按鈕,用於本地化地圖和停止定位。

本地化地圖

替換腳本。

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


public class LocalizeMapController : MonoBehaviour
{
    //稀疏空間地圖相關對象
    private ARSession session;
    private SparseSpatialMapWorkerFrameFilter mapWorker;
    private SparseSpatialMapController map;
    /// <summary>
    ///地圖 ID輸入框
    /// </summary>
    public InputField inputID;
    /// <summary>
    /// 地圖名稱輸入框
    /// </summary>
    public InputField inputName;
    /// <summary>
    /// 文本顯示
    /// </summary>
    public Text text;


    void Start()
    {
        //稀疏空間地圖初始
        session = FindObjectOfType<ARSession>();
        mapWorker = FindObjectOfType<SparseSpatialMapWorkerFrameFilter>();
        map = FindObjectOfType<SparseSpatialMapController>();

        //如果之前有建立過地圖且文本框沒有預設值
        if (inputID.text.Length <= 0)
        {
            inputID.text = PlayerPrefs.GetString("MapID", "");
            inputName.text = PlayerPrefs.GetString("MapName", "");
        }

        map.MapLoad += MapLoadBack; //註冊地圖加載事件
        map.MapLocalized += LocalizedMap;   //註冊定位成功事件
        map.MapStopLocalize += StopLocalizeMap; //註冊停止定位事件

        StartLocalization();
    }

    /// <summary>
    /// 地圖加載反饋
    /// </summary>
    /// <param name="mapInfo">地圖信息</param>
    /// <param name="isSuccess">是否成功</param>
    /// <param name="error">錯誤信息</param>
    private void MapLoadBack(SparseSpatialMapController.SparseSpatialMapInfo mapInfo, bool isSuccess, string error)
    {
        if (isSuccess)
        {
            text.text = "地圖" + mapInfo.Name + "加載成功。";
        }
        else
        {
            text.text = "地圖加載失敗。" + error;
        }
    }
    /// <summary>
    /// 地圖定位成功
    /// </summary>
    private void LocalizedMap()
    {
        text.text = "稀疏空間地圖定位成功。" + DateTime.Now.ToShortTimeString();
    }
    /// <summary>
    /// 停止地圖定位
    /// </summary>
    private void StopLocalizeMap()
    {
        text.text = "稀疏空間地圖停止定位。" + DateTime.Now.ToShortTimeString();
    }
    /// <summary>
    /// 開始本地化地圖
    /// </summary>
    public void StartLocalization()
    {
        //文本框內容不爲空
        if (inputID.text.Length > 0 && inputName.text.Length > 0)
        {
            map.MapManagerSource.ID = inputID.text;
            map.MapManagerSource.Name = inputName.text;
        }
        text.text = "開始本地化地圖。";
        mapWorker.Localizer.startLocalization();
    }
    /// <summary>
    /// 停止本地化
    /// </summary>
    public void StopLocalization()
    {
        mapWorker.Localizer.stopLocalization();
    }

}

打包後在設備上運行,默認獲取之前建立的地圖。期間可以停止定位以後,輸入新的地圖ID和名稱再點擊Start開始本地化地圖。

地圖的原點和方向即SparseSpatialMap遊戲對象的位置方向和本地化時候設備的狀態無關,和建立地圖時候的狀態一致。

本地化地圖

視頻版地址:https://www.bilibili.com/video/BV1Xg4y1z7d8/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章