Unity の空間マッピングSpatial mapping in Unity

このトピックでは、Unity プロジェクトで 空間マッピング を使用する方法について説明します。また、HoloLens デバイスを中心にしたワールドの表面を表す三角形のメッシュを取得して、配置、閉鎖、ルーム分析などを行う方法について説明します。This topic describes how to use spatial mapping in your Unity project, retrieving triangle meshes that represent the surfaces in the world around a HoloLens device, for placement, occlusion, room analysis and more.

Unity には、次の方法で開発者に公開される空間マッピングの完全なサポートが含まれています。Unity includes full support for spatial mapping, which is exposed to developers in the following ways:

  1. MixedRealityToolkit で使用可能な空間マッピングコンポーネント。これは、空間マッピングを開始するための便利で迅速なパスを提供します。Spatial mapping components available in the MixedRealityToolkit, which provide a convenient and rapid path for getting started with spatial mapping
  2. フルコントロールを提供し、より高度なアプリケーション固有のカスタマイズを可能にする、下位レベルの空間マッピング ApiLower-level spatial mapping APIs, which provide full control and enable more sophisticated application specific customization

アプリで空間マッピングを使用するには、Package.appxmanifest で spatialPerception 機能を設定する必要があります。To use spatial mapping in your app, the spatialPerception capability needs to be set in your AppxManifest.

デバイス サポートDevice support

機能Feature HoloLens (第 1 世代)HoloLens (1st gen) HoloLens 2HoloLens 2 イマーシブ ヘッドセットImmersive headsets
空間マッピングSpatial mapping ✔️✔️ ✔️✔️

SpatialPerception 機能の設定Setting the SpatialPerception capability

アプリで空間マッピングデータを使用するためには、SpatialPerception 機能を有効にする必要があります。In order for an app to consume spatial mapping data, the SpatialPerception capability must be enabled.

SpatialPerception 機能を有効にする方法:How to enable the SpatialPerception capability:

  1. Unity エディターで、 [プレーヤーの設定 ] ウィンドウを開きます (> プロジェクトの設定を編集し > player)In the Unity Editor, open the "Player Settings" pane (Edit > Project Settings > Player)
  2. [ Windows ストア ] タブをクリックします。Click on the "Windows Store" tab
  3. [発行の設定] を展開し、 [機能] ボックスの一覧の "SpatialPerception" 機能を確認します。Expand "Publishing Settings" and check the "SpatialPerception" capability in the "Capabilities" list

既に Unity プロジェクトを Visual Studio ソリューションにエクスポートしている場合は、新しいフォルダーにエクスポートするか、 Visual studio の package.appxmanifest でこの機能を手動で設定する必要があることに注意してください。Note that if you have already exported your Unity project to a Visual Studio solution, you will need to either export to a new folder or manually set this capability in the AppxManifest in Visual Studio.

空間マッピングでは、少なくとも10.0.10586.0 の MaxVersionTested が必要です。Spatial mapping also requires a MaxVersionTested of at least 10.0.10586.0:

  1. Visual Studio でソリューションエクスプローラーで package.appxmanifest を右クリックし、[コードの表示] を選択し ます。In Visual Studio, right click on Package.appxmanifest in the Solution Explorer and select View Code
  2. TargetDeviceFamily を指定する行を探し、 maxversiontested = ""maxversiontested 済み = "10.0.10586.0" に変更します。Find the line specifying TargetDeviceFamily and change MaxVersionTested="10.0.10240.0" to MaxVersionTested="10.0.10586.0"
  3. Package.appxmanifest を 保存 します。Save the Package.appxmanifest.

Unity の組み込みの空間マッピングコンポーネントの概要Getting started with Unity's built-in spatial mapping components

Unity には、アプリに空間マッピングを簡単に追加するためのコンポーネントが2つ用意されています。空間マッピングの レンダラー空間マッピングの Collider です。Unity offers 2 components for easily adding spatial mapping to your app, Spatial Mapping Renderer and Spatial Mapping Collider.

空間マッピングレンダラーSpatial Mapping Renderer

空間マッピングレンダラーを使用すると、空間マッピングメッシュを視覚化できます。The Spatial Mapping Renderer allows for visualization of the spatial mapping mesh.

Unity の空間マッピングレンダラー

空間マッピング ColliderSpatial Mapping Collider

