이제 본격적으로 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));

 

이렇게 해주면 위의 큐브가 보이게 되는 것이다.

+ Recent posts