다음을 통해 공유


DirectX 리소스 설정 및 이미지 표시

여기서는 Direct3D 디바이스, 스왑 체인, 렌더링 대상 보기를 생성하는 방법과 렌더링된 이미지를 디스플레이에 표시하는 방법을 보여 드립니다.

목표: C++ UWP(유니버설 Windows 플랫폼) 앱에서 DirectX 리소스를 설정하고 단색을 표시합니다.

필수 조건

사용자가 C++에 익숙하다고 가정합니다. 그래픽 프로그래밍 개념에 대한 기본 경험도 필요합니다.

완료 시간: 20분.

지침

1. ComPtr로 Direct3D 인터페이스 변수 선언

Windows 런타임 C++ 템플릿 라이브러리(WRL)에서 ComPtr 스마트 포인터 템플릿으로 Direct3D 인터페이스 변수를 선언하므로 예외로부터 안전한 방식으로 해당 변수의 수명을 관리할 수 있습니다. 그런 다음 이러한 변수를 사용하여 ComPtr 클래스 및 해당 멤버에 액세스할 수 있습니다. 예시:

    ComPtr<ID3D11RenderTargetView> m_renderTargetView;
    m_d3dDeviceContext->OMSetRenderTargets(
        1,
        m_renderTargetView.GetAddressOf(),
        nullptr // Use no depth stencil.
        );

ComPtr로 ID3D11RenderTargetView를 선언하면, ComPtr의 GetAddressOf 메서드를 사용하여 ID3D11RenderTargetView(**ID3D11RenderTargetView)에 대한 포인터의 주소를 가져와서 ID3D11DeviceContext::OMSetRenderTargets에 전달할 수 있습니다. OMSetRenderTargets는 렌더링 대상을 출력 병합 단계에 바인딩하여 렌더링 대상을 출력 대상으로 지정합니다.

샘플 앱이 시작된 후 초기화 및 로드한 다음 실행할 준비가 됩니다.

2. Direct3D 디바이스 생성

Direct3D API를 사용하여 장면을 렌더링하려면 먼저 디스플레이 어댑터를 나타내는 Direct3D 디바이스를 생성해야 합니다. Direct3D 디바이스를 생성하려면 D3D11CreateDevice 함수를 호출합니다. D3D_FEATURE_LEVEL 값의 배열에서 9.1 수준부터 11.1 수준까지 지정합니다. Direct3D는 배열을 순서대로 안내하고 지원되는 가장 높은 기능 수준을 반환합니다. 그러므로 사용 가능한 가장 높은 수준의 기능을 가져올 수 있도록 D3D_FEATURE_LEVEL 배열 항목을 가장 높은 수준에서 가장 낮은 수준으로 나열합니다. Direct3D 리소스가 Direct2D와 상호 작용하도록 D3D11_CREATE_DEVICE_BGRA_SUPPORT 플래그를 Flags 매개 변수에 전달합니다. 디버그 빌드를 사용하는 경우 D3D11_CREATE_DEVICE_DEBUG 플래그도 전달합니다. 앱 디버깅에 대한 자세한 내용은 디버그 계층을 사용하여 앱을 디버그하는 방법을 참조하세요.

D3D11CreateDevice에서 반환되는 Direct3D 11 디바이스 및 디바이스 컨텍스트를 쿼리하여 Direct3D 11.1 디바이스(ID3D11Device1) 및 디바이스 컨텍스트(ID3D11DeviceContext1)를 가져옵니다.

        // First, create the Direct3D device.

        // This flag is required in order to enable compatibility with Direct2D.
        UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;

#if defined(_DEBUG)
        // If the project is in a debug build, enable debugging via SDK Layers with this flag.
        creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif

        // This array defines the ordering of feature levels that D3D should attempt to create.
        D3D_FEATURE_LEVEL featureLevels[] =
        {
            D3D_FEATURE_LEVEL_11_1,
            D3D_FEATURE_LEVEL_11_0,
            D3D_FEATURE_LEVEL_10_1,
            D3D_FEATURE_LEVEL_10_0,
            D3D_FEATURE_LEVEL_9_3,
            D3D_FEATURE_LEVEL_9_1
        };

        ComPtr<ID3D11Device> d3dDevice;
        ComPtr<ID3D11DeviceContext> d3dDeviceContext;
        DX::ThrowIfFailed(
            D3D11CreateDevice(
                nullptr,                    // Specify nullptr to use the default adapter.
                D3D_DRIVER_TYPE_HARDWARE,
                nullptr,                    // leave as nullptr if hardware is used
                creationFlags,              // optionally set debug and Direct2D compatibility flags
                featureLevels,
                ARRAYSIZE(featureLevels),
                D3D11_SDK_VERSION,          // always set this to D3D11_SDK_VERSION
                &d3dDevice,
                nullptr,
                &d3dDeviceContext
                )
            );

        // Retrieve the Direct3D 11.1 interfaces.
        DX::ThrowIfFailed(
            d3dDevice.As(&m_d3dDevice)
            );

        DX::ThrowIfFailed(
            d3dDeviceContext.As(&m_d3dDeviceContext)
            );

