기본 메시 만들기 및 표시

3차원 UWP(유니버설 Windows 플랫폼) 게임은 일반적으로 다각형을 사용하여 게임의 개체와 표면을 나타냅니다. 이러한 다각형 개체와 표면의 구조를 구성하는 꼭짓점 목록을 메시라고 합니다. 여기서는 큐브 개체에 대한 기본 메시를 만들고 렌더링 및 표시를 위해 셰이더 파이프라인에 제공합니다.

중요 여기에 포함된 예제 코드는 DirectX::XMFLOAT3 및 DirectX::XMFLOAT4X4 등의 형식과 DirectXMath.h에 선언된 인라인 메서드를 사용합니다. 코드를 잘라내어 붙여넣었다면, 프로젝트에 <#include DirectXMath.h>을 추가하십시오.

 

알아야 할 사항

기술

필수 조건

  • 선형 대수 및 3차원 좌표계에 대한 기본 지식
  • Visual Studio 2015 이상 Direct3D 템플릿

지시

다음 단계에서는 기본 메시 큐브를 만드는 방법을 보여줍니다.

1단계: 모델에 대한 메시 생성

대부분의 게임에서 게임 개체의 메시는 특정 꼭짓점 데이터가 포함된 파일에서 로드됩니다. 이러한 꼭짓점의 순서는 애플리케이션에 따라 다르지만, 일반적으로 스트립이나 팬 형태로 직렬화됩니다. 꼭짓점 데이터는 모든 소프트웨어 원본에서 오거나 수동으로 만들 수 있습니다. 꼭짓점 셰이더가 효과적으로 처리할 수 있는 방식으로 데이터를 해석하는 것은 게임에 달려 있습니다.

이 예제에서는 큐브에 간단한 메시를 사용합니다. 파이프라인의 이 단계에서 오브젝트 메쉬와 마찬가지로 큐브는 고유의 좌표계를 사용하여 표현됩니다. 꼭짓점 셰이더는 좌표를 사용하고 사용자가 제공하는 변환 매트릭스를 적용하여 동종 좌표계에서 최종 2차원 뷰 프로젝션을 반환합니다.

큐브의 메시를 정의합니다. 또는 파일에서 로드하십시오. 당신이 결정하세요!

SimpleCubeVertex cubeVertices[] =
{
    { DirectX::XMFLOAT3(-0.5f, 0.5f, -0.5f), DirectX::XMFLOAT3(0.0f, 1.0f, 0.0f) }, // +Y (top face)
    { DirectX::XMFLOAT3( 0.5f, 0.5f, -0.5f), DirectX::XMFLOAT3(1.0f, 1.0f, 0.0f) },
    { DirectX::XMFLOAT3( 0.5f, 0.5f,  0.5f), DirectX::XMFLOAT3(1.0f, 1.0f, 1.0f) },
    { DirectX::XMFLOAT3(-0.5f, 0.5f,  0.5f), DirectX::XMFLOAT3(0.0f, 1.0f, 1.0f) },

    { DirectX::XMFLOAT3(-0.5f, -0.5f,  0.5f), DirectX::XMFLOAT3(0.0f, 0.0f, 1.0f) }, // -Y (bottom face)
    { DirectX::XMFLOAT3( 0.5f, -0.5f,  0.5f), DirectX::XMFLOAT3(1.0f, 0.0f, 1.0f) },
    { DirectX::XMFLOAT3( 0.5f, -0.5f, -0.5f), DirectX::XMFLOAT3(1.0f, 0.0f, 0.0f) },
    { DirectX::XMFLOAT3(-0.5f, -0.5f, -0.5f), DirectX::XMFLOAT3(0.0f, 0.0f, 0.0f) },
};

큐브의 좌표계는 큐브의 중심을 원점에 위치시키고, y축은 왼손 좌표계에서 위에서 아래로 향하도록 정의합니다. 좌표 값은 -1 1 사이의 32비트 부동 값으로 표현됩니다.

