在 Unity 中移动平台模式

移动平台模式允许 HoloLens 2 在船舶、石油平台和其他车辆等移动平台上正常工作。

详细了解移动平台模式

概念概述

若要使混合现实系统正常工作,必须相对于环境跟踪头戴显示设备。 通过此相对跟踪,可以呈现图形,以便显示头戴显示设备的用户在环境中被固定锁定。 通常可以通过组合使用惯性测量单元 (IMU) 的外向相机和测量来计算的姿势来实现跟踪。 当环境处于参考惯性帧时,此方法非常有效。 小效果,如行星式运动,通常被忽视。

当环境不在参考的惯性帧中时,正常的头部跟踪系统将失败。 移动平台模式功能通过考虑相对于惯性帧的环境运动来解决此问题。 因此,在移动平台模式下,HoloLens 2 可以呈现看起来固定到环境的全息影像,即使环境是一艘摇摆不定的船!

如何激活移动平台模式?

为了启用一系列用例,已经提供了各种方法来激活移动平台模式。 必须仔细考虑要选择的方法。 需要询问的一个关键问题是:谁知道 HoloLens 2 当前是否在移动平台中? 请参阅下表中的示例:

谁知道 HL2 是否在移动平台中 设置移动平台模式的最佳方法 好处 成本
系统管理员 移动设备管理 用户无需参与。 任何应用都无需修改即可工作。 可以保护设备,防止其进入错误模式。 用户和应用无法更改模式。
最终用户 “设置”应用 用户通常最了解其使用设备的时间和地点。 任何应用都无需修改即可工作。 用户可能不知道模式的存在。
该应用程序 使用本文中所述的 SDK。 当无法提前知道环境时,可以使用特定于用例的提示来交换模式。 消除了用户必须做出此决定并在设置中更改模式的要求。 设计不佳的应用可能会带来非常糟糕的体验,并使设备处于意外模式。

移动平台模式的最佳做法

主体 说明
尊重用户选择 在为用户更改模式之前,应向用户提供选择,并且应继续尊重该选项供应用运行时使用
向用户提供警告 避免在应用启动/恢复时立即更改模式。 这提供了糟糕的用户体验,因为用户可能不知道设备为何丢失跟踪。
最小化更改模式 更改移动平台模式设置时,设备将丢失跟踪,从而导致负面用户体验。 因此,建议将更改模式的频率降到最低。 理想情况下,仅当设备从固定环境过渡到移动环境时,模式才会更改,反之亦然。
如果环境不确定,请使用移动平台模式 移动平台模式可以在固定环境和移动环境中工作。 常规跟踪算法仅在固定环境中工作,因此,如果不确定环境是否正在移动,选择移动平台模式可能是更安全的选择。
请勿在已知的固定环境中使用移动平台模式 移动平台模式在固定环境中的性能低于标准模式。 这只是一个很小的下降,但大多数用户都能明显感觉到。
考虑将设备留在哪个模式 此 SDK 允许开发人员设计在设备启动时可靠的体验。 请考虑设备下次启动时是否在移动平台上,并将设备保持适当的模式。

在哪里获取 SDK?

移动平台 SDK 支持 C# 和 C++ 的语言投影,使开发人员能够开发适用于 Win32 或 UWP 平台的应用程序。 使用混合现实功能工具下载并安装 SDK。

如何使用此 SDK

安装 SDK 后,可以将脚本设置为使用 MovingPlatformManger,如下所示:

// Top of file
using Microsoft.MixedReality.MovingPlatform;
// Code body
m_movingPlatformManager = new MovingPlatformManager();

读取当前模式

可以按如下所示读取模式的当前值:

MovingPlatformMode currentMode = m_movingPlatformManager.Mode;

MovingPlatformMode 是一个枚举,定义如下:

public enum MovingPlatformMode
{
    Standard,                // The legacy mode that devices use out-of-the-box.
    MovingPlatformOptimized  // Allows tracking on moving platforms.
}

没有移动平台模式的设备(如 VR 设备和 HoloLens 1)将始终返回“标准”。

设置模式