空間マッピングの Collider を使用すると、領域マッピングメッシュを使用して、物理などの holographic コンテンツ (または文字) の操作を行うことができます。The Spatial Mapping Collider allows for holographic content (or character) interaction, such as physics, with the spatial mapping mesh.

Unity の空間マッピング Collider

組み込みの空間マッピングコンポーネントの使用Using the built-in spatial mapping components

物理サーフェスを視覚化して操作する場合は、両方のコンポーネントをアプリに追加することができます。You may add both components to your app if you'd like to both visualize and interact with physical surfaces.

Unity アプリでこれらの2つのコンポーネントを使用するには、次の手順を実行します。To use these two components in your Unity app:

  1. 空間サーフェスメッシュを検出する領域の中央にある [ユーザー] オブジェクトを選択します。Select a GameObject at the center of the area in which you'd like to detect spatial surface meshes.
  2. [インスペクター] ウィンドウで、コンポーネント > XR > 空間マッピング Collider または 空間マッピングレンダラー を追加します。In the Inspector window, Add Component > XR > Spatial Mapping Collider or Spatial Mapping Renderer.

これらのコンポーネントの使用方法の詳細については、 Unity ドキュメントサイトを参照してください。You can find more details on how to use these components at the Unity documentation site.

組み込みの空間マッピングコンポーネント以外にGoing beyond the built-in spatial mapping components

これらのコンポーネントを使用すると、空間マッピングを簡単に開始できるように、ドラッグアンドドロップ操作を簡単に行うことができます。These components make it drag-and-drop easy to get started with Spatial Mapping. 詳細に進むには、次の2つの主要なパスを参照してください。When you want to go further, there are two main paths to explore:

  • 独自の下位レベルのメッシュ処理を行うには、以下の「低レベルの空間マッピングスクリプト API について」セクションを参照してください。To do your own lower-level mesh processing, see the section below about the low-level Spatial Mapping script API.
  • 上位レベルのメッシュ分析を行うには、 MixedRealityToolkitの SpatialUnderstanding ライブラリに関する以下のセクションを参照してください。To do higher-level mesh analysis, see the section below about the SpatialUnderstanding library in MixedRealityToolkit.

低レベルの Unity 空間マッピング API の使用Using the low-level Unity Spatial Mapping API

空間マッピングレンダラーコンポーネントと空間マッピング Collider コンポーネントから取得するよりも制御が必要な場合は、低レベルの空間マッピングスクリプト Api を使用できます。If you need more control than you get from the Spatial Mapping Renderer and Spatial Mapping Collider components, you can use the low-level Spatial Mapping script APIs.

名前空間: UNITYENGINE. XRNamespace: UnityEngine.XR.WSA
: SurfaceObserverSurfaceChangeSurfaceDataSurfaceIdTypes: SurfaceObserver, SurfaceChange, SurfaceData, SurfaceId

空間マッピング Api を使用するアプリケーションで推奨されるフローの概要を次に示します。The following is an outline of the suggested flow for an application that uses the spatial mapping APIs.

SurfaceObserver を設定するSet up the SurfaceObserver(s)

空間マッピングデータが必要な、アプリケーションで定義された領域の領域ごとに1つの SurfaceObserver オブジェクトをインスタンス化します。Instantiate one SurfaceObserver object for each application-defined region of space that you need spatial mapping data for.

SurfaceObserver surfaceObserver;

 void Start () {
     surfaceObserver = new SurfaceObserver();
 }

SetVolumeAsSphere、SetVolumeAsAxisAlignedBox、SetVolumeAsOrientedBox、または Setvolumeassphere を呼び出すことによって、各 SurfaceObserver オブジェクトがデータを提供する領域を指定します。Specify the region of space that each SurfaceObserver object will provide data for by calling either SetVolumeAsSphere, SetVolumeAsAxisAlignedBox, SetVolumeAsOrientedBox, or SetVolumeAsFrustum. これらのメソッドのいずれかを再度呼び出すだけで、後で領域の領域を再定義することができます。You can redefine the region of space in the future by simply calling one of these methods again.

void Start () {
    ...
     surfaceObserver.SetVolumeAsAxisAlignedBox(Vector3.zero, new Vector3(3, 3, 3));
}

