Aracılığıyla paylaş


DirectX kaynaklarını ayarlama ve görüntü görüntüleme

Burada Direct3D cihazı oluşturma, zincir değiştirme ve işleme hedefi görünümünün nasıl oluşturulacağını ve işlenen görüntünün ekrana nasıl sunacağınız gösterilmektedir.

Amaç: C++ Evrensel Windows Platformu (UWP) uygulamasında DirectX kaynaklarını ayarlamak ve düz bir renk görüntülemek.

Önkoşullar

C++ hakkında bilgi sahibi olduğunuzu varsayıyoruz. Ayrıca grafik programlama kavramlarıyla ilgili temel deneyime de ihtiyacınız vardır.

Tamamlanma süresi: 20 dakika.

Yönergeler

1. ComPtr ile Direct3D arabirim değişkenlerini bildirme

Windows Çalışma Zamanı C++ Şablon Kitaplığı'ndan (WRL) ComPtr akıllı işaretçi şablonuyla Direct3D arabirim değişkenlerini bildiririz, böylece bu değişkenlerin ömrünü özel durum güvenli bir şekilde yönetebiliriz. Ardından bu değişkenleri kullanarak ComPtr sınıfına ve üyelerine erişebiliriz. Örneğin:

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

ComPtr ile ID3D11RenderTargetView bildirirseniz, Ardından, id3D11RenderTargetView (**ID3D11RenderTargetView) işaretçisinin adresini ID3D11DeviceContext::OMSetRenderTargetsgeçirmek için ComPtr'nin GetAddressOf yöntemini kullanabilirsiniz. OMSetRenderTargets , işleme hedefini çıkış hedefi olarak belirtmek için işleme hedefini çıkış birleştirme aşamasına bağlar.

Örnek uygulama başlatıldıktan sonra başlatılır ve yüklenir ve çalışmaya hazır olur.

2. Direct3D cihazı oluşturma

Bir sahneyi işlemek için Direct3D API'sini kullanmak için önce görüntü bağdaştırıcısını temsil eden bir Direct3D cihazı oluşturmamız gerekir. Direct3D cihazını oluşturmak için D3D11CreateDevice işlevini çağırırız. D3D_FEATURE_LEVEL değerleri dizisinde düzey 9.1 ile 11.1 arasında bir değer belirtiriz. Direct3D diziyi sırayla gösterir ve desteklenen en yüksek özellik düzeyini döndürür. Bu nedenle, kullanılabilir en yüksek özellik düzeyini elde etmek için en yüksekten en düşüğe D3D_FEATURE_LEVEL dizi girdilerini listeleyeceğiz. Direct3D kaynaklarının Direct2D ile birlikte çalışabilmesi için flags parametresine D3D11_CREATE_DEVICE_BGRA_SUPPORT bayrağını geçiririz. Hata ayıklama derlemesini kullanırsak D3D11_CREATE_DEVICE_DEBUG bayrağını da geçiririz. Uygulamalarda hata ayıklama hakkında daha fazla bilgi için bkz. Uygulamalarda hata ayıklamak için hata ayıklama katmanını kullanma.

Direct3D 11.1 cihazını (ID3D11Device1) ve cihaz bağlamını (ID3D11DeviceContext1) D3D11CreateDevice'den döndürülen Direct3D 11 cihazını ve cihaz bağlamını sorgulayarak elde ederiz.

        // 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. Takas zinciri oluşturma

Ardından, cihazın işleme ve görüntüleme için kullandığı bir takas zinciri oluşturacağız. Takas zincirini tanımlamak amacıyla bir DXGI_SWAP_CHAIN_DESC1 yapısını ilan eder ve başlatırız. Ardından takas zincirini flip-model (yani SwapEffect üyesinde DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL değeri ayarlanmış bir takas zinciri) olarak ayarlayıp Format üyesini DXGI_FORMAT_B8G8R8A8_UNORM olarak ayarlıyoruz. SampleDesc üyesinin belirttiği DXGI_SAMPLE_DESC yapısının Adet üyesini 1 ve DXGI_SAMPLE_DESC yapısının Kalite üyesini sıfır olarak ayarladık çünkü "flip-model" birden çok örnek antialiasing (MSAA) desteklemez. Takas zincirinin görüntüleme cihazına sunum yapmak için bir ön tampon bellek ve işleme hedefi olarak hizmet veren bir arka tampon bellek kullanabilmesi amacıyla BufferCount üyesini 2 olarak ayarladık.

