Unity 中的混合现实本机互操作

每个混合现实应用在开始接收相机数据和呈现帧之前都会获得一个 HolographicSpace。 在 Unity 中,引擎会为你处理这些步骤,处理全息对象并作为其呈现循环的一部分进行内部更新。

但是,在高级场景中,你可能需要访问基础本机对象,例如 HolographicCamera 和当前的 HolographicFrame

WindowsMixedRealityUtilities

命名空间:Microsoft.MixedReality.Toolkit.WindowsMixedReality
类型:WindowsMixedRealityUtilities

MRTK 通过 WindowsMixedRealityUtilities 类跨旧版 WSA 和 XR SDK 提供已封送的类型。

public static HolographicFrame CurrentHolographicFrame { get; }
public static SpatialCoordinateSystem SpatialCoordinateSystem { get; }
public static SpatialInteractionManager SpatialInteractionManager { get; }

取消封送本机指针

从上述方法之一(MRTK 不需要)获取 IntPtr 后,使用以下代码片段将它们封送到托管对象。

如果使用的是 Microsoft.Windows.MixedReality.DotNetWinRT,则可以使用 FromNativePtr() 方法从本机指针构造托管对象:

var worldOrigin = Microsoft.Windows.Perception.Spatial.SpatialCoordinateSystem.FromNativePtr(spatialCoordinateSystemPtr);

否则,请使用 Marshal.GetObjectForIUnknown() 并强制转换到想要的类型:

#if ENABLE_WINMD_SUPPORT
var worldOrigin = Marshal.GetObjectForIUnknown(spatialCoordinateSystemPtr) as Windows.Perception.Spatial.SpatialCoordinateSystem;
#endif

在坐标系之间转换

Unity 使用左手坐标系,而 Windows Perception API 使用右手坐标系。 若要在这两个约定之间转换,可以使用以下帮助程序:

namespace NumericsConversion
{
    public static class NumericsConversionExtensions
    {
        public static UnityEngine.Vector3 ToUnity(this System.Numerics.Vector3 v) => new UnityEngine.Vector3(v.X, v.Y, -v.Z);
        public static UnityEngine.Quaternion ToUnity(this System.Numerics.Quaternion q) => new UnityEngine.Quaternion(q.X, q.Y, -q.Z, -q.W);
        public static UnityEngine.Matrix4x4 ToUnity(this System.Numerics.Matrix4x4 m) => new UnityEngine.Matrix4x4(
            new Vector4( m.M11,  m.M12, -m.M13,  m.M14),
            new Vector4( m.M21,  m.M22, -m.M23,  m.M24),
            new Vector4(-m.M31, -m.M32,  m.M33, -m.M34),
            new Vector4( m.M41,  m.M42, -m.M43,  m.M44));

        public static System.Numerics.Vector3 ToSystem(this UnityEngine.Vector3 v) => new System.Numerics.Vector3(v.x, v.y, -v.z);
        public static System.Numerics.Quaternion ToSystem(this UnityEngine.Quaternion q) => new System.Numerics.Quaternion(q.x, q.y, -q.z, -q.w);
        public static System.Numerics.Matrix4x4 ToSystem(this UnityEngine.Matrix4x4 m) => new System.Numerics.Matrix4x4(
            m.m00,  m.m10, -m.m20,  m.m30,
            m.m01,  m.m11, -m.m21,  m.m31,
           -m.m02, -m.m12,  m.m22, -m.m32,
            m.m03,  m.m13, -m.m23,  m.m33);
    }
}

使用 HolographicFrame 本机数据

注意

更改通过 HolographicFrameNativeData 接收到的本机对象的状态可能会导致不可预测的行为和呈现项目,尤其是当 Unity 也对相同状态进行推理时。 例如,你不应调用 HolographicFrame.UpdateCurrentPrediction,否则 Unity 使用该帧呈现的姿势预测将与 Windows 预期的姿势不同步,这会降低全息影像的稳定性

如果你需要访问本机接口以进行呈现或调试,请在本机插件或 C# 代码中使用来自 HolographicFrameNativeData 的数据。

以下示例演示如何使用 HolographicFrameNativeData 通过 XR SDK 扩展获取当前帧对光子时间的预测。

using System;
using System.Runtime.InteropServices;

public static bool GetCurrentFrameDateTime(out DateTime frameDateTime)
{
#if ENABLE_WINMD_SUPPORT
    IntPtr holographicFramePtr = UnityEngine.XR.WindowsMR.WindowsMREnvironment.CurrentHolographicRenderFrame;

    if (holographicFramePtr != IntPtr.Zero)
    {
        var holographicFrame = Marshal.GetObjectForIUnknown(holographicFramePtr) as Windows.Graphics.Holographic.HolographicFrame;
        frameDateTime = holographicFrame.CurrentPrediction.Timestamp.TargetTime.DateTime;
        return true;
    }
#endif

    frameDateTime = DateTime.MinValue;
    return false;
}

另请参阅