SurfaceObserver () を呼び出す場合は、空間マッピングシステムに新しい情報が格納されている SurfaceObserver の領域領域の各空間サーフェスに対して、ハンドラーを提供する必要があります。When you call SurfaceObserver.Update(), you must provide a handler for each spatial surface in the SurfaceObserver's region of space that the spatial mapping system has new information for. このハンドラーは、1つの空間サーフェスに対してを受け取ります。The handler receives, for one spatial surface:

private void OnSurfaceChanged(SurfaceId surfaceId, SurfaceChange changeType, Bounds bounds, System.DateTime updateTime)
 {
    //see Handling Surface Changes
 }

サーフェイスの変更の処理Handling Surface Changes

処理する主なケースがいくつかあります。There are several main cases to handle. 同じコードパスを使用して削除することができる更新 & が追加されました。Added & Updated which can use the same code path and Removed.

  • この例で追加された & 更新されたケースでは、このメッシュを表す SurfaceData オブジェクトをディクショナリから追加または取得し、必要なコンポーネントを含む構造体を作成してから、RequestMeshDataAsync を呼び出して、シーン内のメッシュデータと位置を設定します。In the Added & Updated cases in the example, we add or get the GameObject representing this mesh from the dictionary, create a SurfaceData struct with the necessary components, then call RequestMeshDataAsync to populate the GameObject with the mesh data and position in the scene.
  • 削除された場合は、このメッシュを表すオブジェクトをディクショナリから削除し、破棄します。In the Removed case, we remove the GameObject representing this mesh from the dictionary and destroy it.
System.Collections.Generic.Dictionary<SurfaceId, GameObject> spatialMeshObjects = 
    new System.Collections.Generic.Dictionary<SurfaceId, GameObject>();

   private void OnSurfaceChanged(SurfaceId surfaceId, SurfaceChange changeType, Bounds bounds, System.DateTime updateTime)
   {
       switch (changeType)
       {
           case SurfaceChange.Added:
           case SurfaceChange.Updated:
               if (!spatialMeshObjects.ContainsKey(surfaceId))
               {
                   spatialMeshObjects[surfaceId] = new GameObject("spatial-mapping-" + surfaceId);
                   spatialMeshObjects[surfaceId].transform.parent = this.transform;
                   spatialMeshObjects[surfaceId].AddComponent<MeshRenderer>();
               }
               GameObject target = spatialMeshObjects[surfaceId];
               SurfaceData sd = new SurfaceData(
                   //the surface id returned from the system
                   surfaceId,
                   //the mesh filter that is populated with the spatial mapping data for this mesh
                   target.GetComponent<MeshFilter>() ?? target.AddComponent<MeshFilter>(),
                   //the world anchor used to position the spatial mapping mesh in the world
                   target.GetComponent<WorldAnchor>() ?? target.AddComponent<WorldAnchor>(),
                   //the mesh collider that is populated with collider data for this mesh, if true is passed to bakeMeshes below
                   target.GetComponent<MeshCollider>() ?? target.AddComponent<MeshCollider>(),
                   //triangles per cubic meter requested for this mesh
                   1000,
                   //bakeMeshes - if true, the mesh collider is populated, if false, the mesh collider is empty.
                   true
                   );

               SurfaceObserver.RequestMeshAsync(sd, OnDataReady);
               break;
           case SurfaceChange.Removed:
               var obj = spatialMeshObjects[surfaceId];
               spatialMeshObjects.Remove(surfaceId);
               if (obj != null)
               {
                   GameObject.Destroy(obj);
               }
               break;
           default:
               break;
       }
   }

データの準備完了Handling Data Ready

OnDataReady ハンドラーは、SurfaceData オブジェクトを受け取ります。The OnDataReady handler receives a SurfaceData object. WorldAnchor、MeshFilter、および (必要に応じて) MeshCollider オブジェクトには、関連付けられている空間サーフェスの最新の状態が反映されます。The WorldAnchor, MeshFilter and (optionally) MeshCollider objects it contains reflect the latest state of the associated spatial surface. 必要に応じて、MeshFilter オブジェクトのメッシュメンバーにアクセスして、メッシュデータの分析や 処理 を実行します。Optionally perform analysis and/or processing of the mesh data by accessing the Mesh member of the MeshFilter object. 最新のメッシュを使用して空間サーフェスをレンダリングし、必要に応じて物理衝突と raycasts に使用します。Render the spatial surface with the latest mesh and (optionally) use it for physics collisions and raycasts. SurfaceData の内容が null でないことを確認することが重要です。It's important to confirm that the contents of the SurfaceData are not null.

