OpenXR API를 사용하여 홀로그램 원격 원격 앱 작성

Holographic Remoting을 사용하는 경우 개요를 읽을 수 있습니다.

중요

이 문서에서는 OpenXR API를 사용하여 HoloLens 2 및 Windows Mixed Reality 헤드셋에 대한 원격 애플리케이션을 만드는 방법에 대해 설명합니다. HoloLens(1세대)용 원격 애플리케이션은 NuGet 패키지 버전 1.x.x를 사용해야 합니다. 이는 HoloLens 2 위해 작성된 원격 애플리케이션이 HoloLens 1과 호환되지 않으며 그 반대의 경우도 마찬가지임을 의미합니다. HoloLens 1에 대한 설명서는 여기에서 찾을 수 있습니다.

홀로그램 원격 앱은 원격으로 렌더링된 콘텐츠를 HoloLens 2 스트리밍하고 몰입형 헤드셋을 Windows Mixed Reality 수 있습니다. 더 많은 시스템 리소스에 액세스하고 원격 몰입형 보기를 기존 데스크톱 PC 소프트웨어에 통합할 수도 있습니다. 원격 앱은 HoloLens 2 입력 데이터 스트림을 수신하고, 가상 몰입형 보기에서 콘텐츠를 렌더링하고, 콘텐츠 프레임을 다시 HoloLens 2 스트리밍합니다. 연결은 표준 Wi-Fi를 사용하여 이루어집니다. 홀로그램 원격은 NuGet 패킷을 통해 데스크톱 또는 UWP 앱에 추가됩니다. 연결을 처리하고 몰입형 보기에서 렌더링하는 추가 코드가 필요합니다. 일반적인 원격 연결의 대기 시간은 50ms입니다. 플레이어 앱은 대기 시간을 실시간으로 보고할 수 있습니다.

이 페이지의 모든 코드와 작업 중인 프로젝트는 Holographic Remoting 샘플 github 리포지토리에서 찾을 수 있습니다.

사전 요구 사항

좋은 시작점은 작동하는 OpenXR 기반 데스크톱 또는 UWP 앱입니다. 자세한 내용은 OpenXR 시작을 참조하세요.

중요

홀로그램 원격을 사용하는 모든 앱은 다중 스레드 아파트를 사용하도록 작성해야 합니다. 단일 스레드 아파트의 사용은 지원되지만 최적이 아닌 성능과 재생 중에 더듬거리는 것으로 이어질 수 있습니다. C++/WinRT winrt::init_apartment 사용하는 경우 다중 스레드 아파트가 기본값입니다.

홀로그램 원격 NuGet 패키지 가져오기

Visual Studio의 프로젝트에 NuGet 패키지를 추가하려면 다음 단계가 필요합니다.

  1. Visual Studio에서 프로젝트를 엽니다.
  2. 프로젝트 노드를 마우스 오른쪽 단추로 클릭하고 NuGet 패키지 관리...를 선택합니다.
  3. 표시되는 패널에서 찾아보기를 선택한 다음, "홀로그램 원격"을 검색합니다.
  4. Microsoft.Holographic.Remoting.OpenXr를 선택한 다음, 최신 2.x.x 버전이 선택되어 있는지 확인하고 설치를 선택합니다.
  5. 미리 보기 대화 상자가 나타나면 확인을 선택합니다.
  6. 사용권 계약 대화 상자가 나타나면 동의 를 선택합니다.
  7. OpenXR.Headers, OpenXR.Loader와 같은 NuGet 패키지에 대해 3~6단계를 반복합니다.

참고

HoloLens 1을 대상으로 하려는 개발자는 NuGet 패키지 버전 1.x.x 를 계속 사용할 수 있습니다. 자세한 내용은 홀로그램 원격 추가(HoloLens(1세대))를 참조하세요.

홀로그램 원격 OpenXR 런타임 선택

