ケーススタディ-HoloLens の空間マッピング機能の拡張

Microsoft HoloLens 用の最初のアプリを作成する際には、デバイス上での空間マッピングの境界をどれだけまでにプッシュできるかについてのみ説明しました。 Microsoft スタジオのソフトウェアエンジニアである Jeff Evertt は、新しいテクノロジがどのように開発され、ユーザーの実際の環境でのホログラムの配置方法をより細かく制御する必要がないかについて説明しています。

注意

HoloLens 2 には、開発者向けの新しいシーンランタイムが実装されています。これは、環境を認識するアプリケーションのための開発を直感的に行うように設計された、構造化された高レベルの環境表現を使用して、混合の

ビデオを見る

空間マッピング以外

私たちは、フラグメント若い conkerに取り組んでいましたが、最初に HoloLens のゲームの2つで、物理的な世界にホログラムを配置するときに、ユーザーの環境についてより高いレベルの理解が必要でした。 各ゲームには独自の配置ニーズがありました。たとえば、フラグメントでは、フロアやテーブルなどのさまざまなサーフェスを区別して、関連する場所に手掛かりを配置する必要がありました。 また、ソファや椅子など、holographic 文字が見られる可能性のある表面を特定できるようにする必要がありました。 Young Conker では、プレーヤーの部屋の中で、生成された画面をプラットフォームとして使用できるようにしたいと考えていました。

これらのゲームの開発パートナーであるAsobo スタジオは、この問題に直面し、HoloLens の空間マッピング機能を拡張するテクノロジを作成しました。 これを使用すると、プレーヤーの部屋を分析し、壁、テーブル、椅子、床などの表面を特定できます。 また、holographic オブジェクトの最適な配置を決定するために、一連の制約に対して最適化する機能が用意されています。

空間を理解するコード

Asobo の元のコードを取って、このテクノロジをカプセル化するライブラリを作成しました。 Microsoft と Asobo は、このコードをオープンソースにし、独自のプロジェクトで使用できるように MixedRealityToolkit で使用できるようにしました。 すべてのソースコードが含まれているので、ニーズに合わせてカスタマイズし、その機能強化をコミュニティと共有することができます。 C++ ソルバーのコードは、UWP DLL にラップされ、 MixedRealityToolkit 内に含まれるドロップイン prefabを使用して Unity に公開されています。

Unity サンプルには多くの便利なクエリが含まれています。これを使用すると、壁上の空のスペースを検索したり、オブジェクトを天井に配置したり、床上の大きなスペースに配置したり、文字の位置を識別したり、その他のさまざまな空間を理解するクエリを実行したりできます。

HoloLens によって提供される空間マッピングソリューションは、問題のある領域全体のニーズに対応できるように設計されていますが、空間を理解するためのモジュールは、2つの特定のゲームのニーズをサポートするように構築されています。 そのため、そのソリューションは、特定のプロセスと一連の前提を中心に構築されています。

  • 固定サイズの playspace: ユーザーは、init 呼び出しの最大 playspace サイズを指定します。
  • 1 回限りのスキャンプロセス: このプロセスには、ユーザーが再生領域を定義するための個別のスキャンフェーズが必要です。 クエリ関数は、スキャンが完了するまで機能しません。
  • ユーザー駆動型の playspace "描画": スキャンフェーズ中に、ユーザーが playspace を移動して表示し、含める必要がある領域を効果的に描画します。 生成されたメッシュは、このフェーズでユーザーからのフィードバックを提供するために重要です。
  • 屋内で home または office セットアップ: クエリ関数は、フラットなサーフェイスと壁面を中心に設計されています。 これは、ソフトな制限です。 ただし、スキャンフェーズでは、主要軸と補助軸に沿ってメッシュテセレーションを最適化するために、主軸分析が完了します。

ルームスキャンプロセス

空間を理解するためのモジュールを読み込むときは、最初にスペースをスキャンします。これにより、床、天井、壁など、使用可能なすべてのサーフェイスが識別され、ラベルが付けられます。 スキャン処理中は、部屋を見て、スキャンに含める必要がある領域を "ペイント" します。

