Unity 中的空間對應

空間對應 可讓您擷取三角形網格,代表 HoloLens 裝置周圍的世界表面。 您可以使用表面數據進行放置、遮蔽和會議室分析,讓您的 Unity 專案獲得額外的沉浸式體驗。

Unity 包含空間對應的完整支援,其會以下列方式向開發人員公開:

  1. MixedRealityToolkit 中可用的空間對應元件,可提供方便且快速的路徑,讓您開始使用空間對應
  2. 較低層級的空間對應 API,可提供完整控制並啟用更複雜的應用程式特定自定義

若要在應用程式中使用空間對應,必須在AppxManifest中設定SpatialPerception功能。

裝置支援

功能 HoloLens (第一代) HoloLens 2 沉浸式頭戴裝置
空間對應 ✔️ ✔️

設定 SpatialPerception 功能

為了讓應用程式取用空間對應數據,必須啟用 SpatialPerception 功能。

如何啟用 SpatialPerception 功能:

  1. 在 Unity 編輯器中,開啟 [ 播放程式設定] 窗格, ([編輯 > 項目設定 > 播放機])
  2. [Windows 市集] 索引標籤 上選取
  3. 展開 [發佈設定],然後在 [功能] 列表中檢查 “SpatialPerception” 功能

注意

如果您已經將 Unity 專案匯出至 Visual Studio 方案,則必須匯出至新的資料夾,或在 Visual Studio 的 AppxManifest 中手動設定此功能

空間對應也需要至少 10.0.10586.0 的 MaxVersionTested:

  1. 在 Visual Studio 中,以滑鼠右鍵按兩下 方案總管 中的 Package.appxmanifest,然後選取 [檢視程式代碼]
  2. 尋找指定 TargetDeviceFamily 的行,並將 MaxVersionTested=“10.0.10240.0” 變更為 MaxVersionTested=“10.0.10586.0”
  3. 儲存 Package.appxmanifest。

如何在 Unity 中新增對應

空間感知系統

在 MRTK 中,查看 空間感知入門 指南,以取得設定各種空間網格觀察者的相關信息。

如需裝置觀察者的相關信息,請參閱 設定裝置指南的網格觀察者

如需場景了解觀察者的相關信息,請參閱 場景了解觀察者 指南。

較高層級的網格分析:Spatial Understanding

警告

Spatial Understanding 已被取代為 Scene Understanding

MixedRealityToolkit 是一組公用程式代碼,適用於以 Unity 全像攝影 API 為基礎的全像攝影開發。

Spatial Understanding

在實體世界中放置全像投影時,通常想要超越空間對應的網格和表面平面。 在程式上完成放置時,需要較高的環境理解層級。 這通常需要決定什麼是樓層、上限和牆。 您也可以針對一組放置條件約束進行優化,以判斷全像攝影物件的最佳實體位置。

在開發 Young Conker 和 Fragments 期間,Asobo Studio 會藉由開發會議室解決器,面臨此問題。 這其中每一個遊戲都有遊戲特定的需求,但它們共用了核心空間理解技術。 HoloToolkit.SpatialUnder understanding 連結庫會封裝這項技術,可讓您快速在牆上尋找空白空間、將物件放在頂端、識別要放置的字元,以及大量的其他空間理解查詢。

所有原始程式碼都包含在內,可讓您根據需求加以自定義,並與社群分享您的改進。 C++ 規劃求解的程式代碼已包裝成 UWP dll,並公開至 Unity,且預製專案包含於 MixedRealityToolkit 內。

了解模組

模塊公開了三個主要介面:簡單表面和空間查詢的拓撲、物件偵測的圖形,以及以條件約束為基礎的物件集合放置求解。 以下說明上述各方式。 除了三個主要模組介面之外,也可以使用光線轉換介面來擷取標記的介面類型,並複製自定義水力遊戲空間網格。

光線轉換

完成會議室掃描之後,標籤會在內部為表面產生,例如樓層、上限和牆。 函 PlayspaceRaycast 式會接受光線,如果光線與已知表面碰撞,則傳回 ,如果是的話,則傳回該表面的相關信息格式 RaycastResult為 。

