The requirements of sparse spatial maps for application environment and flat image recognition can be understood by comparison. The surroundings need to be rich enough to not have large monochrome areas and transparent areas.In addition, lighting and angles can have an impact on map building and positioning.
Official recommendations for building and locating maps are given. https://help.easyar.cn/EasyAR%20Sense/v4/Guides/EasyAR-Sparse-Spatial-Map.html
Overall description
Sparse spatial maps are based on motion tracking, which includes settings for all game objects that need motion tracking first in the scene type.Then there are two main game objects, SparseSpatialMap Worker and SpaseSpatialMap.
SparseSpatialMapWorker Game Object Related
- The Locailation Mode property typically selects "UntilSuccess" when building a map and "KeepUpdate" when locating.
- The Use Global Service Config option sets whether sparse spatial map information defined globally is used.
- BuilderMapController.Host(...The method is to save the map. The parameters you need to enter are the name of the map and the thumbnail of the map, which you can enter "null".
- The BuilderMapController.MapHost event is used to return events about how the map was saved.The event has three parameters, the name of the map after it has been saved successfully, the ID, whether it has been saved successfully, and error information.
- Localizer.startLocalization() and Localizer.stopLocalization() methods are used to start and stop local sparse spatial positioning.If the SparseSpatialMap Game Object sets the ID and name of the map, Map Location will start automatically by default.
SparseSpatialMap Game Object Related
SparseSpatialMap game objects are carriers of sparse spatial maps in Unity. Each sparse spatial map corresponds to a SparseSpatialMap game object when it is positioned. There can be multiple sparse spatial maps in the same scene at the same time.If you want a virtual object to be placed in a sparse spatial map, place its corresponding game object under the corresponding SparseSpatialMap game object and become its child game object.
- The Source Type property sets the role of a sparse spatial map, whether it is used to create a Map Builder or to locate a Map Manager.
- The Map Worker property must be associated with the corresponding SparseSpatialMapWorker game object.Normally no settings are required.
- The Show Point Cloud option sets whether point clouds are effective or not.The effect of displaying point clouds during mapping can help users better build sparse spatial maps.
- The MapLoad event is an event triggered when a specified sparse spatial map is downloaded locally from the server.
- MapLocalized, MapStopLocalize events are events that map locates and stops locating.MapLocalized can be triggered multiple times, or it can be understood that the location can be continuously corrected.
Build a map
- Set the Clear Flags property of Main Camera in the scene to Solid Color.
- Drag the EasyAR_SparseSpatialMapWorker prefabricate from the EasyAR/Prefabs/Composites directory into the scene.
- Drag WorldRoot prefabricates from the EasyAR/Prefabs/Primitives directory into the scene.
- Select the EasyAR_ SparseSpatialMapWorker Game Object and drag the WorldRoot Game Object into the World Root Controller property to assign a value to it.
- Drag the SparseSpatialMap prefabricate from the EasyAR/Prefabs/Primitives directory into the scene.
Add another model under the SpaseSpatialMap game object to distinguish direction, using shapes to distinguish it from the WorldRoot game object.
Add interfaces and scripts.There are save buttons and text boxes showing feedback in the interface.
Script description:
To save the map, you need to save the ID and Name you obtained.There are no API s officially available for sparse spatial map access.
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using easyar; using System; public class BuildMapController : MonoBehaviour { //Sparse Spatial Map Related Objects private ARSession session; private SparseSpatialMapWorkerFrameFilter mapWorker; private SparseSpatialMapController map; /// <summary> ///Save button /// </summary> private Button btnSave; /// <summary> ///Display text /// </summary> private Text text; void Start() { //Sparse Spatial Map Initial session = FindObjectOfType<ARSession>(); mapWorker = FindObjectOfType<SparseSpatialMapWorkerFrameFilter>(); map = FindObjectOfType<SparseSpatialMapController>(); //Register Tracking State Change Events session.WorldRootController.TrackingStatusChanged += OnTrackingStatusChanged; //Initialize save button 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; } //Initialize display text text = GameObject.Find("/Canvas/Panel/Text").GetComponent<Text>(); } /// <summary> ///Save Map Method /// </summary> private void Save() { btnSave.interactable = false; //Register Map Save Results Feedback Events mapWorker.BuilderMapController.MapHost += SaveMapHostBack; //Save Map try { //Save Map mapWorker.BuilderMapController.Host("LearnMap" + DateTime.Now.ToString("yyyyMMddHHmm"), null); text.text = "Start saving the map, please wait."; } catch (Exception ex) { btnSave.interactable = true; text.text = "Save error:" + ex.Message; } } /// <summary> ///Save map feedback /// </summary> /// <param name="mapInfo">map information</param> /// <param name="isSuccess">Success ID</param> /// <param name="error">error message</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 = "The map was saved successfully.\r\nMapID: " + mapInfo.ID + "\r\nMapName: " + mapInfo.Name; } else { btnSave.interactable = true; text.text = "Map save error:" + error; } } /// <summary> ///Camera state change /// </summary> /// <param name="status">status</param> private void OnTrackingStatusChanged(MotionTrackingStatus status) { if (status == MotionTrackingStatus.Tracking) { btnSave.interactable = true; text.text = "Enter the tracking state."; } else { btnSave.interactable = false; text.text = "Exit tracking status." + status.ToString(); } } }
Run on the device after packaging.After entering, the point cloud effect will be displayed.The sparse spatial map SparseSpatialMap game object and the motion tracking WorldRoot game object both have the same origin direction.When you have scanned the surrounding space, click the Save button to save the map to the server.The ID and name of the map are displayed in the prompt text.
Localized Maps
- Save the built map scene as a localized scene.
- Select the SparseSpatialMapWorker game object and modify the Localization Mode l property to Keep Update.
- Select the SparseSpatialMap game object and modify the Source Type property to Map Manager.
Modify the interface. There are two input boxes in the setup interface for entering the map ID and name, a text box for displaying hints, and two buttons for localizing and stopping locating maps.
Replace script.
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using System; using easyar; public class LocalizeMapController : MonoBehaviour { //Sparse Spatial Map Related Objects private ARSession session; private SparseSpatialMapWorkerFrameFilter mapWorker; private SparseSpatialMapController map; /// <summary> ///Map ID Input Box /// </summary> public InputField inputID; /// <summary> ///Map Name Input Box /// </summary> public InputField inputName; /// <summary> ///Text Display /// </summary> public Text text; void Start() { //Sparse Spatial Map Initial session = FindObjectOfType<ARSession>(); mapWorker = FindObjectOfType<SparseSpatialMapWorkerFrameFilter>(); map = FindObjectOfType<SparseSpatialMapController>(); //If a map has been created before and the text box has no default values if (inputID.text.Length <= 0) { inputID.text = PlayerPrefs.GetString("MapID", ""); inputName.text = PlayerPrefs.GetString("MapName", ""); } map.MapLoad += MapLoadBack; //Register Map Load Events map.MapLocalized += LocalizedMap; //Registration Location Success Event map.MapStopLocalize += StopLocalizeMap; //Register Stop Location Event StartLocalization(); } /// <summary> ///Map Load Feedback /// </summary> /// <param name="mapInfo">map information</param> /// <param name="isSuccess">Success</param> /// <param name="error">error message</param> private void MapLoadBack(SparseSpatialMapController.SparseSpatialMapInfo mapInfo, bool isSuccess, string error) { if (isSuccess) { text.text = "Map" + mapInfo.Name + "Loading succeeded."; } else { text.text = "The map failed to load." + error; } } /// <summary> ///Map positioning succeeded /// </summary> private void LocalizedMap() { text.text = "Sparse spatial maps were positioned successfully." + DateTime.Now.ToShortTimeString(); } /// <summary> ///Stop Map Location /// </summary> private void StopLocalizeMap() { text.text = "Sparse spatial maps stop locating." + DateTime.Now.ToShortTimeString(); } /// <summary> ///Start localizing maps /// </summary> public void StartLocalization() { //Text box content is not empty if (inputID.text.Length > 0 && inputName.text.Length > 0) { map.MapManagerSource.ID = inputID.text; map.MapManagerSource.Name = inputName.text; } text.text = "Start localizing the map."; mapWorker.Localizer.startLocalization(); } /// <summary> ///Stop localization /// </summary> public void StopLocalization() { mapWorker.Localizer.stopLocalization(); } }
Run on the device after packaging and get the map you created by default.After you can stop locating, enter a new map ID and name and click Start to start localizing the map.
The origin and direction of the map, that is, the position and direction of the SparseSpatialMap object, are independent of the state of the device when localized and consistent with the state when the map was created.
Video version address: https://www.bilibili.com/video/BV1Xg4y1z7d8/