10
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

DirectX(D3D11.1)再入門 Input-Assembler

Last updated at Posted at 2014-11-25

そろそろD3D9とおさらばしたいということでD3D11を練習し始めました。

4年前にD3D9使い浦島太郎のD3D11入門でも同じことを言われております。

登場以来D3D11のAPIは変わっていないのだけど、最近の更新でSDKがVisualStudio(2012以降?)に付属するようになって、D3DX11が消滅、DirectXMath(旧XNAMath)が導入されるなどの変化があったので、今の開発環境(VisualStudio2013CE)ではどうするのかということをまとめていきたい。

Hello Triangle

まずは、第2話 浦島太郎 魚をつるをベースに三角形を描画してみた。
MinTriangle.png

今回のソース

初期化に関しては、第1話 戻ってきた浦島太郎で説明されているので省略。

DirectX SDKがVisualStudioに含まれるようになったので、個別にSDKをインストールしたり追加のInclude, Libディレクトリを指定する必要がなくなった。新しいD3D11はD3DXが消滅している。あと、XNAMathからDirectXMathになった。

描画関数は以下のようにしたのだけど

void D3D11Manager::Render()
{
    ////////////////////
    // レンダーターゲットのセットと単色クリア
    ////////////////////

    if(!m_renderTarget->IsInitialized()){
        // バックバッファの取得
        ResPtr<ID3D11Texture2D> pBackBuffer;
        m_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
                reinterpret_cast<void**>(&pBackBuffer));

        if(!m_renderTarget->Initialize(m_pDevice, pBackBuffer)){
            return;
        }
    }
    m_renderTarget->SetAndClear(m_pDeviceContext);

    ////////////////////
    // 三角形描画
    ////////////////////
    // shader
    m_shader->Setup(m_pDeviceContext);

    // 描画
    // vertex buffer(Input-Assembler stage)
    m_IASource->Draw(m_pDeviceContext);

    ////////////////////
    // 描画結果の転送
    ////////////////////
    // render targetへの描画
    m_pDeviceContext->Flush();

    // 描画済みのrender targetをモニタに出力
    m_pSwapChain->Present(NULL, NULL);
}

三角形を描画しているのは次の2行。

    // shader
    m_shader->Setup(m_pDeviceContext);

    // vertex buffer(Input-Assembler stage)
    m_IASource->Draw(m_pDeviceContext);

中身は以下のようになっております。

    // Shaderのセットアップ
    void Setup(ID3D11DeviceContext *pDeviceContext)
    {
        pDeviceContext->VSSetShader(m_pVsh, NULL, 0);
        pDeviceContext->PSSetShader(m_pPsh, NULL, 0);

        // 頂点レイアウトのセット
        pDeviceContext->IASetInputLayout(m_pInputLayout);
    }

    void Draw(ID3D11DeviceContext *pDeviceContext)
    {
        // 頂点バッファ
        ID3D11Buffer* pBufferTbl[] = { m_pVertexBuf };
        UINT SizeTbl[] = { sizeof(Vertex) };
        UINT OffsetTbl[] = { 0 };
        pDeviceContext->IASetVertexBuffers(0, 1, pBufferTbl, SizeTbl, OffsetTbl);

        // インデックスバッファ
        pDeviceContext->IASetIndexBuffer(m_pIndexBuf, DXGI_FORMAT_R32_UINT, 0);

        // プリミティブタイプのセット
        pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);

        // Draw
        pDeviceContext->DrawIndexed(3 // index count
                , 0, 0);
    }

ほぼID3D11DeviceContextの呼び出しで、

  • ID3D11DeviceContextのVertex-Shader stageにID3D11VertexShaderをセット
  • ID3D11DeviceContextにPixel-Shader stageにID3D11PixelShaderをセット
  • ID3D11DeviceContextのInput-Assembler stageにID3D11InputLayoutをセット
  • ID3D11DeviceContextのInput-Assembler stageのVertexBufferにID3D11Bufferをセット
  • ID3D11DeviceContextのInput-Assembler stageにIndexBufferにID3D11Bufferをセット
  • ID3D11DeviceContextのInput-Assembler stageにプリミティブ型をセット
  • ID3D11DeviceContextのDrawIndexedをコールする

シェーダーをセットしInput-Assemblerに頂点を供給してからDrawをコールするというのが大枠になる。

HLSL記述とInputLayoutの対応について

今回のシェーダーは以下の記述をしていた。

struct VS_INPUT
{
    float4 Position   : POSITION;
    float4 Color      : COLOR;
};

struct VS_OUTPUT
{
    float4 Position   : SV_POSITION;
    float4 Color      : COLOR;
};

VS_OUTPUT vsMain( VS_INPUT In )
{
    VS_OUTPUT Output;
    Output.Position = In.Position;
    Output.Color    = In.Color;
    return Output;    
}

float4 psMain( VS_OUTPUT In ) : SV_TARGET
{
    return In.Color;
}

VertexShaderのエントリポイントが

struct VS_INPUT
{
    float4 Position   : POSITION;
    float4 Color      : COLOR;
};

VS_OUTPUT vsMain( VS_INPUT In )
{
// 省略
}

となっている(compileする時に"vsMain"を指定する。hlsl上ではただの関数)。
これは、下記のように書くのとだいたい同じらしく(In変数は無くなる)

VS_OUTPUT vsMain(float4 Color: COLOR, float4 Position: POSITION) // VS_INPUTを順番に展開
{
// 省略
}

VertexShaderステージのvsMainにはfloat4の変数が2つ入力するとわかる。

こいつに対して頂点用のID3D11Bufferを作る時のバイト列を投入したい。

typedef struct D3D11_SUBRESOURCE_DATA {
    const void *pSysMem; // <- これ
    UINT SysMemPitch;
    UINT SysMemSlicePitch;
} D3D11_SUBRESOURCE_DATA;

プログラム側でバイト列のレイアウトを宣言するのが次のコード。

        // Create InputLayout
        D3D11_INPUT_ELEMENT_DESC vbElement[] =
        {
            { 
            "POSITION" // SemanticName
            , 0
            , DXGI_FORMAT_R32G32B32A32_FLOAT
            , 0
            , 0
            , D3D11_INPUT_PER_VERTEX_DATA
            , 0 
            },
            { 
            "COLOR" // SemanticName
            , 0
            , DXGI_FORMAT_R32G32B32A32_FLOAT
            , 0
            , D3D11_APPEND_ALIGNED_ELEMENT
            , D3D11_INPUT_PER_VERTEX_DATA
            , 0 
            }
        };

        hr = pDevice->CreateInputLayout(vbElement
        , sizeof(vbElement) / sizeof(D3D11_INPUT_ELEMENT_DESC)
        , vblob->GetBufferPointer(), vblob->GetBufferSize()
        , &m_pInputLayout);

D3D11_INPUT_ELEMENT_DESC structure

1頂点につきfloat4に相当するDXGI_FORMAT_R32G32B32A32_FLOATが2つで、それぞれに"POSITION", "COLOR"というSemanticNameがついているという宣言。
コンパイル済みのVertexShaderのバイトコード(vblob)からSemanticsNameを探したりしているのではないか。

"SemanticName"は勝手に決めていいらしくPOSITIONをHOGE, COLORをFUGAに変えてやってみたら問題なく動いた。システム定義のSemanticNameは、プレフィックスに"SV"がつくのでそれに名前が被らなければたぶんOK。

ということで今回はここまで。

次回、ConstantBufferを導入して三角形が回転する。予定。

参考

10
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?