DirectX での空間のマッピングSpatial mapping in DirectX

このトピックでは、実装する方法を説明します空間マッピングDirectX アプリでします。This topic describes how to implement spatial mapping in your DirectX app. これには、ユニバーサル Windows プラットフォーム SDK に含まれている空間マッピングのサンプル アプリケーションの詳細な説明が含まれます。This includes a detailed explanation of the spatial mapping sample application that is included with the Universal Windows Platform SDK.

このトピックではコードを使用、 HolographicSpatialMapping UWP のコード サンプル。This topic uses code from the HolographicSpatialMapping UWP code sample.

注意

この記事のコード スニペットは現在の使用を示すC++/CX ではなく c++ 17 に準拠していませんC++/WinRT で使用するため、 C++ holographic プロジェクト テンプレートします。The code snippets in this article currently demonstrate use of C++/CX rather than C++17-compliant C++/WinRT as used in the C++ holographic project template. 概念は、同等のC++/WinRT のプロジェクトがコードに変換する必要があります。The concepts are equivalent for a C++/WinRT project, though you will need to translate the code.

DirectX の開発の概要DirectX development overview

空間マッピング用のネイティブ アプリケーションの開発は、Api を使用して、 Windows.Perception.Spatial名前空間。Native application development for spatial mapping uses the APIs under the Windows.Perception.Spatial namespace. これらの Api は空間マッピングによって公開される Api を直接と同様の方法では、空間マッピング機能のフル コントロールを提供Unityします。These APIs provide full control of spatial mapping functionality, in a manner directly analogous to the spatial mapping APIs exposed by Unity.

認識 ApiPerception APIs

空間マッピングの開発用の主な種類は次のとおりです。The primary types provided for spatial mapping development are as follows:

  • SpatialSurfaceObserver SpatialSurfaceInfo オブジェクトの形式で、ユーザーの近くの領域のアプリケーションで指定されたリージョンでの画面について説明します。SpatialSurfaceObserver provides information about surfaces in application-specified regions of space near the user, in the form of SpatialSurfaceInfo objects.
  • SpatialSurfaceInfo単一既存空間のサーフェス、一意の ID を含む、境界のボリュームと最終変更時刻をについて説明します。SpatialSurfaceInfo describes a single extant spatial surface, including a unique ID, bounding volume and time of last change. 要求時に非同期的の SpatialSurfaceMesh が提供されます。It will provide a SpatialSurfaceMesh asynchronously upon request.
  • SpatialSurfaceMeshOptions SpatialSurfaceInfo から要求された SpatialSurfaceMesh オブジェクトのカスタマイズに使用されるパラメーターが含まれています。SpatialSurfaceMeshOptions contains parameters used to customize the SpatialSurfaceMesh objects requested from SpatialSurfaceInfo.
  • SpatialSurfaceMeshメッシュ データを 1 つの空間サーフェスを表します。SpatialSurfaceMesh represents the mesh data for a single spatial surface. 頂点の位置、頂点の法線と三角形のインデックスのデータは、メンバー SpatialSurfaceMeshBuffer オブジェクトに含まれます。The data for vertex positions, vertex normals and triangle indices is contained in member SpatialSurfaceMeshBuffer objects.
  • SpatialSurfaceMeshBufferメッシュのデータの 1 つの型をラップします。SpatialSurfaceMeshBuffer wraps a single type of mesh data.