원격 앱에서 수행해야 하는 첫 번째 단계는 Microsoft.Holographic.Remoting.OpenXr NuGet 패키지의 일부인 Holographic Remoting OpenXR 런타임을 선택하는 것입니다. 환경 변수를 XR_RUNTIME_JSON 앱 내의 RemotingXR.json 파일 경로로 설정하여 이 작업을 수행할 수 있습니다. 이 환경 변수는 OpenXR 로더에서 시스템 기본 OpenXR 런타임을 사용하지 않고 홀로그램 원격 OpenXR 런타임으로 리디렉션하는 데 사용됩니다. Microsoft.Holographic.Remoting.OpenXr NuGet 패키지를 사용하는 경우 RemotingXR.json 파일이 출력 폴더로 컴파일하는 동안 자동으로 복사됩니다. OpenXR 런타임 선택은 일반적으로 다음과 같습니다.

bool EnableRemotingXR() {
    wchar_t executablePath[MAX_PATH];
    if (GetModuleFileNameW(NULL, executablePath, ARRAYSIZE(executablePath)) == 0) {
        return false;
    }
    
    std::filesystem::path filename(executablePath);
    filename = filename.replace_filename("RemotingXR.json");

    if (std::filesystem::exists(filename)) {
        SetEnvironmentVariableW(L"XR_RUNTIME_JSON", filename.c_str());
            return true;
        }

    return false;
}

홀로그램 원격 확장을 사용하여 XrInstance 만들기

일반적인 OpenXR 앱이 수행해야 하는 첫 번째 작업은 OpenXR 확장을 선택하고 XrInstance를 만드는 것입니다. OpenXR 코어 사양은 원격 특정 API를 제공하지 않습니다. 이러한 이유로 Holographic Remoting은 라는 XR_MSFT_holographic_remoting자체 OpenXR 확장을 도입합니다. 이 XR_MSFT_HOLOGRAPHIC_REMOTING_EXTENSION_NAME xrCreateInstance 호출의 XrInstanceCreateInfo에 포함되어 있는지 확인합니다.

기본적으로 앱의 렌더링된 콘텐츠는 HoloLens 2 또는 Windows Mixed Reality 헤드셋에서 실행되는 홀로그램 원격 플레이어에게만 스트리밍됩니다. 또한 렌더링된 콘텐츠를 원격 PC에 표시하기 위해 instance 창의 스왑 체인을 통해 Holographic Remoting은 라는 XR_MSFT_holographic_remoting_frame_mirroring두 번째 OpenXR 확장을 제공합니다. 해당 기능을 사용하려는 경우 를 사용하여 XR_MSFT_HOLOGRAPHIC_REMOTING_FRAME_MIRRORING_EXTENSION_NAME 이 확장을 사용하도록 설정해야 합니다.

중요

홀로그램 원격 OpenXR 확장 API에 대해 알아보려면 Holographic Remoting 샘플 github 리포지토리에서 찾을 수 있는 사양을 검사.

디바이스에 연결

원격 앱이 XrInstance를 만들고 xrGetSystem을 통해 XrSystemId를 쿼리한 후 플레이어 디바이스에 대한 연결을 설정할 수 있습니다.

경고

홀로그램 원격 OpenXR 런타임은 연결이 설정된 후에만 보기 구성 또는 환경 혼합 모드와 같은 디바이스별 데이터를 제공할 수 있습니다. xrEnumerateViewConfigurations, xrEnumerateViewConfigurationViews, xrGetViewConfigurationProperties, , xrEnumerateEnvironmentBlendModesxrGetSystemProperties 는 완전히 연결되기 전에 HoloLens 2 실행 중인 플레이어에 연결하는 경우 일반적으로 얻을 수 있는 것과 일치하는 기본값을 제공합니다. 연결이 설정되기 전에 이러한 메서드를 호출하지 않는 것이 좋습니다. 제안은 XrSession이 성공적으로 만들어지고 세션 상태가 XR_SESSION_STATE_READY 후에 이러한 메서드를 사용합니다.