struct RaycastResult
{
    enum SurfaceTypes
    {
        Invalid,    // No intersection
        Other,
        Floor,
        FloorLike,  // Not part of the floor topology,
                    //  but close to the floor and looks like the floor
        Platform,   // Horizontal platform between the ground and
                    //  the ceiling
        Ceiling,
        WallExternal,
        WallLike,   // Not part of the external wall surface,
                    //  but vertical surface that looks like a
                    //  wall structure
    };
    SurfaceTypes SurfaceType;
    float SurfaceArea;  // Zero if unknown
                        //  (i.e. if not part of the topology analysis)
    DirectX::XMFLOAT3 IntersectPoint;
    DirectX::XMFLOAT3 IntersectNormal;
};

在內部,光線廣播會根據播放空間的計算8公分立方體素表示法來計算。 每個體素都包含一組表面元素,其中包含一組已處理的拓撲數據, (也稱為) 。 比較交集體素數據格中包含的表面,以及用來查閱拓撲資訊的最佳比對。 此拓撲數據包含以 「SurfaceTypes」 列舉形式傳回的標籤,以及交集表面的介面區。

在 Unity 範例中,游標會轉換每個畫面格的光線。 首先,針對 Unity 的碰撞器。 其次,針對瞭解模組的世界表示法。 最後,再次使用UI元素。 在此應用程式中,UI 會取得優先順序、了解結果,最後是 Unity 的碰撞器。 SurfaceType 會報告為游標旁的文字。

Surface 類型會在游標旁邊加上標籤
Surface 類型會在游標旁邊加上標籤

拓撲查詢

在 DLL 中,拓撲管理員會處理環境的標籤。 如上所述,大部分的數據會儲存在表面內,包含在體素磁碟區內。 此外,「PlaySpaceInfos」 結構可用來儲存遊戲空間的相關信息,包括世界對齊 (以下) 、樓層和上限高度的更多詳細數據。 啟發學習法用於判斷樓層、上限和牆。 例如,大於 1 m2 介面區的最大和最低水準表面會被視為樓層。

注意

掃描程式期間的相機路徑也會用於此程式。

拓撲管理員所公開的查詢子集會透過 dll 公開。 公開的拓撲查詢如下所示。

QueryTopology_FindPositionsOnWalls
QueryTopology_FindLargePositionsOnWalls
QueryTopology_FindLargestWall
QueryTopology_FindPositionsOnFloor
QueryTopology_FindLargestPositionsOnFloor
QueryTopology_FindPositionsSittable

每個查詢都有一組參數,專屬於查詢類型。 在下列範例中,使用者會指定所需音量的最小高度 & 寬度、在樓層上方的最小放置高度,以及磁碟區前方的最小距離量。 所有度量都是以公尺為單位。

EXTERN_C __declspec(dllexport) int QueryTopology_FindPositionsOnWalls(
    _In_ float minHeightOfWallSpace,
    _In_ float minWidthOfWallSpace,
    _In_ float minHeightAboveFloor,
    _In_ float minFacingClearance,
    _In_ int locationCount,
    _Inout_ Dll_Interface::TopologyResult* locationData)

每個查詢都會採用預先配置的 「TopologyResult」 結構陣列。 “locationCount” 參數會指定傳入陣列中的 長度。 傳回值會報告傳回的位置數目。 這個數字永遠不會大於傳入 「locationCount」 參數的 。

“TopologyResult” 包含傳回磁碟區的中央位置、面向方向 (,也就是一般) ,以及找到的空間維度。

struct TopologyResult
{
    DirectX::XMFLOAT3 position;
    DirectX::XMFLOAT3 normal;
    float width;
    float length;
};

注意

在 Unity 範例中,每個查詢都會連結到虛擬 UI 面板中的按鈕。 範例會將每個查詢的參數硬式編碼為合理的值。 如需更多範例,請參閱範例程序代碼中的SpaceVisualizer.cs。

圖形查詢

在 dll 中,圖形分析器 (“ShapeAnalyzer_W”) 會使用拓撲分析器來比對使用者定義的自定義圖形。 Unity 範例會定義一組圖形,並在圖形索引標籤內透過應用程式內查詢功能表公開結果。其用意是使用者可以定義自己的物件圖形查詢,並視其應用程式的需求使用這些查詢。

圖形分析僅適用於水準表面。 例如,由平面基座表面和平面背面的平面所定義。 圖形查詢會尋找特定大小、高度和外觀範圍的兩個表面,並對齊並連接兩個表面。 使用 API 術語時,基座和背面是圖形元件,而對齊需求是圖形元件條件約束。

在 Unity 範例中定義的範例查詢, (ShapeDefinition.cs) 中,“sittable” 物件的範例如下所示。

