创建空间感知系统数据提供程序 - MRTK2

空间感知系统是一个可扩展系统,用于为应用程序提供有关实际环境的数据。 若要添加对新硬件平台或新形式的空间感知数据的支持,可能需要自定义数据提供程序。

本文介绍如何为空间感知系统创建自定义数据提供程序(也称为空间观察器)。 此处所示的示例代码来自 SpatialObjectMeshObserver 类实现,可用于在编辑器中加载 3D 网格数据

注意

此示例中使用的完整源代码可在 Assets/MRTK/Providers/ObjectMeshObserver 文件夹中找到。

命名空间和文件夹结构

可通过以下两种方式之一分发数据提供程序:

  1. 第三方加载项
  2. Microsoft 混合现实工具包的一部分

向 MRTK 提交新数据提供程序的审批过程将因案例而异,将在初始建议时传达。 可以通过创建新的“功能请求”类型问题来提交提案。

第三方加载项

命名空间

数据提供程序需有一个命名空间来缓解潜在的名称冲突。 建议命名空间包含以下组件。

  • 生成加载项的公司名称
  • 功能区域

例如,Contoso 公司创建和运送的空间感知数据提供程序可能是“Contoso.MixedReality.Toolkit.SpatialAwareness”。

文件夹结构

建议将数据提供程序的源代码按文件夹层次结构进行布局,如下图所示。

文件夹结构示例

其中,ContosoSpatialAwareness 文件夹包含数据提供程序的实现,Editor 文件夹包含检查器(以及 Unity 编辑器特定的任何其他代码),Profiles 文件夹包含一个或多个预创建的配置文件可编脚本对象。

MRTK 提交

命名空间

如果将空间感知系统数据提供程序提交到混合现实工具包存储库,命名空间“必须”以 Microsoft.MixedReality.Toolkit 开头(例如:Microsoft.MixedReality.Toolkit.SpatialObjectMeshObserver)

且代码应位于 MRTK/Providers 下的文件夹中(例如:MRTK/Providers/ObjectMeshObserver)。

文件夹结构

所有应位于 MRTK/Providers 下的文件夹中(例如:MRTK/Providers/ObjectMeshObserver)。

定义空间数据对象

创建空间感知数据提供程序的第一步是确定它将提供给应用程序的数据类型(例如:网格或平面)。

所有空间数据对象必须实现 IMixedRealitySpatialAwarenessObject 接口。

混合现实工具包基础提供了以下可以在新的数据提供程序中使用或扩展的空间对象。

实现数据提供程序

指定接口和/或基类继承

所有空间感知数据提供程序必须实现 IMixedRealitySpatialAwarenessObserver 接口,该接口指定空间感知系统所需的最小功能。 MRTK 基础包括 BaseSpatialObserver 类,该类提供所需功能的默认实现。

public class SpatialObjectMeshObserver :
    BaseSpatialObserver,
    IMixedRealitySpatialAwarenessMeshObserver,
    IMixedRealityCapabilityCheck
{ }

注意

IMixedRealityCapabilityCheck 接口由 SpatialObjectMeshObserver 类用来指示它提供对 SpatialAwarenessMesh 功能的支持。

应用 MixedRealityDataProvider 属性

创建空间感知数据提供程序的关键步骤是将 MixedRealityDataProvider 属性应用到类。 在空间感知配置文件以及名称、文件夹路径等中选择时,此步骤可为数据提供程序设置默认配置文件和平台。

[MixedRealityDataProvider(
    typeof(IMixedRealitySpatialAwarenessSystem),
    SupportedPlatforms.WindowsEditor | SupportedPlatforms.MacEditor | SupportedPlatforms.LinuxEditor,
    "Spatial Object Mesh Observer",
    "ObjectMeshObserver/Profiles/DefaultObjectMeshObserverProfile.asset",
    "MixedRealityToolkit.Providers")]
public class SpatialObjectMeshObserver :
    BaseSpatialObserver,
    IMixedRealitySpatialAwarenessMeshObserver,
    IMixedRealityCapabilityCheck
{ }

实现 IMixedRealityDataProvider 方法

定义类后,下一步是提供 IMixedRealityDataProvider 接口的实现。

注意

BaseSpatialObserver 类通过 BaseService 类为 IMixedRealityDataProvider 方法仅提供空实现。 这些方法的详细信息通常特定于数据提供程序。

数据提供程序应实现的方法为:

  • Destroy()
  • Disable()
  • Enable()
  • Initialize()
  • Reset()
  • Update()

实现数据提供程序逻辑

下一步是通过实现特定的数据提供程序接口来添加数据提供程序的逻辑,例如 IMixedRealitySpatialAwarenessMeshObserver。 数据提供程序的这一部分通常是特定于平台的。

观察更改通知

为了使应用程序能够响应设备对环境的理解的更改,数据提供程序会引发 IMixedRealitySpatialAwarenessObservationtHandler<T> 接口中定义的通知事件。

  • OnObservationAdded()
  • OnObservationRemoved()
  • OnObservationUpdated()

SpatialObjectMeshObserver 示例中的以下代码演示了添加网格数据时的引发事件。

// The data to be sent when mesh observation events occur.
// This member variable is initialized as part of the Initialize() method.
private MixedRealitySpatialAwarenessEventData<SpatialAwarenessMeshObject> meshEventData = null;

