Távoli holografikus távoli alkalmazás írása a HolographicSpace API használatával

Ha még csak most szeretné elhozni a Holographic Remotingot, olvassa el az áttekintést.

Fontos

Ez a dokumentum egy távoli alkalmazás létrehozását ismerteti a 2. HoloLens-hez a HolographicSpace API használatával. A távoli alkalmazásoknak HoloLens (1. generációs) a NuGet-csomag 1.x.x verzióját kell használniuk. Ez azt jelenti, hogy a 2. HoloLens írt távoli alkalmazások nem kompatibilisek az 1 HoloLens és fordítva. Az 1 HoloLens dokumentációját itt találhatja.

A holografikus távelérésű alkalmazások távolról renderelt tartalmakat streamelnek HoloLens 2. Windows Mixed Reality modern headsetek segítségével. Emellett több rendszererőforrást is elérheti, és távoli modern nézeteket integrálhat a meglévő asztali PC-szoftverekbe. A távoli alkalmazások bemeneti adatfolyamot kapnak a 2. HoloLens-től, egy virtuális modern nézetben renderelik a tartalmat, és a tartalomkereteket a 2. HoloLens streamelik. A kapcsolat a standard Wi-Fi használatával létesítve. A Holographic Remoting egy NuGet-csomaggal van hozzáadva egy asztali vagy UWP-alkalmazáshoz. További kódra van szükség, amely kezeli a kapcsolatot, és egy modern nézetben jelenik meg. Egy tipikus elotolási kapcsolat akár 50 ms késéssel is rendelkezik. A lejátszóalkalmazás valós időben képes jelenteni a késést.

Az oldalon található összes kód és munkaprojekt megtalálható a Holographic Remoting minta github-adattárában.

Előfeltételek

Jó kiindulási pont lehet egy működő DirectX-alapú asztali vagy UWP-alkalmazás, amely a Windows Mixed Reality API-t célozza. Részletekért lásd: A DirectX-fejlesztés áttekintése. A C++ holografikus projektsablon jó kiindulási pont.

Fontos

A Holographic Remotingot használó alkalmazásokat többszálas rendszer használatára kell használni. Az egyszálas tokok használata támogatott, de az optimálisnál nem optimális teljesítményt eredményez, és a lejátszás során akár meg is akad. C++/WinRT winrt::init_apartment az alapértelmezett többszálas rendszer.

A Holographic remoting NuGet-csomag lekért része

A NuGet-csomag projekthez való hozzáadásához a következő lépések szükségesek a Visual Studio.

  1. Nyissa meg a projektet a Visual Studióban.
  2. Kattintson a jobb gombbal a projektcsomópontra, és válassza a Manage NuGet Packages... (NuGet-csomagok kezelése... lehetőséget)
  3. A megjelenő panelen válassza a Tallózás lehetőséget, majd keressen a "Holographic Remoting" kifejezésre.
  4. Válassza a Microsoft.Holographic.Remotinglehetőséget, válassza ki a legújabb 2.x.x verziót, és válassza az Install (Telepítés) lehetőséget.
  5. Ha megjelenik az Előnézet párbeszédpanel, kattintson az OK gombra.
  6. Válassza az Elfogadom lehetőséget, amikor megjelenik a licencszerződés párbeszédpanel.

Megjegyzés

A NuGet-csomag 1.x.x verziója továbbra is elérhető az 1-es verzióra HoloLens fejlesztők számára. Részletekért lásd: Holographic Remoting (HoloLens (1. generációs)).

A távoli környezet létrehozása

Első lépésként az alkalmazásnak létre kell hoznia egy távoli környezetet.

// class declaration
#include <winrt/Microsoft.Holographic.AppRemoting.h>

...

private:
    // RemoteContext used to connect with a Holographic Remoting player and display rendered frames
    winrt::Microsoft::Holographic::AppRemoting::RemoteContext m_remoteContext = nullptr;
// class implementation
#include <HolographicAppRemoting\Streamer.h>

...

CreateRemoteContext(m_remoteContext, 20000, false, PreferredVideoCodec::Default);

Figyelmeztetés

A Holographic Remoting úgy működik, hogy a Windows Mixed Reality-Windows részét képezi, és egy adott futásidejű rendszernek ad vissza. Ez a távoli környezet létrehozása során történik. Emiatt a távoli környezet létrehozása Windows Mixed Reality api-k bármilyen hívása váratlan viselkedést eredményezhet. Az ajánlott módszer a távoli környezet lehető leghamarabb történő létrehozása, mielőtt bármilyen api-val Mixed Reality interakciót. Windows Mixed Reality A CreateRemoteContext hívása előtt soha ne keverje a CreateRemoteContext api-n keresztül létrehozott vagy lekért objektumokat az ezt követően létrehozott vagy lekért objektumokkal.