更新の処理を開始しますStart processing on updates

SurfaceObserver () は、すべてのフレームではなく、遅延時に呼び出す必要があります。SurfaceObserver.Update() should be called on a delay, not every frame.

void Start () {
    ...
     StartCoroutine(UpdateLoop());
}

 IEnumerator UpdateLoop()
    {
        var wait = new WaitForSeconds(2.5f);
        while(true)
        {
            surfaceObserver.Update(OnSurfaceChanged);
            yield return wait;
        }
    }

高レベルのメッシュ分析: SpatialUnderstandingHigher-level mesh analysis: SpatialUnderstanding

MixedRealityToolkitは、Holographic Unity api に基づいて構築された holographic 開発用の便利なユーティリティコードを集めたものです。The MixedRealityToolkit is a collection of helpful utility code for holographic development built upon the holographic Unity APIs.

空間の理解Spatial Understanding

物理的な世界にホログラムを配置するときは、多くの場合、空間マッピングのメッシュとサーフェス平面を超えることをお勧めします。When placing holograms in the physical world it is often desirable to go beyond spatial mapping’s mesh and surface planes. Procedurally の配置が完了したら、より高いレベルの環境を理解することをお勧めします。When placement is done procedurally, a higher level of environmental understanding is desirable. これには通常、floor、天井、および壁面の決定を行う必要があります。This usually requires making decisions about what is floor, ceiling, and walls. また、配置の制約のセットに対して最適化して、holographic オブジェクトにとって最も望ましい物理的な場所を決定することもできます。In addition, the ability to optimize against a set of placement constraints to determining the most desirable physical locations for holographic objects.

若い Conker とフラグメントの開発中に、Asobo スタジオはこの問題に直面し、この目的のための部屋のソルバーを開発していました。During the development of Young Conker and Fragments, Asobo Studios faced this problem head on, developing a room solver for this purpose. これらの各ゲームにはゲーム固有のニーズがありましたが、中心的な空間認識テクノロジを共有しています。Each of these games had game specific needs, but they shared core spatial understanding technology. HoloToolkit ライブラリは、このテクノロジをカプセル化しています。これにより、壁上の空のスペースをすばやく検索したり、オブジェクトを天井に配置したり、文字の位置を識別したり、その他の多くの空間を理解したりすることができます。The HoloToolkit.SpatialUnderstanding library encapsulates this technology, allowing you to quickly find empty spaces on the walls, place objects on the ceiling, identify placed for character to sit, and a myriad of other spatial understanding queries.

すべてのソースコードが含まれているので、ニーズに合わせてカスタマイズし、その機能強化をコミュニティと共有することができます。All of the source code is included, allowing you to customize it to your needs and share your improvements with the community. C++ ソルバーのコードは、UWP dll にラップされ、MixedRealityToolkit 内に含まれている drop in prefab を使用して Unity に公開されています。The code for the C++ solver has been wrapped into a UWP dll and exposed to Unity with a drop in prefab contained within the MixedRealityToolkit.

モジュールについてUnderstanding Modules

モジュールによって公開される3つの主要なインターフェイスは、単純な surface と空間クエリのトポロジ、オブジェクト検出のための図形、およびオブジェクトセットの配置に基づくオブジェクト配置ソルバーです。There are three primary interfaces exposed by the module: topology for simple surface and spatial queries, shape for object detection, and the object placement solver for constraint based placement of object sets. 以下で、これらのそれぞれについて説明します。Each of these is described below. 3つの主要なモジュールインターフェイスに加えて、射線のキャストインターフェイスを使用してタグ付きサーフェス型を取得し、カスタムの watertight playspace メッシュをコピーすることができます。In addition to the three primary module interfaces, a ray casting interface can be used to retrieve tagged surface types and a custom watertight playspace mesh can be copied out.

射線のキャストRay Casting

部屋がスキャンされ、完了すると、床、天井、壁などの表面にラベルが内部的に生成されます。After the room has been scanned and finalized, labels are internally generated for surfaces like the floor, ceiling, and walls. "PlayRaycastResult Eraycast" 関数は、射線を受け取り、光線が既知の表面と競合している場合は、その表面に関する情報を "" の形式で返します。The “PlayspaceRaycast” function takes a ray and returns if the ray collides with a known surface and if so, information about that surface in the form of a “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;
};