각 대괄호 쌍에서 두 번째 DirectX::XMFLOAT3 값 그룹은 꼭짓점과 연결된 색을 RGB 값으로 지정합니다. 예를 들어(-0.5, 0.5, -0.5)의 첫 번째 꼭짓점은 전체 녹색(G 값은 1.0으로 설정되고 "R" 및 "B" 값은 0으로 설정됨)입니다.

따라서 각각 특정 색의 꼭짓점이 8개 있습니다. 각 꼭짓점/색 페어링은 예제에서 꼭짓점의 전체 데이터입니다. 꼭짓점 버퍼를 지정할 때는 이 특정 레이아웃을 염두에 두어야 합니다. 꼭짓점 데이터를 이해할 수 있도록 꼭짓점 셰이더에 이 입력 레이아웃을 제공합니다.

2단계: 입력 레이아웃 설정

이제 꼭짓점이 메모리에 저장되었습니다. 그러나 그래픽 장치에는 자체 메모리가 있으며 Direct3D를 사용하여 액세스합니다. 그래픽 디바이스로 꼭짓점 데이터를 전처리하기 위해서는, 먼저 말하자면 길을 닦아야 합니다. 그래픽 디바이스가 게임에서 데이터를 가져올 때 이를 해석할 수 있도록 꼭짓점 데이터가 배치되는 방식을 선언해야 합니다. 이렇게 하려면 ID3D11InputLayout사용합니다.

꼭짓점 버퍼에 대한 입력 레이아웃을 선언하고 설정합니다.

const D3D11_INPUT_ELEMENT_DESC basicVertexLayoutDesc[] =
{
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0,  0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "COLOR",    0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};

ComPtr<ID3D11InputLayout> inputLayout;
m_d3dDevice->CreateInputLayout(
                basicVertexLayoutDesc,
                ARRAYSIZE(basicVertexLayoutDesc),
                vertexShaderBytecode->Data,
                vertexShaderBytecode->Length,
                &inputLayout)
);

이 코드에서는 꼭짓점의 레이아웃, 즉, 꼭짓점 목록의 각 요소가 포함하는 데이터를 지정합니다. 여기서는 basicVertexLayoutDesc두 개의 데이터 구성 요소를 지정합니다.

  • POSITION: 셰이더에 제공된 위치 데이터에 대한 HLSL 의미 체계입니다. 이 코드에서 DirectX::XMFLOAT3는 32비트 부동 소수점 값 세 개로 이루어진 구조체이며, 이는 3D 좌표(x, y, z)에 해당합니다. 동질의 "w" 좌표를 제공하는 경우, float4를 사용할 수도 있습니다. 이 경우, DXGI_FORMAT_R32G32B32A32_FLOAT를 지정해야 합니다. DirectX::XMFLOAT3 또는 float4를 사용하는지 여부는 게임의 특정 요구 사항에 따라 다릅니다. 메시의 꼭짓점 데이터가 사용하는 형식에 올바르게 일치하는지 확인하세요.

    각 좌표 값은 개체의 좌표 공간에서 -1 1 사이의 부동 소수점 값으로 표현됩니다. 꼭짓점 셰이더가 완료되면 변환된 꼭짓점은 균일한(원근감 수정) 뷰 프로젝션 공간에 있습니다.

    "하지만 열거형 값이 XYZ가 아니라 RGB를 나타낸다고 영리하게 지적합니다!" 좋은 눈! 색 데이터와 좌표 데이터의 두 경우 모두 일반적으로 3개 또는 4개의 구성 요소 값을 사용하므로 두 구성 요소 모두에 대해 동일한 형식을 사용하지 않는 것은 어떨까요? 형식 이름이 아닌 HLSL 의미 체계는 셰이더가 데이터를 처리하는 방법을 나타냅니다.

  • COLOR: 색 데이터에 대한 HLSL 의미 체계입니다. POSITION처럼, 32비트 부동 소수점 값 3개(DirectX::XMFLOAT3)로 구성됩니다. 각 값에는 0에서 1 사이의 부동 숫자로 표현되는 빨간색(r), 파란색(b) 또는 녹색(g) 색 구성 요소가 포함됩니다.

    COLOR 값은 일반적으로 셰이더 파이프라인의 끝에 4개 구성 요소 RGBA 값으로 반환됩니다. 이 예제에서는 모든 픽셀에 대해 셰이더 파이프라인에서 "A" 알파 값을 1.0(최대 불투명도)으로 설정합니다.

