ここでは、HLSL ソース ファイルを使用してシェーダーをコンパイルおよび作成し、それを使用してディスプレイにプリミティブを描画する方法について説明します。
頂点シェーダーとピクセル シェーダーを使用して、黄色の三角形を作成して描画します。 Direct3D デバイス、スワップ チェーン、レンダー ターゲット ビューを作成した後、ディスク上のバイナリ シェーダー オブジェクト ファイルからデータを読み取ります。
目的: シェーダーを作成し、プリミティブを描画するには。
[前提条件]
C++ に精通していることを前提としています。 また、グラフィックス プログラミングの概念に関する基本的な経験も必要です。
また、 DirectX リソースの設定とイメージの表示に関するクイック スタートも行ったことを前提としています。
完了までの時間: 20 分。
インストラクション
1. HLSL ソース ファイルのコンパイル
Microsoft Visual Studio では 、fxc.exe HLSL コード コンパイラを使用して、.hlsl ソース ファイル (SimpleVertexShader.hlsl および SimplePixelShader.hlsl) を .cso バイナリ シェーダー オブジェクト ファイル (SimpleVertexShader.cso および SimplePixelShader.cso) にコンパイルします。 HLSL コード コンパイラの詳細については、「Effect-Compiler ツール」を参照してください。 シェーダー コードのコンパイルの詳細については、「シェーダーの コンパイル」を参照してください。
SimpleVertexShader.hlsl のコードを次に示します。
struct VertexShaderInput
{
DirectX::XMFLOAT2 pos : POSITION;
};
struct PixelShaderInput
{
float4 pos : SV_POSITION;
};
PixelShaderInput SimpleVertexShader(VertexShaderInput input)
{
PixelShaderInput vertexShaderOutput;
// For this lesson, set the vertex depth value to 0.5, so it is guaranteed to be drawn.
vertexShaderOutput.pos = float4(input.pos, 0.5f, 1.0f);
return vertexShaderOutput;
}
SimplePixelShader.hlsl のコードを次に示します。
struct PixelShaderInput
{
float4 pos : SV_POSITION;
};
float4 SimplePixelShader(PixelShaderInput input) : SV_TARGET
{
// Draw the entire triangle yellow.
return float4(1.0f, 1.0f, 0.0f, 1.0f);
}
2. ディスクからのデータの読み取り
DirectX 11 アプリ (ユニバーサル Windows) テンプレートの DirectXHelper.h の DX::ReadDataAsync 関数を使用して、ディスク上のファイルから非同期的にデータを読み取ります。
3. 頂点シェーダーとピクセル シェーダーの作成
SimpleVertexShader.cso ファイルからデータを読み取り、そのデータを vertexShaderBytecode バイト配列に割り当てます。 バイト配列を使用 して ID3D11Device::CreateVertexShader を呼び出し、頂点シェーダー (ID3D11VertexShader) を作成します。 SimpleVertexShader.hlsl ソースで頂点の深度値を 0.5 に設定して、三角形が描画されることを保証します。 頂点シェーダー コードのレイアウトを記述するために D3D11_INPUT_ELEMENT_DESC 構造体の配列を設定し、 ID3D11Device::CreateInputLayout を呼び出してレイアウトを作成します。 配列には、頂点の位置を定義する 1 つのレイアウト要素があります。 SimplePixelShader.cso ファイルからデータを読み取り、 pixelShaderBytecode バイト配列にデータを割り当てます。 バイト配列を使用 して ID3D11Device::CreatePixelShader を呼び出し、ピクセル シェーダー (ID3D11PixelShader) を作成します。 SimplePixelShader.hlsl ソースでピクセル値を (1,1,1,1) に設定して、三角形を黄色にします。 この値を変更することで、色を変更できます。
単純な三角形を定義する頂点バッファーとインデックス バッファーを作成します。 これを行うには、まず三角形を定義し、次に三角形定義を使用して頂点バッファーとインデックス バッファー (D3D11_BUFFER_DESC と D3D11_SUBRESOURCE_DATA) を記述し、最後にバッファーごとに ID3D11Device::CreateBuffer を 1 回呼び出します。
auto loadVSTask = DX::ReadDataAsync(L"SimpleVertexShader.cso");
auto loadPSTask = DX::ReadDataAsync(L"SimplePixelShader.cso");
// Load the raw vertex shader bytecode from disk and create a vertex shader with it.
auto createVSTask = loadVSTask.then([this](const std::vector<byte>& vertexShaderBytecode) {
ComPtr<ID3D11VertexShader> vertexShader;
DX::ThrowIfFailed(
m_d3dDevice->CreateVertexShader(
vertexShaderBytecode->Data,
vertexShaderBytecode->Length,
nullptr,
&vertexShader
)
);
// Create an input layout that matches the layout defined in the vertex shader code.
// For this lesson, this is simply a DirectX::XMFLOAT2 vector defining the vertex position.
const D3D11_INPUT_ELEMENT_DESC basicVertexLayoutDesc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
ComPtr<ID3D11InputLayout> inputLayout;
DX::ThrowIfFailed(
m_d3dDevice->CreateInputLayout(
basicVertexLayoutDesc,
ARRAYSIZE(basicVertexLayoutDesc),
vertexShaderBytecode->Data,
vertexShaderBytecode->Length,
&inputLayout
)
);
});
// Load the raw pixel shader bytecode from disk and create a pixel shader with it.
auto createPSTask = loadPSTask.then([this](const std::vector<byte>& pixelShaderBytecode) {
ComPtr<ID3D11PixelShader> pixelShader;
DX::ThrowIfFailed(
m_d3dDevice->CreatePixelShader(
pixelShaderBytecode->Data,
pixelShaderBytecode->Length,
nullptr,
&pixelShader
)
);
});
// Create vertex and index buffers that define a simple triangle.
auto createTriangleTask = (createPSTask && createVSTask).then([this] () {
DirectX::XMFLOAT2 triangleVertices[] =
{
float2(-0.5f, -0.5f),
float2( 0.0f, 0.5f),
float2( 0.5f, -0.5f),
};
unsigned short triangleIndices[] =
{
0, 1, 2,
};
D3D11_BUFFER_DESC vertexBufferDesc = {0};
vertexBufferDesc.ByteWidth = sizeof(float2) * ARRAYSIZE(triangleVertices);
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;
vertexBufferDesc.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA vertexBufferData;
vertexBufferData.pSysMem = triangleVertices;
vertexBufferData.SysMemPitch = 0;
vertexBufferData.SysMemSlicePitch = 0;
ComPtr<ID3D11Buffer> vertexBuffer;
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&vertexBufferDesc,
&vertexBufferData,
&vertexBuffer
)
);
D3D11_BUFFER_DESC indexBufferDesc;
indexBufferDesc.ByteWidth = sizeof(unsigned short) * ARRAYSIZE(triangleIndices);
indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
indexBufferDesc.CPUAccessFlags = 0;
indexBufferDesc.MiscFlags = 0;
indexBufferDesc.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA indexBufferData;
indexBufferData.pSysMem = triangleIndices;
indexBufferData.SysMemPitch = 0;
indexBufferData.SysMemSlicePitch = 0;
ComPtr<ID3D11Buffer> indexBuffer;
DX::ThrowIfFailed(
m_d3dDevice->CreateBuffer(
&indexBufferDesc,
&indexBufferData,
&indexBuffer
)
);
});
頂点シェーダーとピクセル シェーダー、頂点シェーダー レイアウト、頂点バッファーとインデックス バッファーを使用して、黄色の三角形を描画します。
4. 三角形を描画し、レンダリングされたイメージを表示する
無限ループに入り、シーンを継続的にレンダリングして表示します。 ID3D11DeviceContext::OMSetRenderTargets を呼び出して、出力ターゲットとしてレンダー ターゲットを指定します。 {0.071f、0.04f、0.561f、1.0f} で ID3D11DeviceContext::ClearRenderTargetView を呼び出して、レンダー ターゲットを単色の青にクリアします。
無限ループでは、青い表面に黄色の三角形を描画します。
黄色の三角形を描画するには
- まず、 ID3D11DeviceContext::IASetInputLayout を呼び出して、頂点バッファー データを入力アセンブラー ステージにストリーム配信する方法について説明します。
- 次に、 ID3D11DeviceContext::IASetVertexBuffers と ID3D11DeviceContext::IASetIndexBuffer を呼び出して、頂点バッファーとインデックス バッファーを入力アセンブラー ステージにバインドします。
- 次に、入力アセンブラー ステージが頂点データを三角形ストリップとして解釈するように指定するため、ID3D11DeviceContext::IASetPrimitiveTopology を呼び出し、D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP 値を使用します。
- 次に、 ID3D11DeviceContext::VSSetShader を呼び出して頂点シェーダー コードを使用して頂点シェーダー ステージを初期化し 、ID3D11DeviceContext::P SSetShader を呼び出してピクセル シェーダー コードでピクセル シェーダー ステージを初期化します。
- 最後に、ID3D11DeviceContext::DrawIndexed を呼び出して三角形を描画し、レンダリング パイプラインに送信します。
IDXGISwapChain::Present を呼び出し、描画されたイメージをウィンドウに表示します。
// 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
);
m_d3dDeviceContext->IASetInputLayout(inputLayout.Get());
// Set the vertex and index buffers, and specify the way they define geometry.
UINT stride = sizeof(float2);
UINT offset = 0;
m_d3dDeviceContext->IASetVertexBuffers(
0,
1,
vertexBuffer.GetAddressOf(),
&stride,
&offset
);
m_d3dDeviceContext->IASetIndexBuffer(
indexBuffer.Get(),
DXGI_FORMAT_R16_UINT,
0
);
m_d3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Set the vertex and pixel shader stage state.
m_d3dDeviceContext->VSSetShader(
vertexShader.Get(),
nullptr,
0
);
m_d3dDeviceContext->PSSetShader(
pixelShader.Get(),
nullptr,
0
);
// Draw the cube.
m_d3dDeviceContext->DrawIndexed(
ARRAYSIZE(triangleIndices),
0,
0
);
// 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)
);
概要と次の手順
頂点シェーダーとピクセル シェーダーを使用して、黄色の三角形を作成して描画しました。
次に、周回する 3D キューブを作成し、それに照明効果を適用します。