内部的には、raycast は、playspace の計算された8cm キューブ voxel 表現に対して計算されます。Internally, the raycast is computed against the computed 8cm cubed voxel representation of the playspace. 各 voxel には、処理されたトポロジデータを含む surface 要素のセットが含まれています (「」)。Each voxel contains a set of surface elements with processed topology data (aka surfels). 交差する voxel セルに含まれているが比較され、トポロジ情報の検索に使用される最適な一致が得られます。The surfels contained within the intersected voxel cell are compared and the best match used to look up the topology information. このトポロジデータには、"SurfaceTypes" 列挙型の形式で返されるラベルと、交差するサーフェイスの表面領域が含まれます。This topology data contains the labeling returned in the form of the “SurfaceTypes” enum, as well as the surface area of the intersected surface.

Unity のサンプルでは、カーソルは各フレームに射線をキャストします。In the Unity sample, the cursor casts a ray each frame. まず、Unity の colliders に対して行います。First, against Unity’s colliders. 2つ目は、モジュールのワールド表現を理解することです。Second, against the understanding module’s world representation. 最後に、UI 要素を繰り返します。And finally, again UI elements. このアプリケーションでは、UI の優先順位を取得し、結果を理解した後、Unity の colliders を取得します。In this application, UI gets priority, next the understanding result, and lastly, Unity’s colliders. SurfaceType は、カーソルの横にテキストとして報告されます。The SurfaceType is reported as text next to the cursor.

Surface の種類がカーソルの横に表示されるSurface type is labeled next to the cursor
Surface の種類がカーソルの横に表示されるSurface type is labeled next to the cursor

トポロジクエリTopology Queries

DLL 内では、トポロジマネージャーは環境のラベル付けを処理します。Within the DLL, the topology manager handles labeling of the environment. 前述のように、データの大部分は、voxel ボリューム内に含まれる、1つのデータに格納されます。As mentioned above, much of the data is stored within surfels, contained within a voxel volume. さらに、"Playspace 情報" 構造体は、再生スペースに関する情報を格納するために使用されます。これには、ワールドアラインメント (下記の詳細情報)、floor、および天井高さが含まれます。In addition, the “PlaySpaceInfos” structure is used to store information about the playspace, including the world alignment (more details on this below), floor, and ceiling height. ヒューリスティックは、floor、シーリング、および壁面を決定するために使用されます。Heuristics are used for determining floor, ceiling, and walls. たとえば、1 ~ 2 の範囲を超える水平方向サーフェイスは、床面と見なされます。For example, the largest and lowest horizontal surface with greater than 1 m2 surface area is considered the floor. このプロセスでは、スキャン処理中のカメラパスも使用されることに注意してください。Note that the camera path during the scanning process is also used in this process.

トポロジマネージャーによって公開されるクエリのサブセットは、dll を通じて公開されます。A subset of the queries exposed by the Topology manager are exposed out through the dll. 公開されているトポロジクエリは次のとおりです。The exposed topology queries are as follows.

QueryTopology_FindPositionsOnWalls
QueryTopology_FindLargePositionsOnWalls
QueryTopology_FindLargestWall
QueryTopology_FindPositionsOnFloor
QueryTopology_FindLargestPositionsOnFloor
QueryTopology_FindPositionsSittable

各クエリには、クエリの種類に固有のパラメーターのセットがあります。Each of the queries has a set of parameters, specific to the query type. 次の例では、必要なボリュームの最小の高さ & 幅、床の上の最小配置高さ、およびボリュームの前面にある最小のクリアランスの量をユーザーが指定しています。In the following example, the user specifies the minimum height & width of the desired volume, minimum placement height above the floor, and the minimum amount of clearance in front of the volume. すべての測定値は、メーターで計算されます。All measurements are in meters.

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" 構造体の事前に割り当てられた配列を受け取ります。Each of these queries takes a pre-allocated array of “TopologyResult” structures. "LocationCount" パラメーターは、渡された配列の長さを指定します。The “locationCount” parameter specifies the length of the passed in array. 戻り値は、返された場所の数を報告します。The return value reports the number of returned locations. この数は、渡された "locationCount" パラメーターよりも大きくありません。This number is never greater than the passed in “locationCount” parameter.