Ezután létre kell hozva a holografikus területet. A CoreWindow megadása nem kötelező. A CoreWindow-t nem használó asztali alkalmazások egyszerűen átadhatnak egy nullptr -et.

m_holographicSpace = winrt::Windows::Graphics::Holographic::HolographicSpace::CreateForCoreWindow(nullptr);

Csatlakozás az eszközhöz

Ha a távoli alkalmazás készen áll a tartalom megjelenítésére, létrejön egy kapcsolat a lejátszóeszközhöz.

A kapcsolat kétféleképpen létesíthet kapcsolatot.

  1. A távoli alkalmazás csatlakozik az eszközön futó lejátszóhoz.
  2. Az eszközön futó lejátszó csatlakozik a távoli alkalmazáshoz.

Ha kapcsolatot létesíteni a távoli alkalmazás és a lejátszóeszköz között, hívja meg a metódust a távoli környezetben, és adja meg az Connect állomásnevet és a portot. A Holographic Remoting Player által használt port a 8265.

try
{
    m_remoteContext.Connect(m_hostname, m_port);
}
catch(winrt::hresult_error& e)
{
    DebugLog(L"Connect failed with hr = 0x%08X", e.code());
}

Fontos

Mint minden C++/WinRT API, itt is előfordulhat Connect winrt::hresult_error, amelyet kezelni kell.

Tipp

A C++/WinRT nyelvi leképezés használatának elkerülése érdekében a Holographic Remoting NuGet-csomagban található fájl is megtalálható. A mögöttes COM-felületek deklarációit tartalmazza. A C++/WinRT használata azonban ajánlott.

A távoli alkalmazás bejövő kapcsolatainak figyelése a metódus hívásával Listen történik. A hívás során a kézfogási port és az átviteli port is meg lehet adni. A kézfogási port a kezdeti kézfogáshoz használatos. Az adatokat ezután a rendszer a szállítási porton keresztül küldi el. Alapértelmezés szerint a rendszer a 8265-ös és a 8266-os értéket használja.

try
{
    m_remoteContext.Listen(L"0.0.0.0", m_port, m_port + 1);
}
catch(winrt::hresult_error& e)
{
    DebugLog(L"Listen failed with hr = 0x%08X", e.code());
}

Fontos

A NuGet-csomagon belüli része részletes dokumentációt tartalmaz a Holographic Remoting által elérhetővéált build\native\include\HolographicAppRemoting\Microsoft.Holographic.AppRemoting.idl API-hoz.

Adott események eltolásának kezelése

A távoli környezet három eseményt felfed, amelyek fontosak a kapcsolat állapotának figyelése során.

  1. OnConnected: Akkor aktiválódik, ha sikeresen létrejött a kapcsolat az eszközzel.
winrt::weak_ref<winrt::Microsoft::Holographic::AppRemoting::IRemoteContext> remoteContextWeakRef = m_remoteContext;

m_onConnectedEventRevoker = m_remoteContext.OnConnected(winrt::auto_revoke, [this, remoteContextWeakRef]() {
    if (auto remoteContext = remoteContextWeakRef.get())
    {
        // Update UI state
    }
});
  1. OnDisconnected: Akkor aktiválódik, ha egy létrehozott kapcsolat be van zárva, vagy nem sikerült létrehozni a kapcsolatot.
m_onDisconnectedEventRevoker =
    m_remoteContext.OnDisconnected(winrt::auto_revoke, [this, remoteContextWeakRef](ConnectionFailureReason failureReason) {
        if (auto remoteContext = remoteContextWeakRef.get())
        {
            DebugLog(L"Disconnected with reason %d", failureReason);
            // Update UI

            // Reconnect if this is a transient failure.
            if (failureReason == ConnectionFailureReason::HandshakeUnreachable ||
                failureReason == ConnectionFailureReason::TransportUnreachable ||
                failureReason == ConnectionFailureReason::ConnectionLost)
            {
                DebugLog(L"Reconnecting...");

                ConnectOrListen();
            }
            // Failure reason None indicates a normal disconnect.
            else if (failureReason != ConnectionFailureReason::None)
            {
                DebugLog(L"Disconnected with unrecoverable error, not attempting to reconnect.");
            }
        }
    });
  1. OnListening: A bejövő kapcsolatok figyelése elindul.
