~プログラミング~ DirectX 11で三角形を表示しよう

C++言語でDirectX 11を使ったアプリケーションを開発してみよう。 

 

DirectXの初期化シェーダーの準備が出来たらようやく図形が表示できます。

ここでは、簡単な三角形を表示させてみようと思います。

 

各頂点に色情報を持たせて色付きのポリゴンにしてみます。

 

頂点バッファーを作る

頂点データの準備

三角形を作るので3点の頂点データを作ります。

データはとりあえずグローバル変数として用意してみました。

各頂点は座標 x,y,z と色 r,g,b,a の情報を持てる Vertex という構造体を作ってみました。

struct Vertex {
        float pos[ 3 ];
        float col[ 4 ];
};

Vertex g_VertexList[] {
        { { -0.5f,  0.5f, 0.5f }, { 1.0f, 0.0f, 0.0f, 1.0f } },
        { {  0.5f, -0.5f, 0.5f }, { 0.0f, 1.0f, 0.0f, 1.0f } },
        { { -0.5f, -0.5f, 0.5f }, { 0.0f, 0.0f, 1.0f, 1.0f } }
};

頂点バッファーの作成

頂点データをDirect3Dのパイプラインに流し込む為のバッファーを作成します。

バッファーの作成にはID3D11Device::CreateBufferメソッドを使います。

        D3D11_BUFFER_DESC bufferDesc;
        bufferDesc.ByteWidth           = sizeof( Vertex ) * 3;
        bufferDesc.Usage               = D3D11_USAGE_DEFAULT;
        bufferDesc.BindFlags           = D3D11_BIND_VERTEX_BUFFER;
        bufferDesc.CPUAccessFlags      = 0;
        bufferDesc.MiscFlags           = 0;
        bufferDesc.StructureByteStride = 0;

        D3D11_SUBRESOURCE_DATA subResourceData;
        subResourceData.pSysMem          = g_VertexList;
        subResourceData.SysMemPitch      = 0;
        subResourceData.SysMemSlicePitch = 0;

        hr = m_pDevice->CreateBuffer( &bufferDesc, &subResourceData, &m_pVertexBuffer );
        if ( FAILED( hr ) )
                return hr;

D3D11_BUFFER_DESCD3D11_SUBRESOURCE_DATA という2つのパラメータを使ってバッファーを作成します。

 

D3D11_BUFFER_DESC

ByteWidth ・・・ バッファーのサイズを指定します。

BindFlags  ・・・ 頂点バッファーとしてバインドする為 D3D11_BIND_VERTEX_BUFFER

          を指定します。

 

D3D11_SUBRESOURCE_DATA

pSysMem ・・・ リソースデータのポインタを指定します。

その他の項目はテクスチャデータの場合にだけ使うものなので「0」を指定します。

インプットレイアウトを作る

インプットレイアウトとは、入力されたバッファーがどのようなデータ構造なのかを記述するものです。

 

DirectX 9 の時にはIDirect3DDevice9::SetFVFメソッドなどで頂点フォーマットを指定していました。

DirectX11 では入力バッファーがより柔軟なものになっており、データ構造の記述にはID3D11InputLayoutを使うようになっています。

頂点データの構造を記述

D3D11_INPUT_ELEMENT_DESC を使って頂点データの構造を定義します。

今回は座標と色を持つ構造体なのでD3D11_INPUT_ELEMENT_DESCは2レコードです。

それぞれ HLSL セマンティクスや要素のフォーマットなどを定義します。

D3D11_INPUT_ELEMENT_DESC g_VertexDesc[] {
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT,    0,                            0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "COLOR",    0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

インプットレイアウトの作成

上記の構造定義と頂点シェーダーのコンパイル済みコードを使ってインプットレイアウトを作成します。

シェーダーのコンパイル済みについてはこちらを参照してください。

インプットレイアウトの作成にはID3D11Device::CreateInputLayoutメソッドを使います。

    hr = m_pDevice->CreateInputLayout( g_VertexDesc, ARRAYSIZE( g_VertexDesc ),
                                       g_vs_main, sizeof( g_vs_main ),
                                       &m_pInputLayout );
    if ( FAILED( hr ) )
        return hr;

シェーダーオブジェクトを作る

コンパイル済みコードのバイト配列から頂点シェーダーとピクセルシェーダーのオブジェクトを作成します。

頂点シェーダーオブジェクトの作成にはID3D11Device::CreateVertexShaderメソッドを

ピクセルシェーダーオブジェクトの作成にはID3D11Device::CreatePixelShaderメソッドを使います。

 

    hr = m_pDevice->CreateVertexShader( &g_vs_main, sizeof( g_vs_main ), NULL, &m_pVertexShader );
    if ( FAILED( hr ) )
        return hr;

    hr = m_pDevice->CreatePixelShader( &g_ps_main, sizeof( g_ps_main ), NULL, &m_pPixelShader );
    if ( FAILED( hr ) )
        return hr;

ビューポートを作る

ビューポートは -1.0~1.0 の範囲で作られたワールド座標をスクリーン座標(表示するウインドウのサイズ)に変換するための情報で D3D11_VIEWPORT を使って定義します。

    CRect  rect;
        
    ::GetClientRect( hwnd, &rect );
    m_Viewport.TopLeftX = 0;
    m_Viewport.TopLeftY = 0;
    m_Viewport.Width    = (FLOAT)rect.Width();
    m_Viewport.Height   = (FLOAT)rect.Height();
    m_Viewport.MinDepth = 0.0f;
    m_Viewport.MaxDepth = 1.0f;

描画する

必要なオブジェクトが準備出来たら、それらをデバイスコンテキストへセットして描画します。

        UINT strides = sizeof( Vertex );
        UINT offsets = 0;
        m_pImmediateContext->IASetInputLayout( m_pInputLayout );
        m_pImmediateContext->IASetVertexBuffers( 0, 1, &m_pVertexBuffer, &strides, &offsets );
        m_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
        m_pImmediateContext->VSSetShader( m_pVertexShader, NULL, 0 );
        m_pImmediateContext->RSSetViewports( 1, &m_Viewport );
        m_pImmediateContext->PSSetShader( m_pPixelShader, NULL, 0 );

        m_pImmediateContext->Draw( 3, 0 );

        m_pSwapChain->Present( 0, 0 );

インプットレイアウト → ID3D11DeviceContext::IASetInputLayoutメソッド

頂点バッファ     → ID3D11DeviceContext::IASetVertexBuffersメソッド

頂点シェーダー    → ID3D11DeviceContext::VSSetShaderメソッド

ピクセルシェーダー  → ID3D11DeviceContext::PSSetShaderメソッド

ビューポート     → ID3D11DeviceContext::RSSetViewportsメソッド

 

さらに頂点バッファがどのような順番で三角形を作るかをID3D11DeviceContext::IASetPrimitiveTopologyメソッドで指定します。

 

すべてセット出来たらID3D11DeviceContext::Drawメソッドで描画します。

 

 

 

 

 

 

 

うまく出来たらこんな感じに表示されると思います。

 

ソースコードはこちら