Version: 2023.1
언어: 한국어
XR SDK 입력 하위 시스템
XR SDK 메싱 하위 시스템

XR SDK 디스플레이 하위 시스템

XR SDK 디스플레이 하위 시스템은 텍스처 할당, 프레임 라이프사이클, 케이던스 차단을 위한 인터페이스를 제공합니다.

텍스처 할당

여러 기기 SDK의 경우 일반적인 그래픽스 API가 아닌 SDK 자체를 통해 텍스처를 할당해야 합니다. XR SDK 디스플레이 하위 시스템을 사용하면 외부 플러그인을 사용하여 SDK 텍스처에 블리팅하거나 복사할 필요가 없습니다.

디스플레이 하위 시스템을 사용하면 플러그인 공급자가 텍스처를 할당할 수 있습니다. 가능한 경우 Unity는 불필요한 복사본을 피하기 위해 텍스처에 직접 렌더링합니다. 또한 필요한 경우 텍스처를 자동으로 할당할 수도 있습니다.

다음과 같은 경우 Unity는 텍스처에 직접 렌더링할 수 없으며, 대신 임시 텍스처로 렌더링한 후 텍스처에 블리팅하거나 복사합니다.

  • 이미지 효과를 사용하는 경우 텍스처는 체인에서 마지막에 위치합니다.
  • MSAA를 지원하는 PC에서는 Unity가 멀티샘플링된 텍스처로 렌더링한 후 카메라 스택의 맨 마지막에 텍스처로 확인됩니다.
  • 멀티샘플 자동 확인 확장을 지원하는 모바일에서는 텍스처가 플러시되거나 그리기 작업 이외의 다른 작업을 위한 소스 또는 대상으로 사용되면 암묵적으로 확인됩니다. EXT_multisampled_render_to_texture 확장을 참조하십시오.
  • 디퍼드 렌더링, HDR, 커맨드 버퍼로 인해 Unity가 임시 텍스처로 렌더링합니다.
  • 화면의 하위 집합으로 렌더링하는 경우 Unity는 임시 텍스처로 렌더링합니다.
  • “텍스처 레이아웃”이 렌더링되는 대상과 일치하지 않는 경우(예: Unity가 각 눈을 별도 텍스처로 렌더링하지만, 렌더 패스가 텍스처 배열 또는 단일 텍스처로 렌더링되도록 설정된 경우)
  • kUnityXRRenderTextureFlagsLockedWidthHeight 플래그가 설정되고 renderScale이 1.0이 아닌 경우
  • kUnityXRRenderTextureFlagsWriteOnly 플래그가 설정되고 Unity가 텍스처에서 다시 읽어와야 하는 경우

MSAA

PC와 모바일 모두에서 엔진은 항상 공급자의 텍스처로 확인됩니다. 엔진이 암묵적 확인(텍스처로의 멀티샘플 렌더링 확장을 지원하는 모바일)을 수행하거나 명시적 확인을 수행합니다.

모바일에서 공급자는 kUnityXRRenderTextureFlagsAutoResolve 플래그를 활성화하고 1개의 샘플로 해당 텍스처를 생성해야 합니다.

sRGB

UnityXRFrameSetupHints.appSetup.sRGB를 사용하여 Unity가 sRGB 텍스처 포맷으로의 렌더링을 기대하는지 확인합니다. 궁극적으로 공급자는 UnityXRRenderTextureDesccolorFormat 필드에서 출력 텍스처 포맷을 선택합니다. 포맷이 sRGB 타입이면 Unity는 활성 프로젝트가 선택하는 색 공간에 따라 sRGB 쓰기를 활성화하거나 비활성화합니다. 항상 컴포지터에서 sRGB-리니어 전환을 사용하여 sRGB 텍스처에서 샘플링해야 합니다.

뎁스 텍스처

SDK에 뎁스 정보가 필요한 경우 위의 컬러 버퍼와 동일한 방식으로 뎁스 버퍼를 얻을 수 있습니다. UnityXRRenderTextureDescnativeDepthTex 값은 네이티브 리소스를 지정합니다. nativeDepthTexkUnityXRRenderTextureIdDontCare로 설정된 경우 Unity는 기본적으로 유사한 설명의 텍스처 간에 뎁스 버퍼를 공유합니다.

SDK에 뎁스 정보가 필요하지 않은 경우에는 불필요한 확인을 피하기 위해 UnityXRRenderTextureDesc::depthFormatkUnityXRDepthTextureFormatNone으로 설정해야 합니다.

이중 및 삼중 버퍼링 처리

제출하는 동안(아래 이동 프레임 제출 섹션 참조) SDK에 Unity가 렌더링할 이중 또는 삼중 버퍼 이미지가 필요한 경우 이를 처리하기 위해 각 프레임마다 다른 텍스처 ID를 지정할 수 있습니다. 공급자 플러그인은 UnityXRRenderTextureId 컬렉션의 관리를 책임집니다.