これらの Api を使用してアプリケーションを開発する場合は、(以下で説明するサンプル アプリケーションで説明します)、このよう基本的なプログラム フローが表示されます。When developing an application using these APIs, your basic program flow will look like this (as demonstrated in the sample application described below):

  • 設定する、SpatialSurfaceObserverSet up your SpatialSurfaceObserver
    • 呼び出すRequestAccessAsyncユーザーがデバイスの空間のマッピング機能を使用するアプリケーションのアクセス許可を割り当てられているようにしてください。Call RequestAccessAsync, to ensure that the user has given permission for your application to use the device's spatial mapping capabilities.
    • SpatialSurfaceObserver オブジェクトをインスタンス化します。Instantiate a SpatialSurfaceObserver object.
    • 呼び出すSetBoundingVolumes空間サーフェスに関する情報を挿入するスペースの領域を指定します。Call SetBoundingVolumes to specify the regions of space in which you want information about spatial surfaces. もう一度この関数を呼び出すだけで、将来これらのリージョンを変更することがあります。You may modify these regions in the future by simply calling this function again. 使用して各リージョンを指定するSpatialBoundingVolumeします。Each region is specified using a SpatialBoundingVolume.
    • 登録、 ObservedSurfacesChangedイベントで、新しい情報が指定した領域のリージョン内の空間のサーフェスについて利用可能なときに起動されます。Register for the ObservedSurfacesChanged event, which will fire whenever new information is available about the spatial surfaces in the regions of space you have specified.
  • ObservedSurfacesChanged イベントを処理します。Process ObservedSurfacesChanged events
    • イベント ハンドラーで呼び出すGetObservedSurfaces SpatialSurfaceInfo オブジェクトのマップを受信します。In your event handler, call GetObservedSurfaces to receive a map of SpatialSurfaceInfo objects. このマップを使用して、空間サーフェスのレコードを更新することができます、ユーザーの環境に存在します。Using this map, you can update your records of which spatial surfaces exist in the user's environment.
    • 照会することがあります、SpatialSurfaceInfo オブジェクトごとにTryGetBoundsで表される、サーフェイス上の空間のエクステントを判断する、空間座標系独自の。For each SpatialSurfaceInfo object, you may query TryGetBounds to determine the spatial extents of the surface, expressed in a spatial coordinate system of your choosing.
    • 空間画面用のメッシュを要求する場合は、呼び出すTryComputeLatestMeshAsyncします。If you decide to request mesh for a spatial surface, call TryComputeLatestMeshAsync. 三角形の目的、密度とメッシュが返されるデータの形式を指定するオプションを指定することがあります。You may provide options specifying the desired density of triangles, and the format of the returned mesh data.
  • 受信および処理メッシュReceive and process mesh
    • TryComputeLatestMeshAsync は aysnchronously に対する各呼び出しは、1 つの SpatialSurfaceMesh オブジェクトを返します。Each call to TryComputeLatestMeshAsync will aysnchronously return one SpatialSurfaceMesh object.
    • このオブジェクトから三角形のインデックス、頂点の位置にアクセスするには含まれている SpatialSurfaceMeshBuffer オブジェクトにアクセスすることができます (要求) 場合、メッシュの頂点の法線。From this object you can access the contained SpatialSurfaceMeshBuffer objects in order to access the triangle indices, vertex positions and (if requested) vertex normals of the mesh. このデータは直接互換性のある形式になります、 direct3d11 の Apiメッシュの描画に使用します。This data will be in a format directly compatible with the Direct3D 11 APIs used for rendering meshes.
    • ここから、アプリケーションは必要に応じて分析を実行または処理メッシュのデータの使用とレンダリングと物理法則レイキャストと衝突From here your application can optionally perform analysis or processing of the mesh data, and use it for rendering and physics raycasting and collision.
    • 注意する 1 つの重要な詳細は、(たとえば、メッシュをレンダリングするために使用される頂点シェーダー) にメッシュの頂点の位置に、スケールを適用する必要があります、それらが格納されている、バッファー内に最適化された整数単位からそれらを変換するための新旧従量課金のことです。One important detail to note is that you must apply a scale to the mesh vertex positions (for example in the vertex shader used for rendering the meshes), to convert them from the optimized integer units in which they are stored in the buffer, to meters. このスケールを取得するには呼び出すことによってVertexPositionScaleします。You can retrieve this scale by calling VertexPositionScale.

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

空間マッピングのコード サンプルのチュートリアルSpatial Mapping code sample walkthrough

Holographic 空間マッピングコード サンプルには、管理するためのインフラストラクチャを含む、アプリへの表面メッシュの読み込みを開始する際し、レンダリング サーフェイス メッシュ コードが含まれています。The Holographic Spatial Mapping code sample includes code that you can use to get started loading surface meshes into your app, including infrastructure for managing and rendering surface meshes.

次に、DirectX アプリに画面のマップ機能を追加する手順について説明します。Now, we walk through how to add surface mapping capability to your DirectX app. このコードを追加することができます、アプリ テンプレートを Windows Holographic上記で説明したコード サンプルを参照して、プロジェクト、またはするに従うことができます。You can add this code to your Windows Holographic app template project, or you can follow along by browsing through the code sample mentioned above. このコード サンプルは、Windows Holographic のアプリ テンプレートに基づきます。This code sample is based on the Windows Holographic app template.

SpatialPerception 機能を使用するアプリをセットアップします。Set up your app to use the spatialPerception capability

アプリは、空間のマッピング機能を使用できる必要があります。Your app must be able to use the spatial mapping capability. これは、機能は、空間メッシュ プライベート データを検討できるユーザーの環境の表現であるため、必要です。This is necessary because the spatial mesh is a representation of the user's environment, which may be considered private data. アプリの package.appxmanifest ファイルでこの機能を宣言します。Declare this capability in the package.appxmanifest file for your app. 次に例を示します。Here's an example:

<Capabilities>
  <uap2:Capability Name="spatialPerception" />
</Capabilities>

機能に由来しますuap2名前空間。The capability comes from the uap2 namespace. マニフェストでこの名前空間へのアクセスを取得するには、それを含める、 xlmns属性、<パッケージ > 要素。To get access to this namespace in your manifest, include it as an xlmns attribute in the <Package> element. 次に例を示します。Here's an example:

<Package
    xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
    xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
    xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
    xmlns:uap2="http://schemas.microsoft.com/appx/manifest/uap/windows10/2"
    IgnorableNamespaces="uap uap2 mp"
    >

空間マッピング機能のサポートを確認します。Check for spatial mapping feature support