3. 스왑 체인 생성

다음으로, 디바이스가 렌더링 및 표시에 사용하는 스왑 체인을 생성합니다. DXGI_SWAP_CHAIN_DESC1 구조를 선언하고 초기화하여 스왑 체인을 설명합니다. 스왑 체인을 대칭 이동 모델(즉, SwapEffect 구성원에서 설정된 DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL 값이 있는 스왑 체인)로 설정하고 Format 구성원을 DXGI_FORMAT_B8G8R8A8_UNORM으로 설정합니다. 대칭 이동 모델이 MSAA(multiple sample antialiasing)를 지원하지 않으므로 SampleDesc 구성원이 지정하는 DXGI_SAMPLE_DESC 구조의 Count 구성원을 1로 설정하고 DXGI_SAMPLE_DESCQuality 구성원을 0으로 설정합니다. 스왑 체인이 프런트 버퍼를 사용하여 디스플레이 디바이스에 표시하고 렌더링 대상으로 사용되는 백 버퍼를 사용할 수 있도록 BufferCount 멤버를 2로 설정합니다.

Direct3D 11.1 디바이스를 쿼리하여 기본 DXGI 디바이스를 가져옵니다. 노트북 및 태블릿과 같은 배터리 구동 장치에서 수행해야 하는 전력 소비를 최소화하기 위해 DXGI에서 큐에 대기할 수 있는 최대 백 버퍼 프레임 수로 1이 있는 IDXGIDevice1::SetMaximumFrameLatency 메서드를 호출합니다. 이렇게 하면 앱이 세로 공백 발생 이후에만 렌더링됩니다.

마지막으로 스왑 체인을 생성하려면 DXGI 디바이스에서 부모 팩터리를 가져와야 합니다. IDXGIDevice::GetAdapter를 호출하여 디바이스의 어댑터를 가져온 다음 어댑터에서 IDXGIObject::GetParent를 호출하여 부모 팩터리(IDXGIFactory2)를 가져옵니다. 스왑 체인을 생성하기 위해 스왑 체인 설명자 및 앱의 핵심 창을 사용하여 IDXGIFactory2::CreateSwapChainForCoreWindow를 호출합니다.

            // If the swap chain does not exist, create it.
            DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};

            swapChainDesc.Stereo = false;
            swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
            swapChainDesc.Scaling = DXGI_SCALING_NONE;
            swapChainDesc.Flags = 0;

            // Use automatic sizing.
            swapChainDesc.Width = 0;
            swapChainDesc.Height = 0;

            // This is the most common swap chain format.
            swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;

            // Don't use multi-sampling.
            swapChainDesc.SampleDesc.Count = 1;
            swapChainDesc.SampleDesc.Quality = 0;

            // Use two buffers to enable the flip effect.
            swapChainDesc.BufferCount = 2;

            // We recommend using this swap effect for all applications.
            swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;


            // Once the swap chain description is configured, it must be
            // created on the same adapter as the existing D3D Device.

            // First, retrieve the underlying DXGI Device from the D3D Device.
            ComPtr<IDXGIDevice2> dxgiDevice;
            DX::ThrowIfFailed(
                m_d3dDevice.As(&dxgiDevice)
                );

            // Ensure that DXGI does not queue more than one frame at a time. This both reduces
            // latency and ensures that the application will only render after each VSync, minimizing
            // power consumption.
            DX::ThrowIfFailed(
                dxgiDevice->SetMaximumFrameLatency(1)
                );

            // Next, get the parent factory from the DXGI Device.
            ComPtr<IDXGIAdapter> dxgiAdapter;
            DX::ThrowIfFailed(
                dxgiDevice->GetAdapter(&dxgiAdapter)
                );

            ComPtr<IDXGIFactory2> dxgiFactory;
            DX::ThrowIfFailed(
                dxgiAdapter->GetParent(IID_PPV_ARGS(&dxgiFactory))
                );

            // Finally, create the swap chain.
            CoreWindow^ window = m_window.Get();
            DX::ThrowIfFailed(
                dxgiFactory->CreateSwapChainForCoreWindow(
                    m_d3dDevice.Get(),
                    reinterpret_cast<IUnknown*>(window),
                    &swapChainDesc,
                    nullptr, // Allow on all displays.
                    &m_swapChain
                    )
                );

4. 렌더링 대상 보기 생성