Direct3D 11.1 cihazını sorgulayarak temel alınan DXGI cihazını elde ediyoruz. Dizüstü bilgisayarlar ve tabletler gibi pille çalışan cihazlarda yapılması gereken güç tüketimini en aza indirmek için DXGI'nın kuyruğa alabildiği maksimum arka arabellek çerçevesi sayısı olarak IDXGIDevice1::SetMaximumFrameLatency yöntemini 1 olarak adlandırıyoruz. Bu, uygulamanın yalnızca dikey boşluk sonrasında işlenmesini sağlar.

Son olarak takas zincirini oluşturmak için DXGI cihazından ana fabrikayı almalıyız. Cihaz için bağdaştırıcıyı elde etmek amacıyla IDXGIDevice::GetAdapter çağrısı yapıyoruz ve ardından üst fabrikayı elde etmek amacıyla bağdaştırıcı üzerinde IDXGIObject::GetParent çağrısı yapıyoruz (IDXGIFactory2). Takas zincirini oluşturmak için, takas zinciri tanımlayıcısı ve uygulamanın çekirdek penceresiyle birlikte IDXGIFactory2::CreateSwapChainForCoreWindow işlevini çağırırız.

            // 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. İşleme hedefi görüntüsünü oluşturma

Grafikleri pencerede işlemek için bir işleme hedefi görünümü oluşturmamız gerekir. İşleme hedefi görünümünü oluştururken kullanılacak takas zincirinin geri arabelleğine ulaşmak için IDXGISwapChain::GetBuffer çağrısı yapıyoruz. Arka arabelleği 2B doku (ID3D11Texture2D) olarak belirtiyoruz. İşleme hedefi görünümünü oluşturmak için ID3D11Device::CreateRenderTargetView takas zincirinin arka arabelleği ile çağırırız. Değişim zincirinin geri arabelleğinin tam boyutunu görünüm alanı (D3D11_VIEWPORT) olarak belirterek tüm çekirdek pencereye çizim yapmamız gerekiyor. Görünüm bağlantı noktasını, işlem hattının rasterizer aşamasına bağlamak için ID3D11DeviceContext::RSSetViewports çağrısında kullanırız. Rasterizer aşaması vektör bilgilerini bir raster görüntüsüne dönüştürür. Bu durumda, yalnızca düz bir renk görüntülediğimiz için dönüştürmeye gerek yoktur.

        // 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. İşlenen görüntüyü sunma

Sahneyi sürekli işlemek ve görüntülemek için sonsuz bir döngüye giriyoruz.

Bu döngüde şunları çağırırız:

  1. ID3D11DeviceContext::OMSetRenderTargets ile işleme hedefini çıkış hedefi olarak belirtmek için.
  2. ID3D11DeviceContext::ClearRenderTargetView işleme hedefini düz bir renge temizleyin.
  3. İşlenen görüntüyü pencereye sunmak için IDXGISwapChain::P resent .

Daha önce maksimum kare gecikme süresini 1 olarak ayarladığımız için Windows genellikle işleme döngüsünü genellikle 60 Hz civarında ekran yenileme hızına yavaşlatır. Windows, uygulama presentçağırdığında, uygulamayı uyku moduna alarak işleme döngüsünü yavaşlatır. Windows, ekran yenilenene kadar uygulamayı uyku moduna alır.

        // 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. Uygulama penceresini ve takas zinciri tamponunu yeniden boyutlandırma

Uygulama penceresinin boyutu değişirse, uygulamanın değiştirme zincirinin arabelleklerini yeniden boyutlandırması, işleme hedefi görünümünü yeniden oluşturup ardından yeniden boyutlandırılan işlenmiş görüntüyü sunması gerekir. Değişim zincirinin arabelleklerini yeniden boyutlandırmak için IDXGISwapChain::ResizeBuffers fonksiyonunu çağırıyoruz . Bu çağrıda, arabellek sayısını (BufferCount parametresi iki) ve arabelleklerin biçimini (NewFormat parametresi DXGI_FORMAT_B8G8R8A8_UNORM) değiştirmiyoruz. Swap zincirinin arka arabelleğinin boyutunu, yeniden boyutlandırılan pencereyle aynı boyuta eşitleriz. Swap zincirinin tamponlarını yeniden boyutlandırdıktan sonra, yeni görüntüleme hedefini oluşturur ve yeni işlenen görüntüyü, uygulamayı başlattığımız zamanki gibi sunarız.

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

Özet ve sonraki adımlar

Bir Direct3D cihazı, takas zinciri ve işleme hedefi görünümü oluşturduk ve işlenen görüntüyü ekrana sunduk.

Ardından, ekrana bir üçgen çizeceğiz.

Gölgelendiriciler oluşturma ve temel öğeler çizme