このフェーズで見たメッシュは、どの部分がスキャンされているかをユーザーが知ることができる視覚的なフィードバックの重要な部分です。 空間認識モジュールの DLL は、内部的に、8cm サイズの voxel キューブのグリッドとして playspace を格納します。 スキャンの初期部分では、主要なコンポーネント分析が完了して、部屋の軸が決定されます。 内部的には、これらの軸に合わせて voxel 領域を格納します。 メッシュは、voxel ボリュームから isosurface を抽出することによって、約1秒ごとに生成されます。

白の空間マッピングメッシュと、緑色の playspace メッシュについて理解する

白の空間マッピングメッシュと、緑色の playspace メッシュについて理解する

含まれている SpatialUnderstanding ファイルは、スキャンフェーズプロセスを管理します。 次の関数を呼び出します。

  • SpatialUnderstanding_Init: 開始時に1回呼び出されます。
  • GeneratePlayspace_InitScan: スキャンフェーズを開始する必要があることを示します。
  • GeneratePlayspace_UpdateScan_DynamicScan: 各フレームを呼び出して、スキャンプロセスを更新します。 カメラの位置と向きは、前に説明した playspace の描画プロセスに使用されます。
  • GeneratePlayspace_RequestFinish: playspace を終了するために呼び出されます。 これは、スキャンフェーズ中に "描画された" 領域を使用して、playspace を定義およびロックします。 アプリケーションでは、スキャンフェーズ中に統計のクエリを実行したり、ユーザーフィードバックを提供するためにカスタムメッシュを照会したりすることができます。
  • Import_UnderstandingMesh: スキャン中に、モジュールによって提供された SpatialUnderstandingCustomMesh の動作が、prefab を理解するために、プロセスによって生成されたカスタムメッシュを定期的に照会します。 さらに、この処理は、スキャンが完了した後に実行されます。

SpatialUnderstanding 動作によって実行されるスキャンフローは、 initscan を呼び出し、その後、各フレームに対して アップデートを実行 します。 統計クエリによって適切なカバレッジが報告されると、ユーザーは、[ Requestfinish ] を呼び出して、スキャンフェーズの終了を示すことができます。 戻り値が DLL の処理を完了したことを示すまで、アップデートを引き続き呼び出す ことができ ます。

クエリ

スキャンが完了すると、インターフェイスで次の3種類のクエリにアクセスできるようになります。

  • トポロジクエリ: スキャンされたルームのトポロジに基づく高速クエリです。
  • Shape クエリ: トポロジクエリの結果を使用して、定義したカスタム図形に適した水平方向のサーフェイスを検索します。
  • オブジェクト配置クエリ: オブジェクトの一連のルールと制約に基づいて最適な場所を検索する、より複雑なクエリです。

3つの主要なクエリに加えて、raycasting インターフェイスを使用して、タグ付きサーフェスの種類を取得し、カスタムの watertight ルームメッシュをコピーすることができます。

トポロジクエリ

DLL 内では、トポロジマネージャーは環境のラベル付けを処理します。 前述のように、データの大部分は、voxel ボリューム内に含まれる、1つのデータに格納されています。 さらに、 playspace 情報構造体は、再生領域に関する情報を格納するために使用されます。これには、ワールドアラインメント (下記の詳細情報)、floor、および天井高さが含まれます。

ヒューリスティックは、floor、シーリング、および壁面を決定するために使用されます。 たとえば、1 ~ 2 の範囲を超える水平方向サーフェイスは、床面と見なされます。 このプロセスでは、スキャン処理中のカメラパスも使用されることに注意してください。

トポロジマネージャーによって公開されるクエリのサブセットは、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 パネルのボタンにリンクされていることに注意してください。 サンプルでは、これらの各クエリのパラメーターを妥当な値にハードコーディングしています。 その他の例については、サンプルコードの「 Space ビジュアライザー .cs 」を参照してください。

クエリのシェイプ

DLL 内で、shape analyzer (ShapeAnalyzer_W) は、トポロジアナライザーを使用して、ユーザーが定義したカスタム図形と照合します。 Unity サンプルには、定義済みの一連の図形があります。これは、[クエリ] メニューの [図形] タブに表示されます。

