共用方式為


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

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

在楊康克和片段的開發期間,麻生工作室通過開發房間解決器來面對這個問題。 這些遊戲都有遊戲特定的需求,但他們分享了核心空間理解技術。 HoloToolkit.SpatialUnderstanding 連結庫會封裝這項技術,可讓您快速在牆壁上尋找空白空間、將物件放在天花板上、識別放置給字元的位置,以及無數個其他空間理解查詢。

包含所有原始程式碼,可讓您根據需求自定義原始程式碼,並與社群共用您的改進。 C++規劃求解的程式代碼已包裝在 UWP dll 中,並公開至 Unity,其中含有 MixedRealityToolkit 內含的 prefab。

了解模組

模組會公開三個主要介面:簡單表面和空間查詢的拓撲、物件偵測的形狀,以及物件集條件約束式放置的物件放置規劃求解。 以下說明每一項。 除了三個主要模組介面之外,還可以使用光線轉換介面來擷取已標記的表面類型,也可以複製自定義水位遊戲空間網格。

光線轉換

完成房間掃描之後,會針對地板、天花板和牆壁等表面在內部產生標籤。 函 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 會回報為游標旁的文字。

表面類型會標示在游標旁邊
表面類型會標示在游標旁邊

拓撲查詢

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

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

相反地,沙發圖形有兩個圖形元件和四個圖形條件約束。 元件會依使用者元件清單中的索引來識別(在此範例中為 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 釐米大小的體素立方體網格線。 在掃描的初始部分期間,會完成主要元件分析,以判斷會議室的軸。 在內部,它會儲存對齊這些軸的體素空間。 透過從體素捲擷取等表面,大約每秒產生網格。

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

疑難排解

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

混合實境工具組中的空間對應

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

下一個開發檢查點

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

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

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

另請參閱