HoloLens开发手记 - Unity之Persistence 场景保持

Changwei | 6/15/2016 7:32:00 PM


Persistence 场景保持是HoloLens全息体验的一个关键特性,当用户离开原场景中时,原场景中全息对象会保持在特定位置,当用户回到原场景时,能够准确还原原场景的全息内容。WorldAnchorStore类是实现此特性的关键API,这保证了用户能够将任何全息对象贴到任何他们想要放置的位置。

 

How to persist holograms across sessions 如何在整个会话中保持全息对象


 

WorldAnchorStore能够允许你保持场景中空间锚的位置,为了能够真正保持全息对象,你需要单独使用特定的空间锚来追踪每一个对象。通常创建一个根GameObject并附上空间锚,同时对它的子GameObject也附上具有相对位置偏移的空间锚组件。

为了从先前场景载入全息对象:

  1. 获取WorldAnchorStore对象
  2. 载入空间锚关联的应用数据,从中获取空间锚ID
  3. 通过ID获取空间锚对象

 

下个场景之前,为了保存全息对象信息:

  1. 获取WorldAnchorStore对象
  2. 指定ID来保持对应空间锚对象
  3. 保持与空间锚关联的应用数据

 

Getting the WorldAnchorStore 获取WorldAnchorStore对象


 

命名空间: UnityEngine.WSA.VR.Persistence

类型: WorldAnchorStore

 

为了能够在后续使用WorldAnchorStore,我们需要先通过异步操作打开此对象,如下:

 

WorldAnchorStore.GetAsync(StoreLoaded);

private void StoreLoaded(WorldAnchorStore store)
{
       this.store = store;
}

 

现在就可以使用WorldAnchorStore对象来保存场景信息了。

 

Saving a WorldAnchor 保存一个空间锚


 

注意:同一空间锚不能多次保存。每个空间锚只应该保存一次,如果需要更新空间锚信息,则需要先删除旧的空间锚信息,然后再保存新的空间锚信息。

 

private void SaveGame()
{
       // 保存空间锚对应的全息对象数据
       if (!this.savedRoot) // 仅仅保存根对象一次
       {
              this.savedRoot = this.store.Save("rootGameObject", anchor);
              Assert(this.savedRoot);
       }
}

 

Loading a WorldAnchor 载入一个空间锚


 

载入空间锚数据很简单,如下:

 

private void LoadGame()
{
       // Save data about holograms positioned by this world anchor
       this.savedRoot = this.store.Load("rootGameObject", rootGameObject);
       if (!this.savedRoot)
       {
              // 我们没有成功保存空间锚和全息对象数据,需要重新替换我们的对象
       }
}

 

Enumerating Existing Anchors 枚举已有的空间锚


 

我们可以通过枚举已保存的空间锚信息来查找之前保存的空间锚:

 

string[] ids = this.store.GetAllIds();
for (int index = 0; index < ids.Length; index++)
{
        Debug.Log(ids[index]);
}

 

示例代码


using HoloToolkit.Unity;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.VR.WSA;
using UnityEngine.VR.WSA.Persistence;

public class SceneManager : Singleton<SceneManager>
{

    private WorldAnchorStore anchorStore;
    private Dictionary<string, GameObject> SceneObjects = new Dictionary<string, GameObject>();
    
    void Start()
    {

        WorldAnchorStore.GetAsync(WorldAnchorStoreLoaded);
    }

    private void WorldAnchorStoreLoaded(WorldAnchorStore store)
    {
        this.anchorStore = store;
    }

    //保存场景对象信息
    public bool SaveSceneObject(string objectId, WorldAnchor anchor)
    {
        var result= this.anchorStore.Save(objectId, anchor);
        if (result)
        {
            SceneObjects.Add(objectId, anchor.gameObject);
        }
        return result;
    }

    //载入场景对象信息
    public WorldAnchor LoadSceneObject(string objectId)
    {
        if (SceneObjects.ContainsKey(objectId))
        {
            var target = SceneObjects[objectId];
            return this.anchorStore.Load(objectId, target);
        }
        return null;
       
    }

    //还原场景全部内容
    public void RestoreAllSceneObjects()
    {
        foreach(var key in SceneObjects.Keys)
        {
            var target = SceneObjects[key];
            this.anchorStore.Load(key, target);
        }
    }


}