프레임 라이프사이클

프레임의 라이프사이클을 담당하는 메서드에는 다음의 두 가지가 있습니다. PopulateNextFrameDesc는 렌더링 시작 직전에 발생하고, SubmitCurrentFrame은 렌더링이 완료된 직후에 발생합니다. 두 가지 메서드 모두 그래픽스 스레드에서 호출됩니다.

PopulateNextFrameDesc 동안 디스플레이 공급자는 다음의 작업을 수행해야 합니다.

  • 케이던스를 기다립니다(Unity가 렌더링 커맨드 제출을 다시 시작할 때까지 대기). 또는 SubmitCurrentFrame에서 이 작업을 수행할 수도 있습니다.
  • 다음 이미지를 획득하고 nextFrame 파라미터를 통해 다음에 렌더링할 텍스처 ID를 Unity에 알립니다.

SubmitCurrentFrame 메서드 동안 디스플레이 공급자는 다음의 작업을 수행해야 합니다.

  • 마지막 이동 프레임(예: 눈 텍스처 또는 뎁스 텍스처)을 제출하여 화면에 표시합니다.
  • PopulateNextFrameDesc 동안 대기하는 대신 케이던스를 기다립니다.

케이던스 차단

HMD 디스플레이로 렌더링 시 최대한 낮은 지연 시간과 최대 처리량을 유지하려면 포즈를 얻고 텍스처를 제출할 때 정확한 타이밍을 보장해야 합니다. 각 HMD에는 해당 컴포지터가 실행되는 새로고침 속도가 있습니다. 이 속도보다 빠르게 렌더링하면 타이밍 불일치 또는 중복 작업으로 인해 환경이 최적화되지 않습니다.

Unity는 디스플레이 공급자가 프레임 수명 주기 동안 프레임 케이던스를 차단하거나 대기할 것으로 예상합니다.Unity는 호출 차단에서 ’해제’된 직후 렌더링 커맨드를 제출하기 시작합니다.특정 창 내에서 해제 시간을 컴포지터와 동기화해야 합니다.일부 SDK는 휴리스틱 기반의 플로팅 해제 시간 창을 제공합니다.Meta/Oculus에서는 이를 “대기열”이라고 합니다(자세한 내용은 Oculus 개발자 문서 참조).Valve에서는 이를 “실행 시작”이라고 합니다(이 프레젠테이션의 슬라이드 18 및 19 참조).

Unity는 포즈별 그래픽스 커맨드를 제출하기 전에 프레임 라이프사이클이 완료되기를 기다립니다.

케이던스 대기 위치

공급자는 PopulateNextFrameDesc 또는 SubmitCurrentFrame에서 케이던스를 기다릴 수 있습니다.

Unity가 그래픽스 스레드의 프레임에 대한 그래픽스 커맨드를 제출하는 동안 다음 프레임의 시뮬레이션 루프가 메인 스레드에서 실행됩니다. 여기에는 물리, 스크립트 로직 등이 포함되어 있습니다. PopulateNextFrameDesc는 모든 렌더링 커맨드가 제출된 후, 그리고 다음 프레임의 시뮬레이션과 그에 대해 예약된 그래픽스 작업이 모두 완료된 후에만 그래픽스 스레드에서 호출됩니다. PopulateNextFrameDesc가 기다리는 그래픽스 작업 중 하나는 현재 프레임에 대한 SubmitCurrentFrame입니다. 이는 SubmitCurrentFrame에서 케이던스를 기다려야 하는 이유입니다. 또한 Unity는 PopulateNextFrameDesc가 완료될 때까지 렌더링을 시작하지 않습니다.

이러한 세부 정보를 염두에 두면 PopulateNextFrameDesc가 아니라 SubmitCurrentFrame에서 케이던스를 기다리는 것에 대한 몇 가지 장단점을 파악할 수 있습니다. 예를 들어 SubmitCurrentFrame에서 케이던스를 기다리면, 애플리케이션이 시뮬레이션 동안 부하가 높은 그래픽스 작업을 예약할 경우 성능 문제가 발생할 수 있습니다. SubmitCurrentFrame은 렌더링 후 실행되도록 예약되었으므로, 애플리케이션이 예약한 그래픽스 작업은 SubmitCurrentFrame 후에 그리고 PopulateNextFrameDesc 전에 실행됩니다. 이 경우 공급자는 SubmitCurrentFrame을 기다린 후 Unity가 렌더링을 시작하기를 기대하며 깨어납니다. 하지만 Unity는 PopulateNextFrameDesc를 호출하기 전에 애플리케이션이 예약한 그래픽스 작업을 처리하므로, Unity는 렌더링을 시작할 수 있습니다. 렌더링을 위한 깨어나기 시간과 업데이트 메서드에 예약된 그래픽스 작업 처리 간의 지연으로 인해 지연이 발생할 수 있습니다. 개발자는 렌더링 후 그래픽스 작업을 예약하여 그래픽스 작업이 SubmitCurrentFrame 전에 예약되도록 보장함으로써 최적화를 수행할 수 있습니다.

SubmitCurrentFrame에서 케이던스를 기다리는 공급자는 그래픽스 작업 계산이 메인 스레드에서 병렬로 실행되도록 허용하지만, PopulateNextFrameDesc에서 케이던스를 기다리는 경우에는 Unity 메인 스레드가 완전히 차단됩니다. 이는 시뮬레이션 및 기타 그래픽스 작업이 이미 완료되었기 때문에 허용됩니다. 시뮬레이션 또는 그래픽스 스레드가 시간을 너무 많이 소모하고 기기의 타겟 프레임 속도를 초과할 경우 문제가 발생할 수 있습니다. 이로 인해 PopulateNextFrameDesc가 케이던스의 다음 사이클을 기다리는 동안 프레임 속도가 절반으로 줄어들 수 있습니다.

이동 프레임 제출

Unity가 SubmitCurrentFrame을 호출하면 마지막 프레임으로 설정한 텍스처가 렌더링되거나, Unity가 렌더링 커맨드를 그래픽스 드라이버에 제출하여 렌더링합니다. Unity 작업을 완료하면 컴포지터에 전달할 수 있습니다.

다음 프레임 기술자(descriptor) 작성

렌더링할 다음 프레임을 차단하거나 획득한 후에는 다음 프레임에서 렌더링할 텍스처와 렌더 패스의 레이아웃을 Unity에 알려야 합니다(아래의 렌더 패스 참조).

렌더 패스

UnityXRRenderPass에는 컬링 패스와 씬 그래프 이동이 포함될 수 있습니다. 이는 리소스를 많이 소모하는 작업이므로, 싱글 패스 렌더링 등과 같은 트릭을 통해 Unity가 작업을 수행하는 횟수를 제한해야 합니다.

UnityXRRenderPass에는 출력 텍스처(텍스처 배열일 수 있음), 그리고 뷰, 투사 매트릭스, 렌더링할 사각형 또는 텍스처 배열 슬라이스 등과 같은 UnityXRRenderParams 출력이 포함되어 있습니다.

각 프레임에 대해 디스플레이 공급자는 UnityXRRenderPass를 설정하고, Unity가 다음 프레임에 렌더링되는 UnityXRRenderTextureId를 작성합니다.

UnityXRRenderPass에 대한 사용 사례에는 다음이 포함됩니다.

  • 2패스 스테레오 렌더링(2 RenderPass x 1 RenderParams)
  • 싱글 패스 스테레오 렌더링(1 RenderPass x 2 RenderParams)

API는 다음의 추가 사례를 지원합니다(단, 현재는 Unity가 올바르게 응답하지 않을 수도 있음).

  • 4패스 와이드 FOV 스테레오 렌더링(4 RenderPass x 1 RenderParams)
  • 싱글 패스 + 와이드 FOV 스테레오 렌더링(1 RenderPass x 2 RenderParams + 2 RenderPass x 1 RenderParams)
  • Foveated 렌더링:
    • 각 눈에 대한 두 개의 별도 텍스처(내부 및 외부)
    • 한 개의 텍스처, UV 피팅
  • 외부 뷰 시나리오(HoloLens BEV, Mayo 3rd Eye)(추가 RenderPass)
  • 씬에서 오브젝트 또는 사람을 합성하기 위한 근거리/원거리 렌더링(2 RenderPass, 다른 프로젝션, 다른 타겟)

다음과 같이 가정할 수 있습니다.

  • 패스당 하나의 텍스처(싱글 패스는 하나의 텍스처 배열)
  • 싱글 패스인 경우 패스당 두 개의 포즈/프로젝션(또는 foveated 렌더링)

참고: 이 설정은 사용자 셰이더에 영향을 미치므로 Unity 프로젝트와 XR SDK는 싱글 패스 렌더링에 대해 동일한 설정(활성화/비활성화)을 사용해야 합니다. 싱글 패스 렌더링이 활성화되었는지 확인하려면 UnityXRFrameSetupHints.appSetup.singlePassRendering을 사용하십시오.

컬링 패스

cullingPassIndex가 동일한 값으로 설정된 경우 두 개의 렌더링 패스가 컬링 패스를 공유할 수 있습니다. cullingPassIndex는 사용할 UnityXRCullingPass를 선택합니다. 컬링 패스는 UnityXRNextFrameDesc에 작성해야 합니다.

XR SDK 입력 하위 시스템
XR SDK 메싱 하위 시스템