Windows Mixed Reality は、さまざまな空間マッピングがサポートされていないデバイスを含め、デバイスをサポートします。Windows Mixed Reality supports a wide range of devices, including devices which do not support spatial mapping. アプリは、空間のマッピングを使用することができますまたは機能を提供する空間のマッピングを使用する必要があります、これを使用する前に、空間マッピングがサポートされているかどうかを確認ください。If your app can use spatial mapping, or must use spatial mapping, to provide functionality, it should check to make sure that spatial mapping is supported before trying to use it. たとえば、空間マッピングは、mixed reality アプリで必要な場合メッセージが表示、それに対応するユーザーは、空間のマッピングがないデバイスで実行しようとするとします。For example, if spatial mapping is required by your mixed reality app, it should display a message to that effect if a user tries running it on a device without spatial mapping. または、アプリがユーザーの環境では、空間マッピングが使用可能な場合に何が起こるようなエクスペリエンスを提供する代わりに、独自の仮想環境を表示することができます。Or, your app may be able to render its own virtual environment in place of the user's environment, providing an experience that is similar to what would happen if spatial mapping were available. いずれの場合も、この API といない空間マッピング データを取得し、適切な方法で応答を認識するため、アプリを使用できます。In any event, this API allows your app to be aware of when it will not get spatial mapping data and respond in the appropriate way.

空間マッピング サポートを現在のデバイスを確認するには、最初に、UWP のコントラクトは、4 以上のレベルで確認してから SpatialSurfaceObserver::IsSupported() を呼び出します。To check the current device for spatial mapping support, first make sure the UWP contract is at level 4 or greater and then call SpatialSurfaceObserver::IsSupported(). コンテキストで実行するには、 Holographic 空間マッピングコード サンプル。Here's how to do so in the context of the Holographic Spatial Mapping code sample. サポートは、アクセスを要求する前にチェックされます。Support is checked just before requesting access.

SpatialSurfaceObserver::IsSupported() API では、SDK バージョン 15063 以降で使用できます。The SpatialSurfaceObserver::IsSupported() API is available starting in SDK version 15063. 必要に応じて、この API を使用する前にプラットフォームのバージョン 15063 プロジェクトの再ターゲットします。If necessary, retarget your project to platform version 15063 before using this API.