"TopologyResult" には、返されたボリュームの中央の位置、フェーシングの方向 (通常は)、および検出された領域のサイズが含まれます。The “TopologyResult” contains the center position of the returned volume, the facing direction (i.e. normal), and the dimensions of the found space.

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

Unity サンプルでは、これらの各クエリが仮想 UI パネルのボタンにリンクされていることに注意してください。Note that in the Unity sample, each of these queries is linked up to a button in the virtual UI panel. サンプルでは、これらの各クエリのパラメーターを妥当な値にハードコーディングしています。The sample hard codes the parameters for each of these queries to reasonable values. その他の例については、サンプルコードの SpaceVisualizer.cs を参照してください。See SpaceVisualizer.cs in the sample code for more examples.

クエリのシェイプShape Queries

Dll 内で、shape analyzer ("ShapeAnalyzer_W") は、トポロジアナライザーを使用して、ユーザーが定義したカスタム図形と照合します。Inside of the dll, the shape analyzer (“ShapeAnalyzer_W”) uses the topology analyzer to match against custom shapes defined by the user. Unity のサンプルでは、図形のセットを定義し、[図形] タブ内の [アプリ内クエリ] メニューを使用して結果を表示します。その目的は、ユーザーが独自のオブジェクト図形のクエリを定義し、アプリケーションの必要に応じてそれらを利用できるようにすることです。The Unity sample defines a set of shapes and exposes the results out through the in-app query menu, within the shape tab. The intention is that the user can define their own object shape queries and make use of those, as needed by their application.

図形の分析は、水平方向のサーフェイスでのみ動作することに注意してください。Note that the shape analysis works on horizontal surfaces only. たとえば、ソファは、平らな座席の表面とソファの上面によって定義されています。A couch, for example, is defined by the flat seat surface and the flat top of the couch back. Shape クエリでは、特定のサイズ、高さ、および縦横範囲の2つのサーフェスが検索され、2つのサーフェスがアラインされ、接続されています。The shape query looks for two surfaces of a specific size, height, and aspect range, with the two surfaces aligned and connected. Api の用語を使用して、ソファ座席と背面は形状コンポーネントであり、アラインメント要件はシェイプコンポーネントの制約です。Using the APIs terminology, the couch seat and back top are shape components and the alignment requirements are shape component constraints.

"Sittable" オブジェクトの Unity サンプル (ShapeDefinition.cs) で定義されているクエリの例を次に示します。An example query defined in the Unity sample (ShapeDefinition.cs), for “sittable” objects is as follows.

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

各図形クエリは、一連の図形コンポーネントによって定義されます。各図形コンポーネントには、一連のコンポーネント制約と、コンポーネント間の依存関係を示す一連の図形制約があります。Each shape query is defined by a set of shape components, each with a set of component constraints and a set of shape constraints which listing dependencies between the components. この例では、1つのコンポーネント定義に3つの制約が含まれており、コンポーネント間に図形の制約はありません (コンポーネントが1つだけであるため)。This example includes three constraints in a single component definition and no shape constraints between components (as there is only one component).

これに対し、ソファ図形には、2つの図形コンポーネントと4つのシェイプ制約があります。In contrast, the couch shape has two shape components and four shape constraints. コンポーネントは、ユーザーのコンポーネントリスト内のインデックスによって識別されることに注意してください (この例では0と 1)。Note that components are identified by their index in the user’s component list (0 and 1 in this example).

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 モジュールにラッパー関数が用意されています。Wrapper functions are provided in the Unity module for easy creation of custom shape definitions. コンポーネントとシェイプの制約の完全な一覧は、"ShapeComponentConstraint" 構造と "ShapeConstraint" 構造内の "SpatialUnderstandingDll.cs" にあります。The full list of component and shape constraints can be found in “SpatialUnderstandingDll.cs” within the “ShapeComponentConstraint” and the “ShapeConstraint” structures.

四角形の形状がこの画面にありますRectangle shape is found on this surface
四角形の形状がこの画面にありますRectangle shape is found on this surface

オブジェクト配置のソルバーObject Placement Solver

