close

知道如何創造windows display後,接下來就要設定Direct3D 11 device

要新增兩個東西:device & swap chain

The device object is used by the application to perform rendering onto a buffer. 

The device also contains methods to create resources.

swap chain至少包涵兩個buffer,一個是front buffer,另一個是back buffer

front 為 read-only ,不可修改

back 為 device 繪圖的目的端

當 device 在 back buffer 上繪圖完成,則swap front & back buffer,back 變成 front,front 變成 back

而新增 swap chain 是使用 DXGI_SWAP_CHAIN_DESC 這個 struct,以下是範例:

 DXGI_SWAP_CHAIN_DESC sd;
    ZeroMemory( &sd, sizeof(sd) );
    sd.BufferCount = 1;
    sd.BufferDesc.Width = 640;
    sd.BufferDesc.Height = 480;
    sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    sd.BufferDesc.RefreshRate.Numerator = 60;
    sd.BufferDesc.RefreshRate.Denominator = 1;
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    sd.OutputWindow = g_hWnd;
    sd.SampleDesc.Count = 1;
    sd.SampleDesc.Quality = 0;
    sd.Windowed = TRUE;
    if( FAILED( D3D11CreateDeviceAndSwapChain( NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, 0, featureLevels, 
numFeatureLevels, D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, NULL, 
&g_pImmediateContext ) ) ) {
        return FALSE;
}
==========================================================
關於 DXGI_SWAP_CHAIN_DESC 的補充:
typedef struct DXGI_SWAP_CHAIN_DESC
DXGI_MODE_DESC BufferDesc; 
DXGI_SAMPLE_DESC SampleDesc; 
DXGI_USAGE BufferUsage; 
UINT BufferCount; 
HWND OutputWindow; 
BOOL Windowed; 
DXGI_SWAP_EFFECT SwapEffect; 
UINT Flags; } DXGI_SWAP_CHAIN_DESC;
==========================================================
關於 D3D11CreateDeviceAndSwapChain 的補充:
請參考 ref. D3D11CreateDeviceAndSwapChain Function
==========================================================
接著是 create render target view 的部份
因為要將 render target view 綁定在 back buffer 之上 Direct3D 11 才能在上面繪圖
GetBuffer() 可用來設定 back buffer object
新增 render target view 可用 CreateRenderTargetView() 
在此範例中,default render target view 已經足夠,所以 CreateRenderTargetView 中第二個參數使用 NULL
當新增完成後,immediate context 的參數可呼叫 OMSetRenderTargets() 將此 render target 綁在 pipeline 之上
確保繪圖的結果會畫在 back buffer 之上,以下是程式碼:
    // Create a render target view
    ID3D11Texture2D *pBackBuffer;
    if( FAILED( g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), (LPVOID*)&pBackBuffer ) ) )
        return FALSE;
    hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView );
    pBackBuffer->Release();
    if( FAILED( hr ) )
        return FALSE;
    g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL );
 
最後一件事就是設定 viewportX, Y 的範圍是 -1~1 ,Z 的範圍是 0~1
在 Direct3D 9 ,如果沒有設定 viewport,系統會自動預設,大小跟 render target 一樣
但在 Direct3D 11,沒有預設值,所以必須自行設定
通常將畫面的左上角座標設為(0, 0),size 與 render target 相同,程式碼如下:
    D3D11_VIEWPORT vp;
    vp.Width = (FLOAT)width;
    vp.Height = (FLOAT)height;
    vp.MinDepth = 0.0f;
    vp.MaxDepth = 1.0f;
    vp.TopLeftX = 0;
    vp.TopLeftY = 0;
    g_pImmediateContext->RSSetViewports( 1, &vp );
 
最後,是 get message 的部份,原先的 GetMessage() 有個問題存在
那就是當佇列中沒有訊息時,這個函式會鎖住整個應用程式,直到有訊息要輸出為止
而解決辦法就是使用 PeekMessage(),它接收訊息的功能同 GetMessage(),但是當佇列沒有訊息時,
它會馬上 return,而不是鎖住程式
    MSG msg = {0};
    while( WM_QUIT != msg.message )
    {
        if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
        {
            TranslateMessage( &msg );
            DispatchMessage( &msg );
        }
        else
        {
            Render();  // Do some rendering
        }
    }
繪圖的功能會寫在 Render() 函式中,這個範例程式使用最簡單的 - 把背景塗成單一藍色
當畫完 back buffer 後,swap chain 的 Present() 函式會將畫面顯示,以下是 Render():
    void Render()
    {
        //
        // Clear the backbuffer
        //
        float ClearColor[4] = { 0.0f, 0.125f, 0.6f, 1.0f }; // RGBA
        g_pd3dDevice->ClearRenderTargetView( g_pRenderTargetView, ClearColor );
    
        g_pSwapChain->Present( 0, 0 );
    }
其中 ClearRenderTargetView() 可將畫面清除成某一顏色


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 Genius 的頭像
    Genius

    Nobody

    Genius 發表在 痞客邦 留言(0) 人氣()