可以设置移动平台模式值,如下所示:

bool success = m_movingPlatformManager.TrySetMode(MovingPlatformMode.MovingPlatformOptimized);

如果设备模式现在与请求的模式匹配,TrySetMode 将返回 true。 如果模式已处于所需状态,则不会执行任何操作,并且设备不会丢失跟踪。

模式更改时的回调

有时,了解其他应用或用户是否已更改移动平台模式值可能很有用。 可以按如下所示进行操作。

// Code Body
m_movingPlatformManager.ModeChanged += CallbackOnMPMChanged;
...
void CallbackOnMPMChanged(object sender, MovingPlatformEventArgs args)
{
    movingPlatformModeChanged = true;
    movingPlatformModeValue = args.ModeEntered;
}
...
void Update()
{
    // It's not reccomended to do work in the callback.
    if (movingPlatformModeChanged)
    {
        movingPlatformModeChanged = false;
        // Do some work
    }
}

检查模式是否可设置

有时,在尝试更改模式之前,了解模式是否可设置很有用。 例如,如果想要知道是否在询问用户首选项时有任何值。 可以使用 IsSetModeSupported 函数查找移动平台模式是否可设置:

bool supported = m_movingPlatformManager.IsSetModeSupported();

如果设备可以更改模式,则此函数将返回 true;如果无法更改模式,则返回 false。 此函数负责移动设备管理 (MDM) 策略。 例如,如果 MDM 强制 MovingPlatformMode 设置为“On”,则此函数将返回 false。

演示脚本

此脚本在一个位置显示 SDK 的所有重要元素。 该示例不遵循上面所示的最佳做法。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Microsoft.MixedReality.MovingPlatform;
using System;

public class MovingPlatformDemo : MonoBehaviour
{
    public GameObject cube; // A simple cube to display colors.
    private MovingPlatformManager m_movingPlatformManager;
    private Renderer cubeRenderer;
    private bool movingPlatformModeChanged;
    private MovingPlatformMode movingPlatformModeValue;

    // Start is called before the first frame update
    void Start()
    {
        m_movingPlatformManager = new MovingPlatformManager();
        cubeRenderer = cube.GetComponent<Renderer>();

        // Get initial value of mode, 
        // Just this mechanism would be adequate if a one time check is acceptable. 
        MovingPlatformMode initialMovingPlatformMode = m_movingPlatformManager.Mode;

        // Find if It's possible to change the mode. 
        bool isSettable = m_movingPlatformManager.IsSetModeSupported();

        // Here you would add some use case specific logic using initialMovingPlatformMode and isSettable
        // to decide if you should ask the user if they want to change the mode. 

        // To set the mode.
        bool success = m_movingPlatformManager.TrySetMode(MovingPlatformMode.MovingPlatformOptimized);

        // Visual indicator of current state: Green = Moving Platform Optimized, Red = Regular.
        SetColourFromState(m_movingPlatformManager.Mode, cubeRenderer);

        // We set a callback to be notified if there's a change in mode. This is typically optional.
        m_movingPlatformManager.ModeChanged += CallbackOnMPMChanged;
        movingPlatformModeChanged = false;
    }

    // Update is called once per frame
    void Update()
    {
        // This must be done in the UI thread.
        if (movingPlatformModeChanged)
        {
            movingPlatformModeChanged = false;
            SetColourFromState(movingPlatformModeValue, cubeRenderer);
        }
    }

    // Sets renderer to:
    // Green = Moving Platform Mode Enabled
    // Red = Moving Platform Mode Disabled
    void SetColourFromState(MovingPlatformMode mode, Renderer thisRend)
    {
        if (mode == MovingPlatformMode.MovingPlatformOptimized)
        {
            thisRend.material.color = new Color(0f, 1f, 0f, 1f);
        }
        else
        {
            thisRend.material.color = new Color(1f, 0f, 0f, 1f);
        }
    }

    void CallbackOnMPMChanged(object sender, MovingPlatformEventArgs args)
    {
        movingPlatformModeChanged = true;
        movingPlatformModeValue = args.ModeEntered;
    }
}

另请参阅