オブジェクト配置のソルバーを使用して、オブジェクトを配置する物理的な部屋内の理想的な場所を識別できます。The object placement solver can be used to identify ideal locations in the physical room to place your objects. ソルバーは、オブジェクトのルールと制約を指定して最適な場所を見つけます。The solver will find the best fit location given the object rules and constraints. また、オブジェクトクエリは、オブジェクトが "Solver_RemoveObject" または "Solver_RemoveAllObjects" の呼び出しで削除されるまで保持され、制約された複数オブジェクトの配置が可能になります。In addition, object queries persist until the object is removed with “Solver_RemoveObject” or “Solver_RemoveAllObjects” calls, allowing constrained multi-object placement. オブジェクト配置クエリは、3つの部分で構成されます。パラメーターを持つ配置の種類、規則の一覧、および制約の一覧です。Objects placement queries consist of three parts: placement type with parameters, a list of rules, and a list of constraints. クエリを実行するには、次の API を使用します。To run a query, use the following 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)

この関数は、オブジェクト名、配置定義、および規則と制約の一覧を受け取ります。This function takes an object name, placement definition, and a list of rules and constraints. C# ラッパーは、規則と制約の構築を簡単にするための構築ヘルパー関数を提供します。The C# wrappers provides construction helper functions to make rule and constraint construction easy. 配置定義には、次のいずれかのクエリの種類が含まれます。The placement definition contains the query type – that is, one of the following.

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

各配置型には、型に固有のパラメーターのセットがあります。Each of the placement types has a set of parameters unique to the type. "ObjectPlacementDefinition" 構造体には、これらの定義を作成するための静的ヘルパー関数のセットが含まれています。The “ObjectPlacementDefinition” structure contains a set of static helper functions for creating these definitions. たとえば、床にオブジェクトを配置する場所を見つけるには、次の関数を使用します。For example, to find a place to put an object on the floor, you can use the following function. public static Objectplacement Ementdefinition Create_OnFloor (Vector3 半 Dims) 配置の種類に加えて、一連のルールと制約を指定することができます。public static ObjectPlacementDefinition Create_OnFloor(Vector3 halfDims) In addition to the placement type, you can provide a set of rules and constraints. 規則に違反することはありません。Rules cannot be violated. 型とルールを満たす配置場所は、最適な配置場所を選択するために、一連の制約に対して最適化されます。Possible placement locations that satisfy the type and rules are then optimized against the set of constraints in order to select the optimal placement location. 各ルールと制約は、指定された静的作成関数によって作成できます。Each of the rules and constraints can be created by the provided static creation functions. ルールと制約の構築関数の例を以下に示します。An example rule and constraint construction function is provided below.

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

次のオブジェクト配置クエリは、表面の端に半分のメーターキューブを配置する場所を探しています。これは、以前に配置された他のオブジェクトから、部屋の中心付近に向かっています。The below object placement query is looking for a place to put a half meter cube on the edge of a surface, away from other previously place objects and near the center of the room.

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

成功した場合、配置位置、次元、および向きを含む "Objectplacement Ementresult" 構造体が返されます。If successful, a “ObjectPlacementResult” structure containing the placement position, dimensions and orientation is returned. また、配置は、配置されたオブジェクトの dll の内部リストに追加されます。In addition, the placement is added to the dll’s internal list of placed objects. 後続の配置クエリでは、このオブジェクトが考慮されます。Subsequent placement queries will take this object into account. Unity サンプルの "LevelSolver.cs" ファイルには、クエリの例が多数含まれています。The “LevelSolver.cs” file in the Unity sample contains more example queries.

オブジェクトの配置の結果Results of object placement
図 3: 青色のボックスを使用して、カメラの位置ルールから離れた場所にあるフロアクエリの結果を確認するFigure 3: The blue boxes how the result from three place on floor queries with away from camera position rules

レベルまたはアプリケーションのシナリオで必要とされる複数のオブジェクトの配置場所を解決する場合、は、領域が見つかる確率を最大化するために、最初に不可欠なオブジェクトとラージオブジェクトを解決します。When solving for placement location of multiple objects required for a level or application scenario, first solve indispensable and large objects in order to maximizing the probability that a space can be found. 配置順序は重要です。Placement order is important. オブジェクトの配置が見つからない場合は、制限の少ない構成を試してください。If object placements cannot be found, try less constrained configurations. 一連のフォールバック構成を設定することは、多くの部屋構成で機能をサポートするために不可欠です。Having a set of fallback configurations is critical to supporting functionality across many room configurations.

ルームスキャンプロセスRoom Scanning Process