shapeComponents = new List<ShapeComponent>()
{
    new ShapeComponent(
        new List<ShapeComponentConstraint>()
        {
            ShapeComponentConstraint.Create_SurfaceHeight_Between(0.2f, 0.6f),
            ShapeComponentConstraint.Create_SurfaceCount_Min(1),
            ShapeComponentConstraint.Create_SurfaceArea_Min(0.035f),
        }
    ),
};
AddShape("Sittable", shapeComponents);

每個圖形查詢都是由一組圖形元件所定義,每個元件都有一組元件條件約束,以及一組圖形條件約束,其中列出元件之間的相依性。 此範例在單一元件定義中包含三個條件約束,而且元件之間沒有圖形條件約束 (,因為只有一個元件) 。

相反地,Couch 圖形有兩個圖形元件和四個圖形條件約束。 元件是由使用者元件清單中的索引所識別, (0 和 1 在此範例中) 。

shapeConstraints = new List<ShapeConstraint>()
{
    ShapeConstraint.Create_RectanglesSameLength(0, 1, 0.6f),
    ShapeConstraint.Create_RectanglesParallel(0, 1),
    ShapeConstraint.Create_RectanglesAligned(0, 1, 0.3f),
    ShapeConstraint.Create_AtBackOf(1, 0),
};

Unity 模組中提供包裝函式,以便輕鬆建立自定義圖形定義。 您可以在 “ShapeComponentConstraint” 和 “ShapeConstraint” 結構的 “SpatialUnderstandingDll.cs” 中找到元件和圖形條件約束的完整清單。

在此介面上找到矩形圖形
在此介面上找到矩形圖形

物件放置規劃求解

物件放置規劃求解可用來識別實體空間中用來放置物件的理想位置。 求解器會根據物件規則和條件約束,找到最適合的位置。 此外,對象查詢會持續存在,直到使用 「Solver_RemoveObject」 或 「Solver_RemoveAllObjects」 呼叫移除物件為止,允許限制的多物件放置。 物件放置查詢包含三個部分:具有參數的放置類型、規則清單和條件約束清單。 若要執行查詢,請使用下列 API。

public static int Solver_PlaceObject(
            [In] string objectName,
            [In] IntPtr placementDefinition,        // ObjectPlacementDefinition
            [In] int placementRuleCount,
            [In] IntPtr placementRules,             // ObjectPlacementRule
            [In] int constraintCount,
            [In] IntPtr placementConstraints,       // ObjectPlacementConstraint
            [Out] IntPtr placementResult)

此函式會採用物件名稱、放置定義,以及規則和條件約束的清單。 C# 包裝函式提供建構協助程式函式,讓規則和條件約束建構變得容易。 放置定義包含查詢類型 ,也就是下列其中一項。

public enum PlacementType
{
    Place_OnFloor,
    Place_OnWall,
    Place_OnCeiling,
    Place_OnShape,
    Place_OnEdge,
    Place_OnFloorAndCeiling,
    Place_RandomInAir,
    Place_InMidAir,
    Place_UnderFurnitureEdge,
};

每個放置類型都有一組唯一的參數。 “ObjectPlacementDefinition” 結構包含一組用於建立這些定義的靜態協助程式函式。 例如,若要尋找將物件放在樓層的地方,您可以使用下列函式。 public static ObjectPlacementDefinition Create_OnFloor (Vector3 halfDims) 除了放置類型之外,您還可以提供一組規則和條件約束。 無法違反規則。 滿足類型和規則的可能放置位置接著會針對條件約束集進行優化,以選取最佳的放置位置。 每個規則和條件約束都可以由提供的靜態建立函式建立。 以下提供範例規則和條件約束建構函式。

public static ObjectPlacementRule Create_AwayFromPosition(
    Vector3 position, float minDistance)
public static ObjectPlacementConstraint Create_NearPoint(
    Vector3 position, float minDistance = 0.0f, float maxDistance = 0.0f)

下列物件放置查詢會尋找一個位置,將半公尺立方體放在表面邊緣,與其他先前放置的物件和靠近會議室中心的地方。

List<ObjectPlacementRule> rules =
    new List<ObjectPlacementRule>() {
        ObjectPlacementRule.Create_AwayFromOtherObjects(1.0f),
    };

List<ObjectPlacementConstraint> constraints =
    new List<ObjectPlacementConstraint> {
        ObjectPlacementConstraint.Create_NearCenter(),
    };

