셰이더 및 그리기 기본 요소 만들기
여기서는 HLSL 원본 파일을 사용하여 셰이더를 컴파일하고 만든 다음 디스플레이에 기본 형식을 그리는 데 사용할 수 있는 방법을 보여 줍니다.
꼭짓점 및 픽셀 셰이더를 사용하여 노란색 삼각형을 만들고 그립니다. Direct3D 디바이스, 스왑 체인 및 렌더링 대상 뷰를 만든 후 디스크의 이진 셰이더 개체 파일에서 데이터를 읽습니다.
목표: 셰이더를 만들고 기본 형식을 그립니다.
필수 조건
사용자가 C++에 익숙하다고 가정합니다. 그래픽 프로그래밍 개념에 대한 기본 경험도 필요합니다.
또한 빠른 시작: DirectX 리소스를 설정하고 이미지 표시를 거쳤다고 가정합니다.
완료 시간: 20분.
지침
1. HLSL 원본 파일 컴파일
Microsoft Visual Studio는 fxc.exe HLSL 코드 컴파일러를 사용하여 .hlsl 소스 파일(SimpleVertexShader.hlsl 및 SimplePixelShader.hlsl)을 .cso 이진 셰이더 개체 파일(SimpleVertexShader.cso 및 SimplePixelShader.cso)로 컴파일합니다. HLSL 코드 컴파일러에 대한 자세한 내용은 효과-컴파일러 도구를 참조하세요. 셰이더 코드 컴파일에 대한 자세한 내용은 셰이더 컴파일을 참조하세요.
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을 호출하여 레이아웃을 만듭니다. 배열에는 꼭짓점 위치를 정의하는 하나의 레이아웃 요소가 있습니다. SimplePixelShader.cso 파일에서 데이터를 읽고 pixelShaderBytecode 바이트 배열에 데이터를 할당합니다. 바이트 배열을 사용하여 ID3D11Device::CreatePixelShader를 호출하여 픽셀 셰이더(ID3D11PixelShader)를 만듭니다. 삼각형을 노란색으로 만들기 위해 SimplePixelShader.hlsl 소스에서 픽셀 값을 (1,1,1,1,1)로 설정합니다. 이 값을 변경하여 색을 변경할 수 있습니다.
간단한 삼각형을 정의하는 꼭짓점 및 인덱스 버퍼를 만듭니다. 먼저 삼각형을 정의하고, 다음으로 삼각형 정의를 사용하여 꼭짓점 및 인덱스 버퍼(D3D11_BUFFER_DESC 및 D3D11_SUBRESOURCE_DATA)를 설명하고, 최종적으로 각 버퍼에 대해 ID3D11Device::CreateBuffer를 한 번씩 호출합니다.
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를 호출하여 렌더링 대상을 출력 대상으로 지정합니다. 렌더링 대상을 단색 파란색으로 지우려면 ID3D11DeviceContext::ClearRenderTargetView를 { 0.071f, 0.04f, 0.561f, 1.0f }로 호출합니다.
무한 루프에서는 파란색 표면에 노란색 삼각형을 그립니다.
노란색 삼각형을 그리려면
- 먼저 ID3D11DeviceContext::IASetInputLayout을 호출하여 꼭짓점 버퍼 데이터가 입력 어셈블러 단계로 스트리밍되는 방법을 설명합니다.
- 다음으로 ID3D11DeviceContext::IASetVertexBuffers 및 ID3D11DeviceContext::IASetIndexBuffer를 호출하여 꼭짓점 및 인덱스 버퍼를 입력 어셈블러 단계에 바인딩합니다.
- ID3D11DeviceContext::IASetPrimitiveTopology를 D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP 값과 함께 호출하여, 꼭짓점 데이터를 삼각형 스트립으로 해석할 입력-어셈블러 단계를 지정합니다.
- 다음으로, ID3D11DeviceContext::VSSetShader를 호출하여 꼭짓점 셰이더 코드와 ID3D11DeviceContext::PSSetShader를 사용하여 꼭짓점 셰이더 단계를 초기화하여 픽셀 셰이더 코드를 사용하여 픽셀 셰이더 단계를 초기화합니다.
- 마지막으로 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 큐브를 만들고 조명 효과를 적용합니다.