在 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;
}
}