다음과 같이 최대 비트 전송률, 오디오 사용, 비디오 코덱 또는 깊이 버퍼 스트림 해상도와 같은 일반 속성을 구성할 xrRemotingSetContextPropertiesMSFT 수 있습니다.

XrRemotingRemoteContextPropertiesMSFT contextProperties;
contextProperties = XrRemotingRemoteContextPropertiesMSFT{static_cast<XrStructureType>(XR_TYPE_REMOTING_REMOTE_CONTEXT_PROPERTIES_MSFT)};
contextProperties.enableAudio = false;
contextProperties.maxBitrateKbps = 20000;
contextProperties.videoCodec = XR_REMOTING_VIDEO_CODEC_H265_MSFT;
contextProperties.depthBufferStreamResolution = XR_REMOTING_DEPTH_BUFFER_STREAM_RESOLUTION_HALF_MSFT;
xrRemotingSetContextPropertiesMSFT(m_instance.Get(), m_systemId, &contextProperties);

연결은 두 가지 방법 중 하나로 수행할 수 있습니다.

  1. 원격 앱은 디바이스에서 실행 중인 플레이어에 연결됩니다.
  2. 디바이스에서 실행 중인 플레이어가 원격 앱에 연결합니다.

원격 앱에서 플레이어 디바이스로의 연결을 설정하려면 구조를 통해 호스트 이름 및 포트를 지정하는 메서드를 호출 xrRemotingConnectMSFT 합니다 XrRemotingConnectInfoMSFT . 홀로그램 원격 플레이어에서 사용하는 포트는 8265입니다.

XrRemotingConnectInfoMSFT connectInfo{static_cast<XrStructureType>(XR_TYPE_REMOTING_CONNECT_INFO_MSFT)};
connectInfo.remoteHostName = "192.168.x.x";
connectInfo.remotePort = 8265;
connectInfo.secureConnection = false;
xrRemotingConnectMSFT(m_instance.Get(), m_systemId, &connectInfo);

메서드를 호출 xrRemotingListenMSFT 하여 원격 앱에서 들어오는 연결을 수신 대기할 수 있습니다. 핸드셰이크 포트와 전송 포트는 구조를 통해 XrRemotingListenInfoMSFT 지정할 수 있습니다. 핸드셰이크 포트는 초기 핸드셰이크에 사용됩니다. 그런 다음 전송 포트를 통해 데이터가 전송됩니다. 기본적으로 82658266 이 사용됩니다.

XrRemotingListenInfoMSFT listenInfo{static_cast<XrStructureType>(XR_TYPE_REMOTING_LISTEN_INFO_MSFT)};
listenInfo.listenInterface = "0.0.0.0";
listenInfo.handshakeListenPort = 8265;
listenInfo.transportListenPort = 8266;
listenInfo.secureConnection = false;
xrRemotingListenMSFT(m_instance.Get(), m_systemId, &listenInfo);

또는 xrRemotingListenMSFT를 호출 xrRemotingConnectMSFT 할 때 연결 상태를 연결 해제해야 합니다. XrInstance를 만들고 를 통해 xrRemotingGetConnectionStateMSFTXrSystemId에 대해 쿼리한 후 언제든지 연결 상태를 가져올 수 있습니다.

XrRemotingConnectionStateMSFT connectionState;
xrRemotingGetConnectionStateMSFT(m_instance.Get(), m_systemId, &connectionState, nullptr);

사용 가능한 연결 상태는 다음과 같습니다.

  • XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT
  • XR_REMOTING_CONNECTION_STATE_CONNECTING_MSFT
  • XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFT

중요

xrRemotingConnectMSFT 또는 xrRemotingListenMSFT 은 xrCreateSession을 통해 XrSession을 만들기 전에 호출되어야 합니다. 연결 상태가 XR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT 세션 생성인 동안 XrSession을 만들려고 하면 세션 상태가 즉시 XR_SESSION_STATE_LOSS_PENDING 전환됩니다.