m_onListeningEventRevoker = m_remoteContext.OnListening(winrt::auto_revoke, [this, remoteContextWeakRef]() {
    if (auto remoteContext = remoteContextWeakRef.get())
    {
        // Update UI state
    }
});

A kapcsolat állapota a távoli környezet tulajdonságával ConnectionState is lekérdezhető.

auto connectionState = m_remoteContext.ConnectionState();

Beszédesemények kezelése

A távoli beszédfelület használatával beszédindítókat regisztrálhat a 2. HoloLens-ben, és távolról is elindíthatja őket a távoli alkalmazáshoz.

Ez a további tag szükséges a távoli beszéd állapotának nyomon követéséhez.

winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker m_onRecognizedSpeechRevoker;

Először olvassa be a távoli beszédfelületet.

if (auto remoteSpeech = m_remoteContext.GetRemoteSpeech())
{
    InitializeSpeechAsync(remoteSpeech, m_onRecognizedSpeechRevoker, weak_from_this());
}

Ezután egy aszinkron segítő metódussal inicializálhatja a távoli beszédet. Ezt aszinkron módon kell tenni, mivel az inicializálás jelentős időt is eltelhet. A C++/WinRT-sel való egyidejűség és aszinkron műveletek ismertetik, hogyan lehet aszinkron függvényeket a C++/WinRT használatával összeírni.

winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::StorageFile> LoadGrammarFileAsync()
{
    const wchar_t* speechGrammarFile = L"SpeechGrammar.xml";
    auto rootFolder = winrt::Windows::ApplicationModel::Package::Current().InstalledLocation();
    return rootFolder.GetFileAsync(speechGrammarFile);
}

winrt::fire_and_forget InitializeSpeechAsync(
    winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech remoteSpeech,
    winrt::Microsoft::Holographic::AppRemoting::IRemoteSpeech::OnRecognizedSpeech_revoker& onRecognizedSpeechRevoker,
    std::weak_ptr<SampleRemoteMain> sampleRemoteMainWeak)
{
    onRecognizedSpeechRevoker = remoteSpeech.OnRecognizedSpeech(
        winrt::auto_revoke, [sampleRemoteMainWeak](const winrt::Microsoft::Holographic::AppRemoting::RecognizedSpeech& recognizedSpeech) {
            if (auto sampleRemoteMain = sampleRemoteMainWeak.lock())
            {
                sampleRemoteMain->OnRecognizedSpeech(recognizedSpeech.RecognizedText);
            }
        });

    auto grammarFile = co_await LoadGrammarFileAsync();

    std::vector<winrt::hstring> dictionary;
    dictionary.push_back(L"Red");
    dictionary.push_back(L"Blue");
    dictionary.push_back(L"Green");
    dictionary.push_back(L"Default");
    dictionary.push_back(L"Aquamarine");

    remoteSpeech.ApplyParameters(L"", grammarFile, dictionary);
}

A felismerni kívánt kifejezések megadásának két módja van.

  1. Specifikáció egy beszéd nyelvtani XML-fájljában. Részletekért lásd: Alapszintű XML-nyelvtan létrehozása.
  2. Adja meg a értéket úgy, hogy a szótárvektorban adja át őket a ApplyParameters parancsnak.

Az OnRecognizedSpeech visszahíváson belül a beszédesemények ezután feldolgozhatóak:

void SampleRemoteMain::OnRecognizedSpeech(const winrt::hstring& recognizedText)
{
    bool changedColor = false;
    DirectX::XMFLOAT4 color = {1, 1, 1, 1};

    if (recognizedText == L"Red")
    {
        color = {1, 0, 0, 1};
        changedColor = true;
    }
    else if (recognizedText == L"Blue")
    {
        color = {0, 0, 1, 1};
        changedColor = true;
    }
    else if (recognizedText == L"Green")
    {
        ...
    }

    ...
}

Streamelési tartalom helyi előnézete

Ha ugyanazt a tartalmat jeleníti meg a távoli alkalmazásban, amely az eszközre van küldve, a távoli környezet OnSendFrame eseménye használható. Az esemény minden alkalommal aktiválódik, amikor a Holographic távelérési kódtár elküldi az aktuális keretet OnSendFrame a távoli eszköznek. Ez az ideális időpont a tartalom asztali vagy UWP-ablakba való bekeretzétlére.

#include <windows.graphics.directx.direct3d11.interop.h>

...

