이제 본격적으로 Directx 11에서 그리기 연산이 어떻게 이루어지는 지 살펴보자.
우선 위처럼 하나의 정육면체 큐브를 만든다고 했을 때 이 큐브가 어떻게 만들어지는 지 생각해보자.
이 큐브도 렌더링파이프라인을 모두 거쳐서 나오게 될 것이다.
우선 IA 단계에서 정점과 인덱스 정보를 묘사하는 아이인 Input Layout을 통해 넘겨주고 이를 VS단계에서 카메라에 어떻게 보이게 되는지 행렬곱 연산을 적용시켜 줄 것이다. 그리고 RS단계에서 색상을 보간해줘서 위와 같이 보이게 해야할 것 이다. 그렇게 해주려면 정점과 색상에 대한 정보가 있어야 할 것이다.
코드를 살펴보자면 우선 vertexBuffer와 indexBuffer에 정보를 채워서 GPU쪽에 보내줘야한다.
ComPtr<ID3D11Buffer> _vertexBuffer;
ComPtr<ID3D11Buffer> _indexBuffer;
버퍼로 전달하고 싶은 정보를 구조체로 정의하고 정보를 채워준다음 버퍼 정보 정의해서 하나의 버퍼를 만들어 주면 된다.
이때 큐브모양을 만들어 줄 것이기 때문에 정점을 8개로 만들어주었다.
struct Vertex
{
XMFLOAT3 Pos;
XMFLOAT4 Color;
};
// Create vertex buffer
Vertex vertices[] =
{
{ XMFLOAT3(-1.0f, -1.0f, -1.0f), XMFLOAT4((const float*)&Colors::White) },
{ XMFLOAT3(-1.0f, +1.0f, -1.0f), XMFLOAT4((const float*)&Colors::Black) },
{ XMFLOAT3(+1.0f, +1.0f, -1.0f), XMFLOAT4((const float*)&Colors::Red) },
{ XMFLOAT3(+1.0f, -1.0f, -1.0f), XMFLOAT4((const float*)&Colors::Green) },
{ XMFLOAT3(-1.0f, -1.0f, +1.0f), XMFLOAT4((const float*)&Colors::Blue) },
{ XMFLOAT3(-1.0f, +1.0f, +1.0f), XMFLOAT4((const float*)&Colors::Yellow) },
{ XMFLOAT3(+1.0f, +1.0f, +1.0f), XMFLOAT4((const float*)&Colors::Cyan) },
{ XMFLOAT3(+1.0f, -1.0f, +1.0f), XMFLOAT4((const float*)&Colors::Magenta) }
};
D3D11_BUFFER_DESC vbd;
vbd.Usage = D3D11_USAGE_IMMUTABLE;
vbd.ByteWidth = sizeof(Vertex) * 8;
vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbd.CPUAccessFlags = 0;
vbd.MiscFlags = 0;
vbd.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA vinitData;
vinitData.pSysMem = vertices;
HR(_device->CreateBuffer(&vbd, &vinitData, _vertexBuffer.GetAddressOf()));
이렇게 정점만 넘겨줘도 그려줄 수는 있지만 삼각형으로 그리다보면 겹치는 부분이 많이 생기기 때문에 인덱스 정보를
같이 넘겨준다. 인덱스 버퍼도 버텍스 버퍼와 동일한 방식으로 만들어주면 된다.
// Create the index buffer
uint32 indices[] = {
// front face
0, 1, 2,
0, 2, 3,
// back face
4, 6, 5,
4, 7, 6,
// left face
4, 5, 1,
4, 1, 0,
// right face
3, 2, 6,
3, 6, 7,
// top face
1, 5, 6,
1, 6, 2,
// bottom face
4, 0, 3,
4, 3, 7
};
D3D11_BUFFER_DESC ibd;
ibd.Usage = D3D11_USAGE_IMMUTABLE;
ibd.ByteWidth = sizeof(uint32) * 36;
ibd.BindFlags = D3D11_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = 0;
ibd.MiscFlags = 0;
ibd.StructureByteStride = 0;
D3D11_SUBRESOURCE_DATA iinitData;
iinitData.pSysMem = indices;
HR(_device->CreateBuffer(&ibd, &iinitData, _indexBuffer.GetAddressOf()));
그리고 shader를 사용할 때 Com객체처럼 사용하는데 이때 이름을 맞춰주면 가져오고 세팅할 때 연동이 돼서 편하게 사용
할 수 있다.
_fxWorldViewProj = _fx->GetVariableByName("gWorldViewProj")->AsMatrix();
_fxWorldViewProj->SetMatrix(reinterpret_cast<float*>(&worldViewProj));
VS단계를 보면 이렇게 정점이 월드 뷰 프로젝션 변환 행렬이 곱채져서 반환된다는 것을 볼 수 있다.
cbuffer cbPerObject
{
float4x4 gWorldViewProj;
};
struct VertexIn
{
float3 PosL : POSITION;
float4 Color : COLOR;
};
struct VertexOut
{
float4 PosH : SV_POSITION;
float4 Color : COLOR;
};
VertexOut VS(VertexIn vin)
{
VertexOut vout;
// Transform to homogeneous clip space.
vout.PosH = mul(float4(vin.PosL, 1.0f), gWorldViewProj);
// Just pass vertex color into the pixel shader.
vout.Color = vin.Color;
return vout;
}
그 다음 물체가 어떻게 생겼는지 묘사해주는 Input Layout 단계이다. 이때 쉐이더의 구조체 변수와 클래스 변수와 이름과 구조를 동일하게 맞춰주어야 한다.
void BoxDemo::BuildVertexLayout()
{
// Create the vertex input layout.
D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}
};
// Create the input layout
D3DX11_PASS_DESC passDesc;
_tech->GetPassByIndex(0)->GetDesc(&passDesc);
HR(_device->CreateInputLayout(vertexDesc, 2, passDesc.pIAInputSignature, passDesc.IAInputSignatureSize, _inputLayout.GetAddressOf()));
}
그 다음에는 렌더타켓뷰와 깊이 스텐실뷰를 클리어해주는 것으로 그림 그릴 도화지를 밀어주고 IA단계의 인풋레이아웃을 묘사한 부분을 실제 DeviceContext와 연결시켜주고 물체를 어떤 기본 물체로 그려줄지 세팅하는 토폴로지 단계를 하는 것을 볼 수 있다. 정점버퍼와 인덱스버퍼도 연결시켜준다.
_deviceContext->IASetInputLayout(_inputLayout.Get());
_deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
uint32 stride = sizeof(Vertex);
uint32 offset = 0;
_deviceContext->IASetVertexBuffers(0, 1, _vertexBuffer.GetAddressOf(), &stride, &offset);
_deviceContext->IASetIndexBuffer(_indexBuffer.Get(), DXGI_FORMAT_R32_UINT, 0);
이렇게 해준다음 월드,뷰,프로젝션 변환행렬을 쉐이더쪽에 정보를 넘겨주고 드려주면 된다. 인덱스 버퍼를 통해 그려주는 DrawIndexed를 사용하는 것을 볼 수 있다.
그려준 도화지를 Present를 통해 제출한다.
// Set constants
XMMATRIX world = ::XMLoadFloat4x4(&_world);
XMMATRIX view = ::XMLoadFloat4x4(&_view);
XMMATRIX proj = ::XMLoadFloat4x4(&_proj);
XMMATRIX worldViewProj = world * view * proj;
_fxWorldViewProj->SetMatrix(reinterpret_cast<float*>(&worldViewProj));
D3DX11_TECHNIQUE_DESC techDesc;
_tech->GetDesc(&techDesc);
for (uint32 p = 0; p < techDesc.Passes; ++p)
{
_tech->GetPassByIndex(p)->Apply(0, _deviceContext.Get());
// 36 indices for the box.
_deviceContext->DrawIndexed(36, 0, 0);
}
HR(_swapChain->Present(0, 0));
이렇게 해주면 위의 큐브가 보이게 되는 것이다.
'게임공부 > Directx11(물방울책)' 카테고리의 다른 글
[Directx11][C++][물방울]6. Stencil (1) | 2024.10.21 |
---|---|
[Directx11][C++][물방울]5. 블렌딩 (1) | 2024.10.19 |
[Directx11][C++][물방울]4. 텍스쳐 (1) | 2024.10.18 |
[Directx11][C++][물방울]3. 조명 (3) | 2024.10.16 |
[Directx11][C++][물방울]1.렌더링 파이프라인 (2) | 2024.10.14 |