그래픽을 창에 렌더링하려면 렌더링 대상 뷰를 생성해야 합니다. IDXGISwapChain::GetBuffer를 호출하여 렌더링 대상 뷰를 생성할 때 사용할 스왑 체인의 백 버퍼를 가져옵니다. 백 버퍼를 2D 텍스처(ID3D11Texture2D)로 지정합니다. 렌더링 대상 보기를 생성하기 위해 스왑 체인의 백 버퍼를 사용하여 ID3D11Device::CreateRenderTargetView를 호출합니다. 보기 포트(D3D11_VIEWPORT)를 스왑 체인 백 버퍼의 전체 크기로 지정하여 전체 핵심 창을 그리도록 지정해야 합니다. ID3D11DeviceContext::RSSetViewports 호출에서 뷰 포트를 사용하여 뷰 포트를 파이프라인의 래스터라이저 단계에 바인딩합니다. 래스터라이저 단계에서는 벡터 정보를 래스터 이미지로 변환합니다. 이 경우 단색만 표시하기 때문에 변환이 불필요합니다.

        // Once the swap chain is created, create a render target view.  This will
        // allow Direct3D to render graphics to the window.

        ComPtr<ID3D11Texture2D> backBuffer;
        DX::ThrowIfFailed(
            m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
            );

        DX::ThrowIfFailed(
            m_d3dDevice->CreateRenderTargetView(
                backBuffer.Get(),
                nullptr,
                &m_renderTargetView
                )
            );


        // After the render target view is created, specify that the viewport,
        // which describes what portion of the window to draw to, should cover
        // the entire window.

        D3D11_TEXTURE2D_DESC backBufferDesc = {0};
        backBuffer->GetDesc(&backBufferDesc);

        D3D11_VIEWPORT viewport;
        viewport.TopLeftX = 0.0f;
        viewport.TopLeftY = 0.0f;
        viewport.Width = static_cast<float>(backBufferDesc.Width);
        viewport.Height = static_cast<float>(backBufferDesc.Height);
        viewport.MinDepth = D3D11_MIN_DEPTH;
        viewport.MaxDepth = D3D11_MAX_DEPTH;

        m_d3dDeviceContext->RSSetViewports(1, &viewport);

5. 렌더링된 이미지 표시

무한 루프를 입력하여 장면을 지속적으로 렌더링하고 표시합니다.

이 루프에서는 다음을 호출합니다.

  1. ID3D11DeviceContext::OMSetRenderTargets - 렌더링 대상을 출력 대상으로 지정합니다.
  2. ID3D11DeviceContext::ClearRenderTargetView - 렌더링 대상을 단색으로 지웁니다.
  3. IDXGISwapChain::Present - 렌더링된 이미지를 창에 표시합니다.

이전에 최대 프레임 대기 시간을 1로 설정했기 때문에 Windows는 일반적으로 렌더링 루프를 화면 새로 고침 속도(일반적으로 약 60Hz)로 늦추고 있습니다. Windows는 앱이 표시를 호출할 때 앱을 절전 모드로 설정하여 렌더링 루프를 느리게 합니다. Windows는 화면을 새로 고칠 때까지 앱을 절전 모드로 설정합니다.

        // Enter the render loop.  Note that UWP apps should never exit.
        while (true)
        {
            // Process events incoming to the window.
            m_window->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);

            // Specify the render target we created as the output target.
            m_d3dDeviceContext->OMSetRenderTargets(
                1,
                m_renderTargetView.GetAddressOf(),
                nullptr // Use no depth stencil.
                );

            // Clear the render target to a solid color.
            const float clearColor[4] = { 0.071f, 0.04f, 0.561f, 1.0f };
            m_d3dDeviceContext->ClearRenderTargetView(
                m_renderTargetView.Get(),
                clearColor
                );

            // Present the rendered image to the window.  Because the maximum frame latency is set to 1,
            // the render loop will generally be throttled to the screen refresh rate, typically around
            // 60 Hz, by sleeping the application on Present until the screen is refreshed.
            DX::ThrowIfFailed(
                m_swapChain->Present(1, 0)
                );
        }

6. 앱 창 및 스왑 체인의 버퍼 크기 조정

앱 창의 크기가 변경될 경우, 앱은 스왑 체인의 버퍼 크기를 조정하고, 렌더링 대상 보기를 다시 생성하며, 크기가 조정된 렌더링된 이미지를 표시해야 합니다. 스왑 체인의 버퍼 크기를 조정하기 위해 IDXGISwapChain::ResizeBuffers를 호출합니다. 이 호출에서, 버퍼의 수와 버퍼의 형식을 변경하지 않고 그대로 둡니다(BufferCount 매개 변수를 2로, NewFormat 매개 변수를 DXGI_FORMAT_B8G8R8A8_UNORM으로). 스왑 체인의 백 버퍼 크기를 크기 조정된 창과 동일한 크기로 만듭니다. 스왑 체인의 버퍼 크기를 조정한 후 새 렌더링 대상을 생성하고 앱을 초기화할 때와 비슷하게 렌더링된 새 이미지를 표시합니다.

            // If the swap chain already exists, resize it.
            DX::ThrowIfFailed(
                m_swapChain->ResizeBuffers(
                    2,
                    0,
                    0,
                    DXGI_FORMAT_B8G8R8A8_UNORM,
                    0
                    )
                );

요약 및 다음 단계

Direct3D 디바이스, 스왑 체인, 렌더링 대상 보기를 생성하고 렌더링된 이미지를 디스플레이에 표시했습니다.

다음으로 디스플레이에 삼각형을 그립니다.

셰이더 및 그리기 원형 만들기