전체 형식 목록은 DXGI_FORMAT참조하세요. HLSL 의미 체계의 전체 목록은 의미 체계참조하세요.

ID3D11Device::CreateInputLayout 호출하고 Direct3D 디바이스에서 입력 레이아웃을 만듭니다. 이제 실제로 데이터를 저장할 수 있는 버퍼를 만들어야 합니다.

3단계: 꼭짓점 버퍼 채우기

꼭짓점 버퍼에는 메시의 각 삼각형에 대한 꼭짓점 목록이 포함됩니다. 모든 꼭짓점은 이 목록에서 고유해야 합니다. 이 예제에서는 큐브에 대해 8개의 꼭짓점이 있습니다. 꼭짓점 셰이더는 그래픽 디바이스에서 실행되고 꼭짓점 버퍼에서 읽고 이전 단계에서 지정한 입력 레이아웃에 따라 데이터를 해석합니다.

다음 예제에서는 버퍼에 대한 설명과 하위 리소스를 제공하여 Direct3D에 꼭짓점 데이터의 물리적 매핑 및 그래픽 디바이스의 메모리에서 처리하는 방법에 대한 여러 가지 사항을 알려줍니다. 이는 다양한 내용을 포함할 수 있는 제네릭 ID3D11Buffer를 사용하기 때문에 필요합니다. direct3D가 버퍼의 각 꼭짓점 요소 크기와 꼭짓점 목록의 최대 크기를 포함하여 버퍼의 실제 메모리 레이아웃을 이해할 수 있도록 D3D11_BUFFER_DESCD3D11_SUBRESOURCE_DATA 구조가 제공됩니다. 여기에서 버퍼 메모리에 대한 액세스 및 트래버스 방법을 제어할 수도 있지만 이 자습서의 범위를 약간 벗어납니다.

버퍼를 구성한 후 ID3D11Device::CreateBuffer 호출하여 실제로 만듭니다. 물론 둘 이상의 개체가 있는 경우 각 고유 모델에 대한 버퍼를 만듭니다.

버텍스 버퍼를 선언하고 만듭니다.

D3D11_BUFFER_DESC vertexBufferDesc = {0};
vertexBufferDesc.ByteWidth = sizeof(SimpleCubeVertex) * ARRAYSIZE(cubeVertices);
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 = cubeVertices;
vertexBufferData.SysMemPitch = 0;
vertexBufferData.SysMemSlicePitch = 0;

ComPtr<ID3D11Buffer> vertexBuffer;
m_d3dDevice->CreateBuffer(
                &vertexBufferDesc,
                &vertexBufferData,
                &vertexBuffer);

꼭짓점이 로드되었습니다. 그러나 이러한 꼭짓점 처리 순서는 무엇인가요? 꼭짓점의 인덱스 목록을 제공할 때 처리됩니다. 이러한 인덱스의 순서는 꼭짓점 셰이더가 이를 처리하는 순서입니다.

4단계: 인덱스 버퍼 채우기

이제 각 꼭짓점의 인덱스 목록을 제공합니다. 이러한 인덱스는 0부터 시작하여 꼭짓점 버퍼의 꼭짓점 위치에 해당합니다. 이를 시각화하는 데 도움이 되도록 메시의 각 고유 꼭짓점은 ID와 같이 고유 번호가 할당된 것을 고려합니다. 이 ID는 꼭짓점 버퍼에 있는 꼭짓점의 정수 위치입니다.

번호가 매겨진 8개의 꼭짓점이 있는 큐브

