HoloLens开发手记 - Unity之场景共享 Shared holographic experiences in Unity

Changwei | 7/5/2016 5:00:00 PM


佩戴HoloLens的多个用户可以使用场景共享特性来获取集合视野,并可以与固定在空间中某个位置的同一全息对象进行交互操作。这一切是通过空间锚共享(Anchor Sharing)来实现的。

为了使用共享服务,在AppxManifest文件中必须要启用SpatialPerception能力。

 

Anchor Sharing 空间锚共享


 

在HoloLens扫描空间环境后,用户可以通过手动或者编程来选择建立一些空间锚。空间锚对象的信息的可以被序列化并传递给其他HoloLens设备,每一个设备都可以反序列化这些信息,并可以在空间中定位到此空间锚的位置。为了确保空间锚分享能起作用,每个设备都需要扫描周边足够的空间,使得空间锚代表的点能在空间中被正确识别。

 

Setting the SpatialPreception capability 启用能力

 

上一篇空间映射的文章里提过,这里我就不重复叙述了,想起请看:http://www.cnblogs.com/mantgh/p/5626796.html

 

Setup 初始化

下面的示例代码会在开始共享空间锚之前进行一些初始化操作:

 

public GameObject rootGameObject;
private UnityEngine.VR.WSA.WorldAnchor gameRootAnchor;

void Start ()
{
    gameRootAnchor = rootGameObject.GetComponent<UnityEngine.VR.WSA.WorldAnchor>();

    if (gameRootAnchor == null)
    {
        gameRootAnchor = rootGameObject.AddComponent<UnityEngine.VR.WSA.WorldAnchor>();
    }
}

 

Exporting 导出

 

导出分享一个空间锚的操作步骤如下:

  1. 创建一个 WorldAnchorTransferBatch 对象
  2. 添加空间锚对象用以传输
  3. 开始导出数据
  4. 当数据可用时处理 OnExportDataAvailable事件方法
  5. 处理导出完成事件 OnExportComplete

 

WorldAnchorTransferBatch对象会将空间锚数据导出为bytes数据:

private void ExportGameRootAnchor()
{
    WorldAnchorTransferBatch transferBatch = new WorldAnchorTransferBatch();
    transferBatch.AddWorldAnchor("gameRoot", this.gameRootAnchor);
    WorldAnchorTransferBatch.ExportAsync(transferBatch, OnExportDataAvailable, OnExportComplete);
}

 

当导出的数据可用时,使用任意方法将数据发往另一台设备:

 

private void OnExportDataAvailable(byte[] data)
{
    TransferDataToClient(data);
}

 

一旦数据导出完成,如果我们传输或者序列化数据失败,需要告诉其他设备放弃此段错误的数据。如果序列化成功,需要告诉其他设备可以使用导入使用此数据:

 

private void OnExportComplete(SerializationCompletionReason completionReason)
{
    if (completionReason != SerializationCompletionReason.Succeeded)
    {
        SendExportFailedToClient();
    }
    else
    {
        SendExportSucceededToClient();
    }
}

 

Importing 导入数据

 

设备在接收到其他来源的数据后我们同样可以使用WorldAnchorTransferBatch对象将我们的全息对象放置到数据代表的物理位置上。注意:导入有时会失败,需要重试:

 

//这个数组需要通过网络来从其他来源更新数据 
 network from TransferDataToClient
private byte[] importedData;
private int retryCount = 3;

private void ImportRootGameObject()
{
    WorldAnchorTransferBatch.ImportAsync(importedData, OnImportComplete);
}

private void OnImportComplete(SerializationCompletionReason completionReason, WorldAnchorTransferBatch deserializedTransferBatch)
{
    if (completionReason != SerializationCompletionReason.Succeeded)
    {
        Debug.Log("Failed to import: " + completionReason.ToString());
        if (retryCount > 0)
        {
            retryCount--;
            WorldAnchorTransferBatch.ImportAsync(importedData, OnImportComplete);
        }
        return;
    }

    this.gameRootAnchor = deserializedTransferBatch.LockObject("gameRoot", this.rootGameObject);
}

 

虽然可以通过导入远程数据来使全息对象固定在与其他用户相同的位置上,但是全息对象在Unity坐标系中位置可能与其他人不同。

 

示例代码:HoloToolkit Sharing


 

HoloToolkit项目简单封装了场景共享特性,大家可以直接使用Sharing目录下的prefab来集成此特性。

项目主页: https://github.com/Microsoft/HoloToolkit-Unity/tree/master/Assets/HoloToolkit/Sharing