HoloLens によって提供される空間マッピングソリューションは、問題のある領域全体のニーズに対応できるように設計されていますが、空間認識モジュールは、2つの特定のゲームのニーズをサポートするように構築されています。While the spatial mapping solution provided by the HoloLens is designed to be generic enough to meet the needs of the entire gamut of problem spaces, the spatial understanding module was built to support the needs of two specific games. このソリューションは、次に示すように、特定のプロセスと想定のセットに基づいて構築されています。Its solution is structured around a specific process and set of assumptions, summarized below.

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.

ユーザー駆動型の playspace "描画" –スキャンフェーズ中に、ユーザーは再生速度を移動して、必要な領域を効果的に描画します。User driven playspace “painting” – During the scanning phase, the user moves and looks around the plays pace, effectively painting the areas which should be included. 生成されたメッシュは、このフェーズでユーザーからのフィードバックを提供するために重要です。The generated mesh is important to provide user feedback during this phase. 屋内で home または office セットアップ–クエリ関数は、フラットなサーフェイスと壁面を中心に設計されています。Indoors home or office setup – The query functions are designed around flat surfaces and walls at right angles. これは、ソフトな制限です。This is a soft limitation. ただし、スキャンフェーズでは、主要軸と補助軸に沿ってメッシュテセレーションを最適化するために、主軸分析が完了します。However, during the scanning phase, a primary axis analysis is completed to optimize the mesh tessellation along major and minor axis. 含まれている SpatialUnderstanding.cs ファイルは、スキャンフェーズプロセスを管理します。The included SpatialUnderstanding.cs file manages the scanning phase process. 次の関数を呼び出します。It calls the following functions.

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 を呼び出し、その後、各フレームに対してアップデートを実行します。The scanning flow, driven by the “SpatialUnderstanding” behavior calls InitScan, then UpdateScan each frame. 統計クエリによって適切なカバレッジが報告されると、ユーザーは、ユーザーが RequestFinish を呼び出して、スキャンフェーズの終了を示すことができます。When the statistics query reports reasonable coverage, the user is allowed to airtap to call RequestFinish to indicate the end of the scanning phase. 戻り値が dll の処理を完了したことを示すまで、アップデートを引き続き呼び出すことができます。UpdateScan continues to be called until it’s return value indicates that the dll has completed processing.

メッシュについてUnderstanding Mesh

Dll を理解すると、内部的に再生スペースが8cm サイズの voxel キューブのグリッドとして格納されます。The understanding dll internally stores the playspace as a grid of 8cm sized voxel cubes. スキャンの初期部分では、主要なコンポーネント分析が完了して、部屋の軸が決定されます。During the initial part of scanning, a primary component analysis is completed to determine the axes of the room. 内部的には、これらの軸に合わせて voxel 領域を格納します。Internally, it stores its voxel space aligned to these axes. メッシュは、voxel ボリュームから isosurface を抽出することによって、約1秒ごとに生成されます。A mesh is generated approximately every second by extracting the isosurface from the voxel volume.

Voxel ボリュームから生成されたメッシュを生成しましたGenerated mesh produced from the voxel volume
Voxel ボリュームから生成されたメッシュを生成しましたGenerated mesh produced from the voxel volume

トラブルシューティングTroubleshooting

  • SpatialPerception機能が設定されていることを確認します。Ensure you have set the SpatialPerception capability
  • 追跡が失われると、次の OnSurfaceChanged イベントによってすべてのメッシュが削除されます。When tracking is lost, the next OnSurfaceChanged event will remove all meshes.

混合 Reality ツールキットでの空間マッピングSpatial Mapping in Mixed Reality Toolkit

混合 Reality Toolkit v2 での空間マッピングの使用の詳細については、MRTK ドキュメントの「 空間認識」セクション を参照してください。For more information on using Spatial Mapping with Mixed Reality Toolkit v2, see the Spatial Awareness section of the MRTK docs.

次の開発チェックポイントNext Development Checkpoint

私たちが用意した Unity 開発チェックポイント体験に従っている場合、読者は MRTK コア構成要素を探索している段階にいます。If you're following the Unity development checkpoint journey we've laid out, you're in the midst of exploring the MRTK core building blocks. ここから、次の構成要素に進むことができます。From here, you can proceed to the next building block:

または、Mixed Reality プラットフォームの機能と API に移動します。Or jump to Mixed Reality platform capabilities and APIs:

いつでも Unity 開発チェックポイントに戻ることができます。You can always go back to the Unity development checkpoints at any time.

関連項目See also