예제 큐브에는 8개의 꼭짓점이 있으며, 이 꼭짓점들은 측면에 6개의 사면체를 만듭니다. 쿼드를 삼각형으로 분할하여, 8개의 꼭짓점을 사용하여 총 12개의 삼각형을 만듭니다. 삼각형마다 3개의 꼭짓점이 있으므로, 인덱스 버퍼에는 총 36개의 항목이 있습니다. 이 예제에서 이 인덱스 패턴은 삼각형 목록으로 알려져 있으며, 기본 토폴로지를 설정할 때 Direct3D에서는 D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST로 지정합니다.

삼각형이 점과 측면을 공유할 때 많은 중복이 있기 때문에 인덱스를 나열하는 가장 비효율적인 방법일 수 있습니다. 예를 들어 삼각형이 마름모꼴에서 한 변을 공유하는 경우, 다음과 같이 4개의 꼭짓점을 위해 6개의 인덱스를 나열합니다.

인덱스의 순서 로 마름모를 작성할 때.

  • 삼각형 1: [0, 1, 2]
  • 삼각형 2: [0, 2, 3]

스트립 또는 팬 토폴로지에서 순회 중에 많은 중복 측면을 제거하는 방식으로 꼭짓점을 정렬합니다(예: 이미지의 인덱스 0에서 인덱스 2까지의 측면). 대형 메시의 경우 꼭짓점 셰이더가 실행되는 횟수를 크게 줄이고 성능을 크게 향상시킵니다. 그러나 간단하게 유지하고 삼각형 목록을 고수하겠습니다.

꼭짓점 버퍼에 대한 인덱스를 간단한 삼각형 목록 토폴로지로 선언합니다.

unsigned short cubeIndices[] =
{   0, 1, 2,
    0, 2, 3,

    4, 5, 6,
    4, 6, 7,

    3, 2, 5,
    3, 5, 4,

    2, 1, 6,
    2, 6, 5,

    1, 7, 6,
    1, 0, 7,

    0, 3, 4,
    0, 4, 7 };

꼭짓점이 8개뿐인 경우 버퍼의 인덱스 요소 36개가 매우 중복됩니다. 일부 중복을 제거하고 스트립 또는 팬과 같은 다른 꼭짓점 목록 형식을 사용하도록 선택하는 경우 ID3D11DeviceContext::IASetPrimitiveTopology 메서드에 특정 D3D11_PRIMITIVE_TOPOLOGY 값을 제공할 때 해당 형식을 지정해야 합니다.

다양한 인덱스 목록 기술에 대한 자세한 내용은 기본 토폴로지참조하세요.

5단계: 변환 행렬에 대한 상수 버퍼 만들기

꼭짓점 처리를 시작하기 전에 각 꼭짓점에 프로세스 중에 곱해지는 변환 행렬을 제공해야 합니다. 대부분의 3차원 게임에는 다음 세 가지가 있습니다.

  • 개체(모델) 좌표계에서 전체 세계 좌표계로 변환되는 4x4 행렬입니다.
  • 세계 좌표계에서 카메라(보기) 좌표계로 변환되는 4x4 행렬입니다.
  • 카메라 좌표계에서 2차원 뷰 프로젝션 좌표계로 변환되는 4x4 행렬입니다.

이러한 행렬은 상수 버퍼를 통해셰이더에 전달됩니다. 상수 버퍼는 셰이더 파이프라인의 다음 패스를 실행하는 동안 일정하게 유지되며 HLSL 코드의 셰이더에서 직접 액세스할 수 있는 메모리 영역입니다. 각 상수 버퍼를 두 번 정의합니다. 먼저 게임의 C++ 코드에서, 그리고 셰이더 코드에 대한 C와 유사한 HLSL 구문에서 한 번 이상 정의합니다. 두 선언은 형식 및 데이터 정렬 측면에서 직접 대응해야 합니다. 셰이더가 HLSL 선언을 사용하여 C++에서 선언된 데이터를 해석할 때, 형식이 일치하지 않거나 데이터의 정렬이 맞지 않으면 찾기 어려운 오류가 쉽게 발생할 수 있습니다.