/// <summary>
/// Sends the observations using the mesh data contained within the configured 3D model.
/// </summary>
private void SendMeshObjects()
{
    if (!sendObservations) { return; }

    if (spatialMeshObject != null)
    {
        MeshFilter[] meshFilters = spatialMeshObject.GetComponentsInChildren<MeshFilter>();
        for (int i = 0; i < meshFilters.Length; i++)
        {
            SpatialAwarenessMeshObject meshObject = SpatialAwarenessMeshObject.Create(
                meshFilters[i].sharedMesh,
                MeshPhysicsLayer,
                $"Spatial Object Mesh {currentMeshId}",
                currentMeshId,
                ObservedObjectParent);

            meshObject.GameObject.transform.localPosition = meshFilters[i].transform.position;
            meshObject.GameObject.transform.localRotation = meshFilters[i].transform.rotation;

            ApplyMeshMaterial(meshObject);

            meshes.Add(currentMeshId, meshObject);

            // Initialize the meshEventData variable with data for the added event.
            meshEventData.Initialize(this, currentMeshId, meshObject);
            // Raise the event via the spatial awareness system.
            SpatialAwarenessSystem?.HandleEvent(meshEventData, OnMeshAdded);

            currentMeshId++;
        }
    }

    sendObservations = false;
}

注意

SpatialObjectMeshObserver 类不会引发 OnObservationUpdated 事件,因为 3D 模型仅加载一次。 WindowsMixedRealitySpatialMeshObserver 类中的实现提供了为观察到的网格引发 OnObservationUpdated 事件的示例。

添加 Unity 探查器检测

性能在混合现实应用程序中非常重要。 每个组件都增加了应用程序必须考虑的一些开销。 为此,必须确保所有空间感知数据提供程序在内部循环和经常使用的代码路径中包含 Unity 探查器检测。

建议在检测自定义提供程序时实现 MRTK 使用的模式。

        private static readonly ProfilerMarker UpdateObserverPerfMarker = new ProfilerMarker("[MRTK] WindowsMixedRealitySpatialMeshObserver.UpdateObserver");

        /// <summary>
        /// Requests updates from the surface observer.
        /// </summary>
        private void UpdateObserver()
        {
            using (UpdateObserverPerfMarker.Auto())
            {
                // Code to be measured.
            }
        }

注意

用于标识探查器标记的名称是任意的。 MRTK 使用以下模式。

“[product] className.methodName - 可选备注”

建议自定义数据提供程序遵循类似的模式,以帮助在分析跟踪时简化特定组件和方法的标识。

创建配置文件和检查器

在 混合现实 Toolkit 中,使用配置文件配置数据提供程序。

定义配置文件

配置文件内容应镜像数据提供程序的可访问属性(例如:更新间隔)。 每个接口中定义的所有用户可配置属性应包含在配置文件中。

如果新数据提供程序扩展了现有的提供程序,则建议使用基类。 例如,SpatialObjectMeshObserverProfile 扩展 MixedRealitySpatialAwarenessMeshObserverProfile 以使客户能够提供 3D 模型作为环境数据。

[CreateAssetMenu(
    menuName = "Mixed Reality Toolkit/Profiles/Spatial Object Mesh Observer Profile",
    fileName = "SpatialObjectMeshObserverProfile",
    order = 100)]
public class SpatialObjectMeshObserverProfile : MixedRealitySpatialAwarenessMeshObserverProfile
{
    [SerializeField]
    [Tooltip("The model containing the desired mesh data.")]
    private GameObject spatialMeshObject = null;

    /// <summary>
    /// The model containing the desired mesh data.
    /// </summary>
    public GameObject SpatialMeshObject => spatialMeshObject;
}

CreateAssetMenu该属性可应用于配置文件类,使客户能够使用“创建>资产>混合现实工具包>配置文件”菜单创建配置文件实例

实现检查器

配置文件检查器是用于配置和查看配置文件内容的用户界面。 每个配置文件检查器应扩展 BaseMixedRealityToolkitConfigurationProfileInspector 类。

CustomEditor 属性向 Unity 告知检查器应用到的资产类型。

[CustomEditor(typeof(SpatialObjectMeshObserverProfile))]
public class SpatialObjectMeshObserverProfileInspector : BaseMixedRealityToolkitConfigurationProfileInspector
{ }

创建程序集定义

混合现实 Toolkit 使用程序集定义 (.asmdef) 文件来指定组件之间的依赖关系,并帮助 Unity 缩短编译时间。

建议为所有数据提供程序及其编辑器组件创建程序集定义文件。

如果使用前面示例中的文件夹结构,ContosoSpatialAwareness 数据提供程序将有两个 .asmdef 文件。

第一个程序集定义用于数据提供程序。 在此示例中,它将被称为 ContosoSpatialAwareness,并位于该示例的 ContosoSpatialAwareness 文件夹中。 此程序集定义必须指定对 Microsoft.MixedReality.Toolkit 及其所依赖的任何其他程序集的依赖关系。

ContosoInputEditor 程序集定义指定配置文件检查器和编辑器特定的任何代码。 此文件必须位于编辑器代码的根文件夹中。 在此示例中,该文件位于 ContosoSpatialAwareness\Editor 文件夹中。 此程序集定义将包含对 ContosoSpatialAwareness 程序集的引用,以及:

  • Microsoft.MixedReality.Toolkit
  • Microsoft.MixedReality.Toolkit.Editor.Inspectors
  • Microsoft.MixedReality.Toolkit.Editor.Utilities

注册数据提供程序

创建后,可将数据提供程序注册到空间感知系统,以在应用程序中使用。

选择空间对象网格观察程序

打包和分发

作为第三方组件分发的数据提供程序的具体打包和分发细节由开发人员决定。 最常见的解决方案可能是生成一个 .unitypackage,通过 Unity Asset Store 进行分发。

如果数据提供程序作为“Microsoft 混合现实工具包”包的一部分提交和接受,Microsoft MRTK 团队会将其打包,作为 MRTK 产品/服务的一部分进行分发。

请参阅