m_onSendFrameEventRevoker = m_remoteContext.OnSendFrame(
    winrt::auto_revoke, [this](const winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DSurface& texture) {
        winrt::com_ptr<ID3D11Texture2D> texturePtr;
        {
            winrt::com_ptr<ID3D11Resource> resource;
            winrt::com_ptr<::IInspectable> inspectable = texture.as<::IInspectable>();
            winrt::com_ptr<Windows::Graphics::DirectX::Direct3D11::IDirect3DDxgiInterfaceAccess> dxgiInterfaceAccess;
            winrt::check_hresult(inspectable->QueryInterface(__uuidof(dxgiInterfaceAccess), dxgiInterfaceAccess.put_void()));
            winrt::check_hresult(dxgiInterfaceAccess->GetInterface(__uuidof(resource), resource.put_void()));
            resource.as(texturePtr);
        }

        // Copy / blit texturePtr into the back buffer here.
    });

Mélységi reprodukálás

A 2.1.0-s verziótól kezdődőena Holographic Remoting támogatja a Depth Reprojection parancsokat. Ehhez a színpuffert és a mélységi puffert is streamelni kell a távoli alkalmazásból a 2. HoloLens tárolóba. Alapértelmezés szerint a mélységi pufferstreamelés engedélyezve van, és úgy van konfigurálva, hogy a színpuffer felbontásának felét használja. Ez a következőképpen módosítható:

// class implementation
#include <HolographicAppRemoting\Streamer.h>

...

CreateRemoteContext(m_remoteContext, 20000, false, PreferredVideoCodec::Default);

// Configure for half-resolution depth.
m_remoteContext.ConfigureDepthVideoStream(DepthBufferStreamResolution::Half_Resolution);

Vegye figyelembe, hogy ha az alapértelmezett értékeket nem szabad használni, a 2. kapcsolat létrehozása előtt meg kell HoloLens ConfigureDepthVideoStream használni. A legjobb hely közvetlenül a távoli környezet létrehozása után. A DepthBufferStreamResolution lehetséges értékei:

  • Full_Resolution
  • Half_Resolution
  • Quarter_Resolution
  • Letiltva (a 2.1.3-as verzióval bővült, és ha nincs további mélységű videóstream létrehozva)

Ne feledje, hogy a teljes feloldási mélységű puffer használata hatással van a sávszélességre vonatkozó követelményekre is, és figyelembe kell vennie a számára megadott maximális CreateRemoteContext sávszélesség-értéket.

A felbontás konfigurálása mellett egy mélységi puffert is végleges kell véglegesítésre a HolographicCameraRenderingParameters.CommitDirect3D11DepthBuffer segítségével.


void SampleRemoteMain::Render(HolographicFrame holographicFrame)
{
    ...

    m_deviceResources->UseHolographicCameraResources([this, holographicFrame](auto& cameraResourceMap) {
        
		...

        for (auto cameraPose : prediction.CameraPoses())
        {
            DXHelper::CameraResources* pCameraResources = cameraResourceMap[cameraPose.HolographicCamera().Id()].get();

            ...

            m_deviceResources->UseD3DDeviceContext([&](ID3D11DeviceContext3* context) {
                
                ...

                // Commit depth buffer if available and enabled.
                if (m_canCommitDirect3D11DepthBuffer && m_commitDirect3D11DepthBuffer)
                {
                    auto interopSurface = pCameraResources->GetDepthStencilTextureInteropObject();
                    HolographicCameraRenderingParameters renderingParameters = holographicFrame.GetRenderingParameters(cameraPose);
                    renderingParameters.CommitDirect3D11DepthBuffer(interopSurface);
                }
            });
        }
    });
}

Annak ellenőrzéséhez, hogy a 2. HoloLens megfelelően működik-e a mélységi reprodukálás, engedélyezheti a mélységi vizualizációt a Eszközportál. A részletekért lásd: Verifying Depth is Set Correctly (A mélység ellenőrzése helyesen van beállítva).

Nem kötelező: Egyéni adatcsatornák

Egyéni adatcsatornák segítségével felhasználói adatokat lehet küldeni a már létrehozott kapcsolaton keresztül. További információ: Egyéni adatcsatornák.

Nem kötelező: Rendszerszinkronizálás koordinálása

A 2.7.0-sverziójától kezdődően a koordinátarendszer-szinkronizálással a térbeli adatok igazíthatóak a lejátszó és a távoli alkalmazás között. További információ: A rendszerszinkronizálás koordinálása holografikus elotolással – áttekintés.

Lásd még: