HoloLens 개발 메모 #1

Voxel-Horizon을 HoloLens로 돌리기 위해 엔진을 포팅중이다.
작업하면서 기록으로 남겨두고 싶은 내용들을 정리해둔다.

1. 기존 VR환경과 비슷한점.
왼쪽 오른쪽 눈에 대해서 각각의 view/projection matrix와 파라미터를 제공한다.
Oculus나 HoloLens나 양안에 대한 View/Projection Matrix를 얻어서 왼쪽 오른쪽 각각의 버퍼에 대해서 렌더링 해주면 일단 입체영상을 사용자에게 보여줄 수 있다. 그 점은 기본적으로 같다.

2. 기존 VR환경과 다른점.

– Draw 처리
Oculus의 경우 RTV를 2개 생성하고 렌더링도 두번한다.
HoloLens는 RTV에 TextureArray를 사용해서 렌더링을 한번 한다. 물론 내부적으로 Shader는 2회 돌아갈수 밖에 없지만 적어도 Draw API호출은 한번 뿐이다.
culling을 위해 view frustum이 필요한데 왼쪽/오른쪽 눈에 대해서 view frustm을 따로 처리하면 culling 시간이 두배가 된다. 대부분의 경우 양쪽을 따로 culling해봐야 시간만 두 배 걸리지 보이지 않는 오브젝트 개수는 거의 비슷하게 나온다. 효율이 나쁘다. 그래서 Oculus로 개발할때는 왼쪽 오른쪽의 view frustum을 모두 감싸는 새로운 view frustum을 만들어서 처리했다.
HoloLens의 경우 API에서 아예 왼쪽/오른쪽을 모두 포함하는 view frustum을 제공한다.

코드는 다음과 같은 형태이다.

holographicFrame->UpdateCurrentPrediction();
HolographicFramePrediction^ prediction = holographicFrame->CurrentPrediction;

bool atLeastOneCameraRendered = false;
UINT size = prediction->CameraPoses->Size;

for (auto cameraPose : prediction->CameraPoses)
{
    Windows::Foundation::Numerics::float4x4 matLeft = cameraPose->ProjectionTransform.Left;
    Windows::Foundation::Numerics::float4x4 matRight = cameraPose->ProjectionTransform.Right;

    Platform::IBox<Windows::Perception::Spatial::SpatialBoundingFrustum>^ frustumVisible = cameraPose->TryGetVisibleFrustum(m_referenceFrame->CoordinateSystem);
    
    Platform::IBox<Windows::Perception::Spatial::SpatialBoundingFrustum>^ frustumCulled = cameraPose->TryGetCullingFrustum(m_referenceFrame->CoordinateSystem);

– 공간설정
Spatial이라 부르는데 이게 이전의 VR시스템엔 없다. 공간을 구성한다고 했는데 쉽게 말해 배경으로 사용할 폴리곤 데이터를 설정하는 것이다. HoloLens가 스캔해서 공간을 구성하는 방법이 있고, 미리 만들어진(혹은 HoloLens가 스캔한 데이터를 저장한) 데이터를 읽어서 공간을 구성하는 방법이 있다.

3.DirectX를 다루는 방식에서의 차이점.

– Back-Buffer 리소스 생성
일반적인 UWP DX11앱하고 똑같다고 생각했는데 HoloLens용으로 만들땐 생각보다 많이 다르다.
예를 들면 데스크탑의 경우 HWND으로부터 SwapChain을 생성하고 XAML UWP앱은 XAML의 SwapChainPanel로부터 SwapChain을 생성한다. 그리고 양쪽 모두 SwapChain으로부터 RTV(Render Target View)로 사용할 버퍼를 가져온다.이 버퍼에서 RTV를 얻어온다.
데스크탑이든 UWP든 초기에 SwapChain으로부터 Back-Buffer를 생성하고 화면 사이즈가 변하거나 device-lost가 발생하지 않는 이상 그대로 유지한다는 점은 똑같다.

HoloLens의 경우는 XAML의 SwapChain을 사용하지 않는다. 네이티브 API로는 SwapChain을 사용하는 방식이 아니다. 이미 배포된 UWP XAML앱에서 DirectX를 쓸 수도 있으니까 그런 경우 중간 레이어를 두고 호환성은 유지해줄거라 추측한다.

Windows::Graphics::Holographic::HolographicFrame과 HolographicFramePrediction 으로부터 HolographicRenderingParameter를 받아 그 안에서 가리키고 있는 IDirect3DSurface를 RTV로 사용해야한다. 저 이벤트로 날라오는 파라미터외엔 RTV버퍼를 가져올 방법이 없다. 아예 어플리케이션 초기화할 당시에 RTV를 생성하는것이 불가능하도록 API설계가 되어있다.

코드를 보면 다음과 같은 식이다. 이 코드는 샘플의 EnsureCameraResources()함수를 참고해서 만들었는데 매 프레임 렌더링 하기 전에 호출된다.


void __stdcall CD3DDevice::EnsureCameraResources(Windows::Graphics::Holographic::HolographicFrame^ frame, HolographicFramePrediction^ prediction)
{
    auto camPoses = prediction->CameraPoses;
    
    HolographicCameraPose^ pose = camPoses->GetAt(0);
    auto cameraParameters = frame->GetRenderingParameters(pose);

    // Get the WinRT object representing the holographic camera's back buffer.
    IDirect3DSurface^ surface = cameraParameters->Direct3D11BackBuffer;

    // Get a DXGI interface for the holographic camera's back buffer.
    // Holographic cameras do not provide the DXGI swap chain, which is owned
    // by the system. The Direct3D back buffer resource is provided using WinRT
    // interop APIs.
    ComPtr<ID3D11Resource> resource;
    GetDXGIInterfaceFromObject(surface, IID_PPV_ARGS(&resource));

    // Get a Direct3D interface for the holographic camera's back buffer.
    ComPtr<ID3D11Texture2D> cameraBackBuffer;
    resource.As(&cameraBackBuffer);

    // Determine if the back buffer has changed. If so, ensure that the render target view
    // is for the current back buffer.
    if (m_pCameraBuffer == cameraBackBuffer.Get())
        return;

    // Create a render target view of the back buffer.
    // Creating this resource is inexpensive, and is better than keeping track of
    // the back buffers in order to pre-allocate render target views for each one.
    m_pD3DDevice->CreateRenderTargetView(cameraBackBuffer.Get(), nullptr, &m_pCameraRTV);

앱 초기화시에 RTV를 미리 만들어둘수도 없거니와 이전 프레임에서 생성된, 혹은 를 계속 사용할 수 있음을 보장하지 않는다.
최악의 경우는 매프레임마다 RTV에 관련된 back buffer리소스들을 몽땅 다시 만들어줘야할 수 있다. 물론 현재까지 테스트해본 바에 의하면 그런 경우는 일어나지 않는다.

2016-12-06

일단 엔진 DLL을 정상적으로 로드하고 RTV를 생성하고 렌더링은 아무것도 하지 않는 선까지 작업을 진행했다. 아무것도 렌더링 하지 않지만 여기까지 오는데 몇 일 걸렸다. 다음번 포스팅에선 이미지라도 한장 띄운 스샷이라도 첨부하겠다.


HoloLens 개발 메모 #1”에 대한 답글 2개

답글 남기기

댓글을 게시하려면 다음의 방법 중 하나를 사용하여 로그인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중