if (m_surfaceObserver == nullptr)
   {
       using namespace Windows::Foundation::Metadata;
       if (ApiInformation::IsApiContractPresent(L"Windows.Foundation.UniversalApiContract", 4))
       {
           if (!SpatialSurfaceObserver::IsSupported())
           {
               // The current system does not have spatial mapping capability.
               // Turn off spatial mapping.
               m_spatialPerceptionAccessRequested = true;
               m_surfaceAccessAllowed = false;
           }
       }

       if (!m_spatialPerceptionAccessRequested)
       {
           /// etc ...

ある UWP コントラクトがレベル 4 より小さい場合は、アプリを続行する、デバイスは空間マッピング処理を実行できるように注意してください。Note that when the UWP contract is less than level 4, the app should proceed as though the device is capable of doing spatial mapping.

空間マッピング データへのアクセスを要求します。Request access to spatial mapping data

アプリは、任意の画面のオブザーバーを作成する前に、空間マッピングのデータにアクセスする許可を要求する必要があります。Your app needs to request permission to access spatial mapping data before trying to create any surface observers. 詳細については後でこのページで提供されると、画面のマッピング コード サンプルに基づく例を次に示します。Here's an example based upon our Surface Mapping code sample, with more details provided later on this page:

auto initSurfaceObserverTask = create_task(SpatialSurfaceObserver::RequestAccessAsync());
initSurfaceObserverTask.then([this, coordinateSystem](Windows::Perception::Spatial::SpatialPerceptionAccessStatus status)
{
    if (status == SpatialPerceptionAccessStatus::Allowed)
    {
        // Create a surface observer.
    }
    else
    {
        // Handle spatial mapping unavailable.
    }
}

画面のオブザーバーを作成します。Create a surface observer

Windows::Perception::Spatial::Surfaces名前空間が含まれています、 SpatialSurfaceObserverクラスで指定した 1 つまたは複数のボリュームの監視、 SpatialCoordinateSystemします。The Windows::Perception::Spatial::Surfaces namespace includes the SpatialSurfaceObserver class, which observes one or more volumes that you specify in a SpatialCoordinateSystem. 使用して、 SpatialSurfaceObserverなる表面メッシュをリアルタイムでデータにアクセスするインスタンス。Use a SpatialSurfaceObserver instance to access surface mesh data in real time.

AppMain.h:From AppMain.h:

// Obtains surface mapping data from the device in real time.
Windows::Perception::Spatial::Surfaces::SpatialSurfaceObserver^     m_surfaceObserver;
Windows::Perception::Spatial::Surfaces::SpatialSurfaceMeshOptions^  m_surfaceMeshOptions;

前述の前のセクションは、アプリで使用できる前に、空間マッピング データへのアクセスを要求する必要があります。As noted in the previous section, you must request access to spatial mapping data before your app can use it. このアクセスは、HoloLens で自動的に付与されます。This access is granted automatically on the HoloLens.

// The surface mapping API reads information about the user's environment. The user must
// grant permission to the app to use this capability of the Windows Mixed Reality device.
auto initSurfaceObserverTask = create_task(SpatialSurfaceObserver::RequestAccessAsync());
initSurfaceObserverTask.then([this, coordinateSystem](Windows::Perception::Spatial::SpatialPerceptionAccessStatus status)
{
    if (status == SpatialPerceptionAccessStatus::Allowed)
    {
        // If status is allowed, we can create the surface observer.
        m_surfaceObserver = ref new SpatialSurfaceObserver();

次に、境界の特定のボリュームを観察する表面のオブザーバーを構成する必要があります。Next, you need to configure the surface observer to observe a specific bounding volume. ここでは、20 x 20 x 5 メーター、座標系の原点を中心とするボックスを確認します。Here, we observe a box that is 20x20x5 meters, centered at the origin of the coordinate system.

// The surface observer can now be configured as needed.

        // In this example, we specify one area to be observed using an axis-aligned
        // bounding box 20 meters in width and 5 meters in height and centered at the
        // origin.
        SpatialBoundingBox aabb =
        {
            { 0.f,  0.f, 0.f },
            {20.f, 20.f, 5.f },
        };

        SpatialBoundingVolume^ bounds = SpatialBoundingVolume::FromBox(coordinateSystem, aabb);
        m_surfaceObserver->SetBoundingVolume(bounds);

複数の外接するボリュームを代わりに設定できることに注意してください。Note that you can set multiple bounding volumes instead.

これは、擬似コードです。This is pseudocode:

m_surfaceObserver->SetBoundingVolumes(/* iterable collection of bounding volumes*/);

ビューの視錐台などの他の外接する図形を使用することもまたはは軸ではない境界ボックスが配置されます。It is also possible to use other bounding shapes - such as a view frustum, or a bounding box that is not axis aligned.

これは、擬似コードです。This is pseudocode:

m_surfaceObserver->SetBoundingVolume(
            SpatialBoundingVolume::FromFrustum(/*SpatialCoordinateSystem*/, /*SpatialBoundingFrustum*/)
            );

場合に応答するコードを記述することができますが異なる方法で何も行うサーフェスのマッピング データが利用できない場合、アプリが必要な場合で、 SpatialPerceptionAccessStatusでない許可- たとえば、できなく Pc で没入型のデバイスをそれらのデバイスは空間マッピングのハードウェアがあるないため、接続されているとします。If your app needs to do anything differently when surface mapping data is not available, you can write code to respond to the case where the SpatialPerceptionAccessStatus is not Allowed - for example, it will not be allowed on PCs with immersive devices attached because those devices don't have hardware for spatial mapping. これらのデバイスの代わりに、空間ステージについては、ユーザーの環境とデバイスの構成に依存する必要があります。For these devices, you should instead rely on the spatial stage for information about the user's environment and device configuration.

初期化し、なる表面メッシュ コレクションの更新Initialize and update the surface mesh collection

Surface のオブザーバーが正常に作成すると場合、は、表面メッシュ コレクションを初期化するために進むことができます。If the surface observer was successfully created, we can proceed to initialize our surface mesh collection. ここでは、監視対象のサーフェスの現在のセットをすぐに取得するのに、プル モデルの API を使用します。Here, we use the pull model API to get the current set of observed surfaces right away:

auto mapContainingSurfaceCollection = m_surfaceObserver->GetObservedSurfaces();
        for (auto& pair : mapContainingSurfaceCollection)
        {
            // Store the ID and metadata for each surface.
            auto const& id = pair->Key;
            auto const& surfaceInfo = pair->Value;
            m_meshCollection->AddOrUpdateSurface(id, surfaceInfo);
        }

表面メッシュのデータの取得に使用可能なプッシュ モデルもあります。There is also a push model available to get surface mesh data. 自由にアプリを設計する場合をポーリングするデータを頻繁に、選択した場合、プル モデルのみを使用すると答えると、または特定の期間中に、フレームごとに 1 回など、ゲームのセットアップ中にします。You are free to design your app to use only the pull model if you choose, in which case you'll poll for data every so often - say, once per frame - or during a specific time period, such as during game setup. そうである場合、上記のコードは必要なものには。If so, the above code is what you need.

コード サンプルでは、教育目的では、両方のモデルの使用を示すために選択しました。In our code sample, we chose to demonstrate the use of both models for pedagogical purposes. ここでは、システムは、変更を認識するたびに、表面メッシュを最新の状態データを受信するイベントに定期受信します。Here, we subscribe to an event to receive up-to-date surface mesh data whenever the system recognizes a change.

m_surfaceObserver->ObservedSurfacesChanged += ref new TypedEventHandler<SpatialSurfaceObserver^, Platform::Object^>(
            bind(&HolographicDesktopAppMain::OnSurfacesChanged, this, _1, _2)
            );

コード サンプルは、これらのイベントに応答することも構成されます。Our code sample is also configured to respond to these events. その方法を見てみましょう。Let's walk through how we do this.

注: これによって、メッシュのデータを処理するアプリの最も効率的な方法ができない可能性があります。NOTE: This might not be the most efficient way for your app to handle mesh data. このコードでは、わかりやすくするためが書き込まれ、最適化されていません。This code is written for clarity and is not optimized.

読み取り専用マップを格納する表面メッシュのデータが提供されるSpatialSurfaceInfoオブジェクトを使用してPlatform::Guidsキー値として。The surface mesh data is provided in a read-only map that stores SpatialSurfaceInfo objects using Platform::Guids as key values.

IMapView<Guid, SpatialSurfaceInfo^>^ const& surfaceCollection = sender->GetObservedSurfaces();

このデータを処理するには、コレクション内ではないキー値の最初の項目について説明します。To process this data, we look first for key values that aren't in our collection. このサンプル アプリでデータを格納する方法の詳細については、このトピックの「表示されます。Details on how the data is stored in our sample app will be presented later in this topic.

// Process surface adds and updates.
for (const auto& pair : surfaceCollection)
{
    auto id = pair->Key;
    auto surfaceInfo = pair->Value;

    if (m_meshCollection->HasSurface(id))
    {
        // Update existing surface.
        m_meshCollection->AddOrUpdateSurface(id, surfaceInfo);
    }
    else
    {
        // New surface.
        m_meshCollection->AddOrUpdateSurface(id, surfaceInfo);
    }
}

また、表面メッシュ、表面メッシュ コレクション内にあるが、今後のシステム コレクションにないを削除する必要があります。We also have to remove surface meshes that are in our surface mesh collection, but that aren't in the system collection anymore. これを行うにはここで紹介を追加すると、メッシュ; の更新の反対のようなもの必要があります。アプリのコレクションを確認する場合にループ処理、 Guidがあるがシステム コレクション内にします。To do so, we need to do something akin to the opposite of what we just showed for adding and updating meshes; we loop on our app's collection, and check to see if the Guid we have is in the system collection. システム コレクションにない場合は都合から削除します。If it's not in the system collection, we remove it from ours.

AppMain.cpp でイベント ハンドラー: からFrom our event handler in AppMain.cpp:

m_meshCollection->PruneMeshCollection(surfaceCollection);

RealtimeSurfaceMeshRenderer.cpp でメッシュの排除の実装:The implementation of mesh pruning in RealtimeSurfaceMeshRenderer.cpp:

void RealtimeSurfaceMeshRenderer::PruneMeshCollection(IMapView<Guid, SpatialSurfaceInfo^>^ const& surfaceCollection)
{
    std::lock_guard<std::mutex> guard(m_meshCollectionLock);
    std::vector<Guid> idsToRemove;

    // Remove surfaces that moved out of the culling frustum or no longer exist.
    for (const auto& pair : m_meshCollection)
    {
        const auto& id = pair.first;
        if (!surfaceCollection->HasKey(id))
        {
            idsToRemove.push_back(id);
        }
    }

    for (const auto& id : idsToRemove)
    {
        m_meshCollection.erase(id);
    }
}

取得し、なる表面メッシュ データ バッファーの使用Acquire and use surface mesh data buffers

表面メッシュ情報を取得することは、データ コレクションを取得し、そのコレクションの更新の処理と同じくらい簡単でした。Getting the surface mesh information was as easy as pulling a data collection and processing updates to that collection. ここで詳しく説明します詳細データを使用する方法。Now, we'll go into detail on how you can use the data.

このコード例では、レンダリングの表面メッシュを使用する選択しました。In our code example, we chose to use the surface meshes for rendering. これは、現実世界のサーフェスの背後にあるホログラムが他の一般的なシナリオです。This is a common scenario for occluding holograms behind real-world surfaces. メッシュをレンダリングまたは処理されたバージョンを表示できますが、ルームがのどの領域をユーザーに表示するアプリやゲームの機能の提供を開始する前にスキャンされます。You can also render the meshes, or render processed versions of them, to show the user what areas of the room are scanned before you start providing app or game functionality.

コード サンプルは、前のセクションで説明したイベント ハンドラーからなる表面メッシュの更新プログラムを受信したときに、プロセスを開始します。The code sample starts the process when it receives surface mesh updates from the event handler that we described in the previous section. この関数のコードの重要な行は、サーフェイスを更新する呼び出しメッシュ: この時点までが既に処理されたメッシュの情報とに応じて、使用するため、頂点とインデックスのデータを取得しようとしています。The important line of code in this function is the call to update the surface mesh: by this time we have already processed the mesh info, and we are about to get the vertex and index data for use as we see fit.

RealtimeSurfaceMeshRenderer.cpp: からFrom RealtimeSurfaceMeshRenderer.cpp:

void RealtimeSurfaceMeshRenderer::AddOrUpdateSurface(Guid id, SpatialSurfaceInfo^ newSurface)
{
    auto options = ref new SpatialSurfaceMeshOptions();
    options->IncludeVertexNormals = true;

    auto createMeshTask = create_task(newSurface->TryComputeLatestMeshAsync(1000, options));
    createMeshTask.then([this, id](SpatialSurfaceMesh^ mesh)
    {
        if (mesh != nullptr)
        {
            std::lock_guard<std::mutex> guard(m_meshCollectionLock);
            '''m_meshCollection[id].UpdateSurface(mesh);'''
        }
    }, task_continuation_context::use_current());
}

サンプル コードが設計されていますように、データ クラスSurfaceMesh、ハンドル メッシュのデータ処理および表示します。Our sample code is designed so that a data class, SurfaceMesh, handles mesh data processing and rendering. これらのメッシュはどのようなRealtimeSurfaceMeshRendererのマップを実際に保持します。These meshes are what the RealtimeSurfaceMeshRenderer actually keeps a map of. 1 つずつは送信元 SpatialSurfaceMesh への参照を備え、メッシュの頂点またはインデックス バッファーにアクセスしたり、メッシュの変換を取得する必要がある任意の時間を使用します。Each one has a reference to the SpatialSurfaceMesh it came from, and we use it any time that we need to access the mesh vertex or index buffers, or get a transform for the mesh. ここで、更新プログラムを必要とすると、メッシュをフラグです。For now, we flag the mesh as needing an update.

SurfaceMesh.cpp: からFrom SurfaceMesh.cpp:

void SurfaceMesh::UpdateSurface(SpatialSurfaceMesh^ surfaceMesh)
{
    m_surfaceMesh = surfaceMesh;
    m_updateNeeded = true;
}

次回、メッシュが自身を描画するように求めは、フラグまず確認します。Next time the mesh is asked to draw itself, it will check the flag first. 更新プログラムが必要な場合は、GPU で頂点とインデックス バッファーが更新されます。If an update is needed, the vertex and index buffers will be updated on the GPU.

void SurfaceMesh::CreateDeviceDependentResources(ID3D11Device* device)
{
    m_indexCount = m_surfaceMesh->TriangleIndices->ElementCount;
    if (m_indexCount < 3)
    {
        // Not enough indices to draw a triangle.
        return;
    }

最初に、生データ バッファーを取得します。First, we acquire the raw data buffers:

Windows::Storage::Streams::IBuffer^ positions = m_surfaceMesh->VertexPositions->Data;
    Windows::Storage::Streams::IBuffer^ normals   = m_surfaceMesh->VertexNormals->Data;
    Windows::Storage::Streams::IBuffer^ indices   = m_surfaceMesh->TriangleIndices->Data;

次に、Direct3D デバイス バッファーを作成、HoloLens によって提供されるメッシュ データ。Then, we create Direct3D device buffers with the mesh data provided by the HoloLens:

CreateDirectXBuffer(device, D3D11_BIND_VERTEX_BUFFER, positions, m_vertexPositions.GetAddressOf());
    CreateDirectXBuffer(device, D3D11_BIND_VERTEX_BUFFER, normals,   m_vertexNormals.GetAddressOf());
    CreateDirectXBuffer(device, D3D11_BIND_INDEX_BUFFER,  indices,   m_triangleIndices.GetAddressOf());

    // Create a constant buffer to control mesh position.
    CD3D11_BUFFER_DESC constantBufferDesc(sizeof(SurfaceTransforms), D3D11_BIND_CONSTANT_BUFFER);
    DX::ThrowIfFailed(
        device->CreateBuffer(
            &constantBufferDesc,
            nullptr,
            &m_modelTransformBuffer
            )
        );

    m_loadingComplete = true;
}

注: 前のスニペットで使用される、CreateDirectXBuffer ヘルパー関数では、画面のマッピングのコード サンプルを参照してください。SurfaceMesh.cpp、GetDataFromIBuffer.h します。NOTE: For the CreateDirectXBuffer helper function used in the previous snippet, see the Surface Mapping code sample: SurfaceMesh.cpp, GetDataFromIBuffer.h. これで、デバイス リソースの作成が完了して、メッシュが読み込まれ、更新プログラムの準備をして、表示すると見なされます。Now the device resource creation is complete, and the mesh is considered to be loaded and ready for update and render.

更新し、表面メッシュをレンダリングします。Update and render surface meshes

SurfaceMesh クラスでは、特殊化された update 関数があります。Our SurfaceMesh class has a specialized update function. SpatialSurfaceMesh独自の変換を備え、サンプルの現在の座標系を使用する、 SpatialStationaryReferenceFrame変換を取得します。Each SpatialSurfaceMesh has its own transform, and our sample uses the current coordinate system for our SpatialStationaryReferenceFrame to acquire the transform. GPU 上でモデルの定数バッファーを更新します。Then it updates the model constant buffer on the GPU.

void SurfaceMesh::UpdateTransform(
    ID3D11DeviceContext* context,
    SpatialCoordinateSystem^ baseCoordinateSystem
    )
{
    if (m_indexCount < 3)
    {
        // Not enough indices to draw a triangle.
        return;
    }

    XMMATRIX transform = XMMatrixIdentity();

    auto tryTransform = m_surfaceMesh->CoordinateSystem->TryGetTransformTo(baseCoordinateSystem);
    if (tryTransform != nullptr)
    {
        transform = XMLoadFloat4x4(&tryTransform->Value);
    }

    XMMATRIX scaleTransform = XMMatrixScalingFromVector(XMLoadFloat3(&m_surfaceMesh->VertexPositionScale));

    XMStoreFloat4x4(
        &m_constantBufferData.vertexWorldTransform,
        XMMatrixTranspose(
            scaleTransform * transform
            )
        );

    // Normals don't need to be translated.
    XMMATRIX normalTransform = transform;
    normalTransform.r[3] = XMVectorSet(0.f, 0.f, 0.f, XMVectorGetW(normalTransform.r[3]));
    XMStoreFloat4x4(
        &m_constantBufferData.normalWorldTransform,
        XMMatrixTranspose(
            normalTransform
        )
        );

    if (!m_loadingComplete)
    {
        return;
    }

    context->UpdateSubresource(
        m_modelTransformBuffer.Get(),
        0,
        NULL,
        &m_constantBufferData,
        0,
        0
        );
}

表面メッシュをレンダリングするときは、ときに、コレクションを表示する前に、いくつかの準備作業を行います。When it's time to render surface meshes, we do some prep work before rendering the collection. 現在の表示構成のシェーダーのパイプラインを設定し、入力アセンブラー ステージを設定します。We set up the shader pipeline for the current rendering configuration, and we set up the input assembler stage. なお、holographic カメラ ヘルパー クラスCameraResources.cpp /ビューのプロジェクション定数バッファーをここまでで既に設定が。Note that the holographic camera helper class CameraResources.cpp already has set up the view/projection constant buffer by now.

RealtimeSurfaceMeshRenderer::Render:From RealtimeSurfaceMeshRenderer::Render:

auto context = m_deviceResources->GetD3DDeviceContext();

context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
context->IASetInputLayout(m_inputLayout.Get());

// Attach our vertex shader.
context->VSSetShader(
    m_vertexShader.Get(),
    nullptr,
    0
    );

// The constant buffer is per-mesh, and will be set as such.

if (depthOnly)
{
    // Explicitly detach the later shader stages.
    context->GSSetShader(nullptr, nullptr, 0);
    context->PSSetShader(nullptr, nullptr, 0);
}
else
{
    if (!m_usingVprtShaders)
    {
        // Attach the passthrough geometry shader.
        context->GSSetShader(
            m_geometryShader.Get(),
            nullptr,
            0
            );
    }

    // Attach our pixel shader.
    context->PSSetShader(
        m_pixelShader.Get(),
        nullptr,
        0
        );
}

これが完了すると、メッシュにループを自体を描画するために 1 つずつに伝えます。Once this is done, we loop on our meshes and tell each one to draw itself. 注: 何らかの視錐台カリングを使用するこのサンプル コードが最適化されていないが、アプリでこの機能を含める必要があります。NOTE: This sample code is not optimized to use any sort of frustum culling, but you should include this feature in your app.

std::lock_guard<std::mutex> guard(m_meshCollectionLock);

auto device = m_deviceResources->GetD3DDevice();

// Draw the meshes.
for (auto& pair : m_meshCollection)
{
    auto& id = pair.first;
    auto& surfaceMesh = pair.second;

    surfaceMesh.Draw(device, context, m_usingVprtShaders, isStereo);
}

個々 のメッシュは、頂点とインデックス バッファー、stride、およびモデル変換定数バッファーを設定します。The individual meshes are responsible for setting up the vertex and index buffer, stride, and model transform constant buffer. 同様に、Windows Holographic のアプリケーション テンプレートで回転するキューブ、インスタンス化を使用してステレオスコ ピックのバッファーを表示します。As with the spinning cube in the Windows Holographic app template, we render to stereoscopic buffers using instancing.

SurfaceMesh::Draw:From SurfaceMesh::Draw:

// The vertices are provided in {vertex, normal} format

const auto& vertexStride = m_surfaceMesh->VertexPositions->Stride;
const auto& normalStride = m_surfaceMesh->VertexNormals->Stride;

UINT strides [] = { vertexStride, normalStride };
UINT offsets [] = { 0, 0 };
ID3D11Buffer* buffers [] = { m_vertexPositions.Get(), m_vertexNormals.Get() };

context->IASetVertexBuffers(
    0,
    ARRAYSIZE(buffers),
    buffers,
    strides,
    offsets
    );

const auto& indexFormat = static_cast<DXGI_FORMAT>(m_surfaceMesh->TriangleIndices->Format);

context->IASetIndexBuffer(
    m_triangleIndices.Get(),
    indexFormat,
    0
    );

context->VSSetConstantBuffers(
    0,
    1,
    m_modelTransformBuffer.GetAddressOf()
    );

if (!usingVprtShaders)
{
    context->GSSetConstantBuffers(
        0,
        1,
        m_modelTransformBuffer.GetAddressOf()
        );
}

context->PSSetConstantBuffers(
    0,
    1,
    m_modelTransformBuffer.GetAddressOf()
    );

context->DrawIndexedInstanced(
    m_indexCount,       // Index count per instance.
    isStereo ? 2 : 1,   // Instance count.
    0,                  // Start index location.
    0,                  // Base vertex location.
    0                   // Start instance location.
    );

画面のマッピングの選択肢を表示Rendering choices with Surface Mapping

画面のマッピングのコード サンプルには、表面メッシュのデータのレンダリングをオクルー ジョン専用となる表面メッシュのデータの表示が画面に表示されるコードが用意されています。The Surface Mapping code sample offers code for occlusion-only rendering of surface mesh data, and for on-screen rendering of surface mesh data. パスを選ぶかまたは両方がアプリケーションに依存します。Which path you choose - or both - depends on your application. このドキュメントで両方の構成を説明します。We'll walk through both configurations in this document.

Holographic 効果のレンダリング オクルー ジョン バッファーRendering occlusion buffers for holographic effect

現在、仮想カメラのレンダー ターゲット ビューをオフにして開始します。Start by clearing the render target view for the current virtual camera.

AppMain.cpp: からFrom AppMain.cpp:

context->ClearRenderTargetView(pCameraResources->GetBackBufferRenderTargetView(), DirectX::Colors::Transparent);

これは、「プリレンダ リング」パスです。This is a "pre-rendering" pass. ここでは、深さのみを表示するために、メッシュ レンダラーを要求することによって、オクルー ジョン バッファーを作成します。Here, we create an occlusion buffer by asking the mesh renderer to render only depth. この構成では、レンダー ターゲット ビューを接続せず、メッシュ レンダラーでは、ピクセル シェーダーのステージを設定nullptrピクセルを描画するために、GPU をわざわざしないようにします。In this configuration, we don't attach a render target view, and the mesh renderer sets the pixel shader stage to nullptr so that the GPU doesn't bother to draw pixels. ジオメトリを深度バッファーにラスタライズして、グラフィックス パイプラインの停止があります。The geometry will be rasterized to the depth buffer, and the graphics pipeline will stop there.

// Pre-pass rendering: Create occlusion buffer from Surface Mapping data.
context->ClearDepthStencilView(pCameraResources->GetSurfaceDepthStencilView(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

// Set the render target to null, and set the depth target occlusion buffer.
// We will use this same buffer as a shader resource when drawing holograms.
context->OMSetRenderTargets(0, nullptr, pCameraResources->GetSurfaceOcclusionDepthStencilView());

// The first pass is a depth-only pass that generates an occlusion buffer we can use to know which
// hologram pixels are hidden behind surfaces in the environment.
m_meshCollection->Render(pCameraResources->IsRenderingStereoscopic(), true);

ホログラムとオクルー ジョンのマッピングの画面バッファーに対する追加の深度テスト描画できます。We can draw holograms with an extra depth test against the Surface Mapping occlusion buffer. このコード サンプルでレンダリング キューブ上のピクセルを別の色、画面の背面にある場合。In this code sample, we render pixels on the cube a different color if they are behind a surface.

AppMain.cpp: からFrom AppMain.cpp:

// Hologram rendering pass: Draw holographic content.
context->ClearDepthStencilView(pCameraResources->GetHologramDepthStencilView(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

// Set the render target, and set the depth target drawing buffer.
ID3D11RenderTargetView *const targets[1] = { pCameraResources->GetBackBufferRenderTargetView() };
context->OMSetRenderTargets(1, targets, pCameraResources->GetHologramDepthStencilView());

// Render the scene objects.
// In this example, we draw a special effect that uses the occlusion buffer we generated in the
// Pre-Pass step to render holograms using X-Ray Vision when they are behind physical objects.
m_xrayCubeRenderer->Render(
    pCameraResources->IsRenderingStereoscopic(),
    pCameraResources->GetSurfaceOcclusionShaderResourceView(),
    pCameraResources->GetHologramOcclusionShaderResourceView(),
    pCameraResources->GetDepthTextureSamplerState()
    );

SpecialEffectPixelShader.hlsl からコードに基づいています。Based on code from SpecialEffectPixelShader.hlsl:

// Draw boundaries
min16int surfaceSum = GatherDepthLess(envDepthTex, uniSamp, input.pos.xy, pixelDepth, input.idx.x);

if (surfaceSum <= -maxSum)
{
    // The pixel and its neighbors are behind the surface.
    // Return the occluded 'X-ray' color.
    return min16float4(0.67f, 0.f, 0.f, 1.0f);
}
else if (surfaceSum < maxSum)
{
    // The pixel and its neighbors are a mix of in front of and behind the surface.
    // Return the silhouette edge color.
    return min16float4(1.f, 1.f, 1.f, 1.0f);
}
else
{
    // The pixel and its neighbors are all in front of the surface.
    // Return the color of the hologram.
    return min16float4(input.color, 1.0f);
}

注: GatherDepthLessルーチン、画面のマッピングのコード サンプルを参照してください。SpecialEffectPixelShader.hlsl します。Note: For our GatherDepthLess routine, see the Surface Mapping code sample: SpecialEffectPixelShader.hlsl.

表示になる表面メッシュ データのレンダリングRendering surface mesh data to the display

表面メッシュだけでもステレオ表示バッファーに描画できます。We can also just draw the surface meshes to the stereo display buffers. ライティング、完全な面を描画することにしましたが、自由ワイヤー フレームを描画、レンダリングの前にメッシュの処理、テクスチャ マップでは、適用および具合にします。We chose to draw full faces with lighting, but you're free to draw wireframe, process meshes before rendering, apply a texture map, and so on.

ここでは、コード サンプルは、コレクションを描画するために、メッシュ レンダラーを指示します。Here, our code sample tells the mesh renderer to draw the collection. この時間ピクセル シェーダーをアタッチし、現在の仮想のカメラの指定したターゲットを使用してレンダリング パイプラインを完了するため、深さのみのパスの場合を指定しますはありません。This time we don't specify a depth-only pass, so it will attach a pixel shader and complete the rendering pipeline using the targets that we specified for the current virtual camera.

// SR mesh rendering pass: Draw SR mesh over the world.
context->ClearDepthStencilView(pCameraResources->GetSurfaceOcclusionDepthStencilView(), D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

// Set the render target to the current holographic camera's back buffer, and set the depth buffer.
ID3D11RenderTargetView *const targets[1] = { pCameraResources->GetBackBufferRenderTargetView() };
context->OMSetRenderTargets(1, targets, pCameraResources->GetSurfaceDepthStencilView());

// This drawing pass renders the surface meshes to the stereoscopic display. The user will be
// able to see them while wearing the device.
m_meshCollection->Render(pCameraResources->IsRenderingStereoscopic(), false);

関連項目See also