Holographic Remoting의 구현 xrCreateSession 은 연결이 설정되기를 기다리는 것을 지원합니다. 를 호출 xrRemotingConnectMSFT 하거나 xrRemotingListenMSFT 바로 다음에 를 호출할 xrCreateSession수 있습니다. 그러면 연결이 차단되고 연결이 설정될 때까지 기다립니다. 의 xrRemotingConnectMSFT 시간 제한은 10초로 고정되고 는 무제한입니다 xrRemotingListenMSFT. 이 시간 내에 연결을 설정할 수 있는 경우 XrSession 만들기가 성공하고 세션 상태가 XR_SESSION_STATE_READY 전환됩니다. 연결을 설정할 수 없는 경우 세션 만들기도 성공하지만 즉시 XR_SESSION_STATE_LOSS_PENDING 전환됩니다.

일반적으로 연결 상태는 XrSession 상태와 결합됩니다. 연결 상태를 변경하면 세션 상태에도 영향을 줍니다. instance 경우 연결 상태가 에서 XR_REMOTING_CONNECTION_STATE_CONNECTED_MSFTXR_REMOTING_CONNECTION_STATE_DISCONNECTED_MSFT 세션 상태로 전환되면 XR_SESSION_STATE_LOSS_PENDING 전환됩니다.

원격 특정 이벤트 처리

홀로그램 원격 OpenXR 런타임은 연결 상태를 모니터링하는 데 중요한 세 가지 이벤트를 노출합니다.

  1. XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT: 디바이스에 대한 연결이 성공적으로 설정되면 트리거됩니다.
  2. XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT: 설정된 연결이 닫혀 있거나 연결을 설정할 수 없는 경우 트리거됩니다.
  3. XR_TYPE_REMOTING_EVENT_DATA_LISTENING_MSFT: 들어오는 연결을 수신 대기할 때 시작됩니다.

이러한 이벤트는 큐에 배치되며 원격 앱은 를 통해 xrPollEvent정기적으로 큐에서 읽어야 합니다.

auto pollEvent = [&](XrEventDataBuffer& eventData) -> bool {
	eventData.type = XR_TYPE_EVENT_DATA_BUFFER;
	eventData.next = nullptr;
	return CHECK_XRCMD(xrPollEvent(m_instance.Get(), &eventData)) == XR_SUCCESS;
};