상수 버퍼는 HLSL에 의해 변경되지 않습니다. 게임에서 특정 데이터를 업데이트할 때 변경할 수 있습니다. 게임 개발자는 종종 4개의 상수 버퍼 클래스를 만듭니다. 즉, 프레임당 업데이트를 위한 한 가지 유형입니다. 모델/개체당 업데이트에 대한 하나의 형식; 게임별 업데이트 상태 새로 고침에 대한 한 가지 유형; 및 게임의 수명 동안 변경되지 않는 데이터에 대한 하나의 형식입니다.

이 예제에서는 변경되지 않는 값이 하나만 있습니다: 3개의 행렬에 대한 DirectX::XMFLOAT4X4 데이터.

참고 여기에 제시된 예제 코드는 열 주 행렬을 사용합니다. 대신 HLSL에서 row_major 키워드를 사용하고, 원본 행렬 데이터가 행 우선 행렬임을 확실히 하여 행 우선 행렬을 사용할 수 있습니다. DirectXMath는 행 주 행렬을 사용하며 row_major 키워드로 정의된 HLSL 매트릭스와 함께 직접 사용할 수 있습니다.

 

각 꼭짓점을 변환하는 데 사용하는 세 개의 행렬에 대해 상수 버퍼를 선언한 후 생성합니다.

struct ConstantBuffer
{
    DirectX::XMFLOAT4X4 model;
    DirectX::XMFLOAT4X4 view;
    DirectX::XMFLOAT4X4 projection;
};
ComPtr<ID3D11Buffer> m_constantBuffer;
ConstantBuffer m_constantBufferData;

// ...

// Create a constant buffer for passing model, view, and projection matrices
// to the vertex shader.  This allows us to rotate the cube and apply
// a perspective projection to it.

D3D11_BUFFER_DESC constantBufferDesc = {0};
constantBufferDesc.ByteWidth = sizeof(m_constantBufferData);
constantBufferDesc.Usage = D3D11_USAGE_DEFAULT;
constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
constantBufferDesc.CPUAccessFlags = 0;
constantBufferDesc.MiscFlags = 0;
constantBufferDesc.StructureByteStride = 0;
m_d3dDevice->CreateBuffer(
                &constantBufferDesc,
                nullptr,
                &m_constantBuffer
             );

m_constantBufferData.model = DirectX::XMFLOAT4X4( // Identity matrix, since you are not animating the object
            1.0f, 0.0f, 0.0f, 0.0f,
            0.0f, 1.0f, 0.0f, 0.0f,
            0.0f, 0.0f, 1.0f, 0.0f,
            0.0f, 0.0f, 0.0f, 1.0f);

);
// Specify the view (camera) transform corresponding to a camera position of
// X = 0, Y = 1, Z = 2.  

m_constantBufferData.view = DirectX::XMFLOAT4X4(
            -1.00000000f, 0.00000000f,  0.00000000f,  0.00000000f,
             0.00000000f, 0.89442718f,  0.44721359f,  0.00000000f,
             0.00000000f, 0.44721359f, -0.89442718f, -2.23606800f,
             0.00000000f, 0.00000000f,  0.00000000f,  1.00000000f);

참고 곱하기 결과는 현재 2차원 뷰포트 크기 매개 변수(디스플레이의 픽셀 높이 및 너비에 해당하는 경우)와 일치해야 하므로 디바이스별 리소스를 설정할 때 일반적으로 프로젝션 매트릭스를 선언합니다. 이러한 변경 내용이 변경되면 x 좌표 및 y 좌표 값의 크기를 적절하게 조정해야 합니다.

 

// Finally, update the constant buffer perspective projection parameters
// to account for the size of the application window.  In this sample,
// the parameters are fixed to a 70-degree field of view, with a depth
// range of 0.01 to 100.  