Solver_PlaceObject(
    “MyCustomObject”,
    new ObjectPlacementDefinition.Create_OnEdge(
        new Vector3(0.25f, 0.25f, 0.25f),
        new Vector3(0.25f, 0.25f, 0.25f)),
    rules.Count,
    UnderstandingDLL.PinObject(rules.ToArray()),
    constraints.Count,
    UnderstandingDLL.PinObject(constraints.ToArray()),
    UnderstandingDLL.GetStaticObjectPlacementResultPtr());

如果成功,則會傳回包含放置位置、維度和方向的 “ObjectPlacementResult” 結構。 此外,位置會新增至 dll 的內部放置物件清單。 後續的放置查詢會將此物件納入考慮。 Unity 範例中的 「LevelSolver.cs」 檔案包含更多範例查詢。

物件放置的結果
圖 3:藍色方塊顯示來自三個樓層查詢的結果與相機位置規則不同

解決層級或應用程式案例所需之多個物件的位置時,請先解決異常和大型物件,以將找到空間的機率最大化。 放置順序很重要。 如果找不到物件位置,請嘗試較少的限制設定。 擁有一組後援組態對於支持許多會議室設定的功能非常重要。

會議室掃描程式

雖然 HoloLens 所提供的空間對應解決方案設計成足以符合整個問題空間之需求的泛型,但空間理解模組是為了支援兩個特定遊戲的需求而建置。 其解決方案是以特定程式及一組假設為結構,如下所述。

Fixed size playspace – The user specifies the maximum playspace size in the init call.

One-time scan process –
    The process requires a discrete scanning phase where the user walks around,
    defining the playspace.
    Query functions will not function until after the scan has been finalized.

用戶驅動遊戲空間「繪製」– 在掃描階段,用戶會移動並查看播放步調,有效地繪製應該包含的區域。 在此階段,產生的網格對於提供使用者意見反應很重要。 室內住家或辦公室設定 – 查詢函式是針對平面表面和牆設計,以直角呈現。 這是虛限制。 不過,在掃描階段期間,主要軸分析已完成,以優化沿著主要和次要軸的網格鑲嵌。 包含的 SpatialUnderstanding.cs 檔案會管理掃描階段程式。 它會呼叫下列函式。

SpatialUnderstanding_Init – Called once at the start.

GeneratePlayspace_InitScan – Indicates that the scan phase should begin.

GeneratePlayspace_UpdateScan_DynamicScan –
    Called each frame to update the scanning process. The camera position and
    orientation is passed in and is used for the playspace painting process,
    described above.

GeneratePlayspace_RequestFinish –
    Called to finalize the playspace. This will use the areas “painted” during
    the scan phase to define and lock the playspace. The application can query
    statistics during the scanning phase as well as query the custom mesh for
    providing user feedback.

Import_UnderstandingMesh –
    During scanning, the “SpatialUnderstandingCustomMesh” behavior provided by
    the module and placed on the understanding prefab will periodically query the
    custom mesh generated by the process. In addition, this is done once more
    after scanning has been finalized.

掃描流程,由 「SpatialUnderstanding」 行為所驅動,會呼叫 InitScan,然後更新掃描每個畫面。 當統計數據查詢報告合理的涵蓋範圍時,用戶可透過 airtap 呼叫 RequestFinish 來指出掃描階段的結束。 UpdateScan 會繼續呼叫,直到其傳回值指出 dll 已完成處理為止。

瞭解網格

瞭解 dll 會在內部將播放空間儲存為 8 公分大小的體素立方體格。 在掃描的初始部分中,主要元件分析已完成,以判斷會議室的軸。 在內部,它會儲存對齊這些軸的體素空間。 從體素磁碟區擷取 isosurface,大約每秒產生一個網格。

從體素磁碟區產生的網格
從體素磁碟區產生的網格

疑難排解

  • 確定您已設定 SpatialPerception 功能
  • 追蹤遺失時,下一個 OnSurfaceChanged 事件將會移除所有網格。

Mixed Reality 工具組中的空間對應

如需搭配使用空間對應與 Mixed Reality 工具組的詳細資訊,請參閱 MRTK 檔的空間感知一節

下一個開發檢查點

如果您遵循我們配置的 Unity 開發旅程,您正在探索 MRTK 核心建置組塊。 接下來,您可以繼續進行下一個建置組塊:

或者,直接跳到混合實境平台功能和 API 的主題:

您可以隨時回到 Unity 開發檢查點

另請參閱