XrEventDataBuffer eventData{};
while (pollEvent(eventData)) {
	switch (eventData.type) {
	
	...
	
	case XR_TYPE_REMOTING_EVENT_DATA_LISTENING_MSFT: {
		DEBUG_PRINT("Holographic Remoting: Listening on port %d",
					reinterpret_cast<const XrRemotingEventDataListeningMSFT*>(&eventData)->listeningPort);
		break;
	}
	case XR_TYPE_REMOTING_EVENT_DATA_CONNECTED_MSFT: {
		DEBUG_PRINT("Holographic Remoting: Connected.");
		break;
	}
	case XR_TYPE_REMOTING_EVENT_DATA_DISCONNECTED_MSFT: {
		DEBUG_PRINT("Holographic Remoting: Disconnected - Reason: %d",
					reinterpret_cast<const XrRemotingEventDataDisconnectedMSFT*>(&eventData)->disconnectReason);
		break;
	}
}

로컬로 스트리밍된 콘텐츠 미리 보기

디바이스 XR_MSFT_holographic_remoting_frame_mirroring 로 전송되는 원격 앱에 동일한 콘텐츠를 표시하려면 확장을 사용할 수 있습니다. 이 확장을 사용하면 다음과 같이 XrFrameEndInfo에 연결되지 않은 을 사용하여 XrRemotingFrameMirrorImageInfoMSFT xrEndFrame에 텍스처를 제출할 수 있습니다.

XrFrameEndInfo frameEndInfo{XR_TYPE_FRAME_END_INFO};
...

XrRemotingFrameMirrorImageD3D11MSFT mirrorImageD3D11{
    static_cast<XrStructureType>(XR_TYPE_REMOTING_FRAME_MIRROR_IMAGE_D3D11_MSFT)};
mirrorImageD3D11.texture = m_window->GetNextSwapchainTexture();

XrRemotingFrameMirrorImageInfoMSFT mirrorImageEndInfo{
    static_cast<XrStructureType>(XR_TYPE_REMOTING_FRAME_MIRROR_IMAGE_INFO_MSFT)};
mirrorImageEndInfo.image = reinterpret_cast<const XrRemotingFrameMirrorImageBaseHeaderMSFT*>(&mirrorImageD3D11);

frameEndInfo.next = &mirrorImageEndInfo;

xrEndFrame(m_session.Get(), &frameEndInfo);

m_window->PresentSwapchain();

위의 예제에서는 DX11 스왑 체인 텍스처를 사용하고 xrEndFrame 호출 직후 창을 제공합니다. 사용량은 스왑 체인 텍스처로 제한되지 않습니다. 또한 추가 GPU 동기화가 필요하지 않습니다. 사용 및 제약 조건에 대한 자세한 내용은 확장 사양을 검사. 원격 앱이 DX12를 사용하는 경우 XrRemotingFrameMirrorImageD3D11MSFT 대신 XrRemotingFrameMirrorImageD3D12MSFT를 사용합니다.

선택 사항: 사용자 지정 데이터 채널

버전 2.5.0부터 OpenXR API와 함께 사용자 지정 데이터 채널을 사용하여 이미 설정된 원격 연결을 통해 사용자 데이터를 보낼 수 있습니다. 자세한 내용은 OpenXR API를 사용하는 사용자 지정 데이터 채널을 참조하세요.

선택 사항: 음성

버전 2.6.0XR_MSFT_holographic_remoting_speech부터 확장은 원격 앱이 OpenXR API를 사용하여 플레이어 앱에서 감지한 음성 명령에 반응할 수 있도록 합니다.

[! 중요] 자세한 사양홀로그램 원격 샘플 github 리포지토리에서 찾을 수 있습니다.

플레이어 앱에서 음성 인식기를 초기화하기 위해 원격 앱에서 를 호출 xrInitializeRemotingSpeechMSFT할 수 있습니다. 이 호출은 언어, 구 사전 및 문법 파일의 내용으로 구성된 음성 초기화 매개 변수를 플레이어 앱으로 전송합니다.

참고

버전 2.6.1 이전에는 음성 인식기가 당 XrSession한 번만 초기화되어야 합니다.

이벤트에 표시된 XR_TYPE_EVENT_DATA_REMOTING_SPEECH_RECOGNIZER_STATE_CHANGED_MSFT 대로 음성 인식기 만들기가 성공하면 플레이어 앱에서 음성 인식 결과가 생성될 때 원격 앱에 알림이 표시됩니다. 이벤트 구조는 XrEventDataRemotingSpeechRecognizerStateChangedMSFT 플레이어 쪽의 음성 인식기 상태가 변경되면 이벤트 큐에 배치됩니다.

XrRemotingSpeechRecognizerStateMSFT 는 플레이어 쪽에서 음성 인식기의 가능한 모든 상태를 정의하고 XrEventDataRemotingSpeechRecognizedMSFT 플레이어 쪽의 음성 인식기에서 인식된 구가 있는 경우 이벤트 구조가 이벤트 큐에 배치됩니다. 원격 앱이 인식된 구에 대한 알림을 받은 후 를 호출 xrRetrieveRemotingSpeechRecognizedTextMSFT하여 인식된 구를 검색할 수 있습니다.

참고

XrRemotingSpeechRecognitionConfidenceMSFT Windows Speech Recognition API에서 음성 인식 결과와 함께 반환된 SpeechRecognitionConfidence 열거형의 직접 매핑입니다.

선택 사항: 좌표계 동기화

버전 2.7.0부터 좌표계 동기화를 사용하여 플레이어와 원격 앱 간에 공간 데이터를 정렬할 수 있습니다. 자세한 내용은 홀로그램 원격 개요를 사용하여 좌표계 동기화를 참조하세요.

참고 항목