float xScale = 1.42814801f;
float yScale = 1.42814801f;
if (backBufferDesc.Width > backBufferDesc.Height)
{
    xScale = yScale *
                static_cast<float>(backBufferDesc.Height) /
                static_cast<float>(backBufferDesc.Width);
}
else
{
    yScale = xScale *
                static_cast<float>(backBufferDesc.Width) /
                static_cast<float>(backBufferDesc.Height);
}
m_constantBufferData.projection = DirectX::XMFLOAT4X4(
            xScale, 0.0f,    0.0f,  0.0f,
            0.0f,   yScale,  0.0f,  0.0f,
            0.0f,   0.0f,   -1.0f, -0.01f,
            0.0f,   0.0f,   -1.0f,  0.0f
            );

이 작업을 진행하는 동안ID3D11DeviceContext의 꼭짓점 및 인덱스 버퍼를 설정하고, 또한 사용 중인 토폴로지를 설정하십시오.

// Set the vertex and index buffers, and specify the way they define geometry.
UINT stride = sizeof(SimpleCubeVertex);
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);

좋습니다! 입력 어셈블리가 완료되었습니다. 렌더링을 위해 모든 것이 준비되었습니다. 꼭짓점 셰이더를 시작합시다.

6단계: 꼭짓점 셰이더를 이용해 메쉬 처리

이제 메시를 정의하는 꼭짓점을 포함한 꼭짓점 버퍼와, 꼭짓점이 처리되는 순서를 정의하는 인덱스 버퍼를 가지고 있으므로, 이들을 꼭짓점 셰이더로 전송합니다. 컴파일된 상위 수준 셰이더 언어로 표현된 꼭짓점 셰이더 코드는 꼭짓점 버퍼의 각 꼭짓점마다 한 번 실행되므로 꼭짓점별 변환을 수행할 수 있습니다. 최종 결과는 일반적으로 2차원 프로젝션입니다.

(꼭짓점 셰이더를 로드하셨습니까? 그렇지 않은 경우, "" DirectX 게임 내 리소스를 로드하는 방법 ""을 검토하십시오.)

여기서는 꼭짓점 셰이더를 만듭니다...

// Set the vertex and pixel shader stage state.
m_d3dDeviceContext->VSSetShader(
                vertexShader.Get(),
                nullptr,
                0);

... 상수 버퍼를 설정합니다.

m_d3dDeviceContext->VSSetConstantBuffers(
                0,
                1,
                m_constantBuffer.GetAddressOf());

다음은 개체 좌표에서 월드 좌표로 변환한 다음 2차원 뷰 프로젝션 좌표계로 변환을 처리하는 꼭짓점 셰이더 코드입니다. 또한 꼭짓점당 간단한 조명을 적용하여 장면을 예쁘게 만듭니다. 이는 꼭짓점 셰이더의 HLSL 파일(이 예제에서는 SimplerVertexShader.hlsl)에 적용됩니다.

cbuffer simpleConstantBuffer : register( b0 )
{
    matrix model;
    matrix view;
    matrix projection;
};

struct VertexShaderInput
{
    DirectX::XMFLOAT3 pos : POSITION;
    DirectX::XMFLOAT3 color : COLOR;
};

struct PixelShaderInput
{
    float4 pos : SV_POSITION;
    float4 color : COLOR;
};

PixelShaderInput SimpleVertexShader(VertexShaderInput input)
{
    PixelShaderInput vertexShaderOutput;
    float4 pos = float4(input.pos, 1.0f);

    // Transform the vertex position into projection space.
    pos = mul(pos, model);
    pos = mul(pos, view);
    pos = mul(pos, projection);
    vertexShaderOutput.pos = pos;

    // Pass the vertex color through to the pixel shader.
    vertexShaderOutput.color = float4(input.color, 1.0f);

    return vertexShaderOutput;
}