図形の分析は、水平方向のサーフェイスでのみ動作することに注意してください。 たとえば、ソファは、平らな座席の表面とソファの上面によって定義されています。 Shape クエリでは、特定のサイズ、高さ、および縦横範囲の2つのサーフェスが検索され、2つのサーフェスがアラインされ、接続されています。 この Api の用語を使用して、ソファ座席とソファの背面の上部には形状コンポーネントがあり、アラインメント要件はシェイプコンポーネントの制約です。

"Sittable" オブジェクトの Unity サンプル (図形定義 .cs) で定義されているクエリの例を次に示します。

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

各図形クエリは、一連の図形コンポーネントによって定義されます。各図形コンポーネントには、一連のコンポーネント制約と、コンポーネント間の依存関係を示す一連の図形制約があります。 この例では、1つのコンポーネント定義に3つの制約が含まれており、コンポーネント間に図形の制約はありません (コンポーネントが1つだけであるため)。

これに対し、ソファ図形には、2つの図形コンポーネントと4つのシェイプ制約があります。 コンポーネントは、ユーザーのコンポーネントリスト内のインデックスによって識別されることに注意してください (この例では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 呼び出しで削除されるまで保持され、複数オブジェクトの制約付き配置が可能になります。

オブジェクト配置クエリは、パラメーターを含む配置の種類、規則の一覧、制約の一覧の 3 つの部分で構成されます。 クエリを実行するには、次の 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 つの Place On Floor クエリの結果が表示されます。

青いボックスには、"カメラの位置から離れる" ルールを含む 3 つの Place On Floor クエリの結果が表示されます。

ヒント:

  • レベルまたはアプリケーションのシナリオに必要な複数のオブジェクトの配置場所を解決する場合は、まず、スペースが見つかる確率を最大化するために、複雑なオブジェクトと大きなオブジェクトを解決します。
  • 配置順序は重要です。 オブジェクトの配置が見つからない場合は、制約の少ない構成を試してください。 フォールバック構成のセットを持つことは、多くの部屋構成で機能をサポートするために不可欠です。

レイ キャスト

3 つの主要なクエリに加えて、レイ キャスト インターフェイスを使用してタグ付けされたサーフェスの種類を取得し、カスタムの watertight プレイスペース メッシュをコピーできます。部屋をスキャンして終了した後、ラベルは、床、壁、壁のようなサーフェスに対して内部的に生成されます。 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;
     };

内部的には、レイキャストは、プレイスペースの計算された 8cm キューブボクセル表現に対して計算されます。 各ボクセルには、処理されたトポロジ データ (サーペルとも呼ばれる) を含むサーフェス要素のセットが含まれています。 交差するボクセル セル内に含まれるサーペルが比較され、トポロジ情報の検索に最適な一致が使用されます。 このトポロジ データには 、SurfaceTypes 列挙型の形式で返されるラベル付けと、交差するサーフェスの表面領域が含まれている。

Unity サンプルでは、カーソルによって各フレームに光線がキャストされます。 まず、Unity のコライダーに対して、2 つ目は、理解モジュールのワールド表現に対する。最後に、UI 要素に対して。 このアプリケーションでは、UI が優先順位を取得し、その結果を理解し、最後に Unity のコライダーを取得します。 SurfaceType は、カーソルの横にテキストとして報告されます。

レイキャスト結果レポートの交差部分とフロア。

レイキャスト結果レポートの交差部分とフロア。

コードの入手

オープン ソース コードは MixedRealityToolkit で使用できます。 プロジェクトでコードを使用する場合HoloLens開発者フォーラムでお知らせください。 それを使用して何を行うのかを見るのを待つ必要があります。

筆者について

Jeff Evertt, Software Engineering Lead at Microsoft Jeff Everttは、初期から開発経験まで、HoloLensに取り組むソフトウェア エンジニアリング のリードです。 以前HoloLens、Xbox Kinectやゲーム業界でさまざまなプラットフォームやゲームに取り組む。 Jeff は、ビープ音が鳴るフラッシュ ライトを使用したロボット工学、グラフィックス、および物に情熱を注ぐ。 彼は、新しいことを学び、ソフトウェア、ハードウェア、特に 2 つの交差する空間で作業を行っています。

関連項目