cbuffer가 상단에 있는 것을 보셨나요? 이는 이전에 C++ 코드에서 선언한 것과 동일한 상수 버퍼에 대한 HLSL 아날로그입니다. 그리고 VertexShaderInputstruct? 와, 그건 마치 입력 레이아웃과 꼭지 데이터 선언 같네요! C++ 코드의 상수 버퍼 및 꼭짓점 데이터 선언은 HLSL 코드의 선언과 일치하며 기호, 형식 및 데이터 맞춤을 포함하는 것이 중요합니다.

PixelShaderInput 꼭짓점 셰이더의 주 함수에서 반환되는 데이터의 레이아웃을 지정합니다. 꼭짓점 처리를 마치면 2차원 프로젝션 공간에서 꼭짓점 위치와 꼭짓점별 조명에 사용되는 색을 반환합니다. 그래픽 카드는 셰이더의 데이터 출력을 사용하여 파이프라인의 다음 단계에서 픽셀 셰이더를 실행할 때 색이 지정되어야 하는 "조각"(가능한 픽셀)을 계산합니다.

7단계: 메시를 픽셀 셰이더로 통과시키기

일반적으로 그래픽 파이프라인의 이 단계에서는 개체의 표시되는 프로젝트된 표면에서 픽셀당 작업을 수행합니다. 사람들은 질감을 좋아한다. 그러나 샘플의 목적을 위해, 이 단계를 단순히 통과하기만 하면 됩니다.

먼저 픽셀 셰이더의 인스턴스를 만들어 보겠습니다. 픽셀 셰이더는 장면의 2차원 프로젝션에서 모든 픽셀에 대해 실행되어 해당 픽셀에 색을 할당합니다. 이 경우 꼭짓점 셰이더에서 반환된 픽셀의 색을 직선으로 전달합니다.

픽셀 셰이더를 설정합니다.

m_d3dDeviceContext->PSSetShader( pixelShader.Get(), nullptr, 0 );

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);
}

이 코드를 꼭짓점 셰이더 HLSL(예: SimplePixelShader.hlsl)과 별도로 HLSL 파일에 넣습니다. 이 코드는 뷰포트의 표시되는 모든 픽셀(그리는 화면 부분의 메모리 내 표현)에 대해 한 번 실행되며, 이 경우 전체 화면에 매핑됩니다. 이제 그래픽 파이프라인이 완전히 정의되었습니다.

8단계: 메시 래스터화 및 표시

파이프라인을 실행해 보겠습니다. 이는 간단합니다: ID3D11DeviceContext::DrawIndexed를 호출합니다.

해당 큐브를 그립니다!

// Draw the cube.
m_d3dDeviceContext->DrawIndexed( ARRAYSIZE(cubeIndices), 0, 0 );
            

그래픽 카드 내에서 각 꼭짓점은 인덱스 버퍼에 지정된 순서대로 처리됩니다. 코드가 꼭짓점 셰이더를 실행하고 2차원 조각이 정의되면 픽셀 셰이더가 호출되고 삼각형이 색이 지정됩니다.

이제 큐브를 화면에 배치합니다.

해당 프레임 버퍼를 디스플레이에 표시합니다.

// Present the rendered image to the window.  Because the maximum frame latency is set to 1,
// the render loop is generally  throttled to the screen refresh rate, typically around
// 60 Hz, by sleeping the app on Present until the screen is refreshed.

m_swapChain->Present(1, 0);

그리고 당신은 끝났어! 모델이 가득 찬 장면의 경우 여러 꼭짓점 및 인덱스 버퍼를 사용하며 모델 유형에 따라 셰이더가 다를 수도 있습니다. 각 모델에는 고유한 좌표계가 있으며 상수 버퍼에 정의한 행렬을 사용하여 공유 세계 좌표계로 변환해야 합니다.

비고

이 항목에서는 직접 만드는 간단한 기하 도형을 만들고 표시하는 방법에 대해 설명합니다. 파일에서 더 복잡한 기하 도형을 로드하여 샘플에 특화된 꼭짓점 버퍼 개체(.vbo) 형식으로 변환하는 방법에 대한 자세한 내용은 DirectX 게임에서의 리소스 로드 방법을 참조하세요.