본문 바로가기
서적 정리/DirectX11을 이용한 3D 게임 프로그래밍 입문

44.정점 버퍼(Vertex Buffer)

by 민돌이2 2022. 2. 7.

Direct3D 코드에서 버퍼는 ID3D11Buffer 인터페이스로 대표된다. Direct3D의 버퍼들은 자료를 담을 뿐만 아니라, CPU나 GPU가 자료에 어떻게 접근할 수 있고 버퍼가 파이프라인의 어디에 묶이는지에 대한 정보도 가진다. 

 

정점 버퍼를 생성하고 파이프라인에 묶기까지 아래와 같은 과정을 거쳐야한다.

  1. 생성할 버퍼를 서술하는 D3D11_BUFFER_DESC 구조체를 채운다.
  2. 버퍼의 초기화에 사용할 자료를 서술하는 D3D11_SUBRESOURCE_DATA 구조체를 채운다.
  3. ID3D11Device::CreateBuffer를 호출해서 버퍼를 생성한다.
  4. ID3D11DeviceContext::IASetVertexBuffers을 호출하여 정점 버퍼를 파이프라인에 묶는다.(Input Assembler : IA)

 

1.생성할 버퍼를 서술하는 D3D11_BUFFER_DESC 구조체를 채운다.

D3D11_BUFFER_DESC 구조체는 d3d11.h에서 찾을 수 있다.

typedef struct D3D11_BUFFER_DESC
{
	UINT ByteWidth;
	D3D11_USAGE Usage;
	UINT BindFlags;
	UINT CPUAccessFlags;
	UINT MiscFlags;
	UINT StructureByteStride;
} D3D11_BUFFER_DESC;

1.ByteWidth : 생성할 버퍼의 크기(byte 단위)
2.Usage : 버퍼가 쓰이는 방식(*주 1)
3.BindFlags : 버퍼가 파이프라인에 바인딩되는 방법을 식별(*주 2)
4.CPUAccessFlags : CPU가 버퍼에 접근하는 방식을 식별. CPU가 버퍼를 사용하지 않는다면 0을 지정한다.
5.MiscFlags : 기타 플래그 식별
6.StructureByteStride : 구조적 버퍼에 저장된 원소 하나의 크기. 구조적 버퍼를 위해서만 필요하고, 그 외의 모든 버퍼에 대해서는 0을 지정한다.

 

2.버퍼의 초기화에 사용할 자료를 서술하는 D3D11_SUBRESOURCE_DATA 구조체를 채운다.
D3D11_SUBRESOURCE_DATA 구조체는 d3d11.h에서 찾을 수 있다.

typedef struct D3D11_SUBRESOURCE_DATA
{
	const void *pSysMem;
	UINT SysMemPitch;
	UINT SysMemSlicePitch;
} D3D11_SUBRESOURCE_DATA;​

1.pSysMem : 버퍼를 초기화할 자료를 담은 시스템 메모리 배열을 가리키는 포인터.
2.SysMemPitch : 텍스처의 한 줄 시작에서 다음 줄 까지의 거리(byte)이다. 2D, 3D 텍스처 데이터에서만 사용되고, 나머지에서는 사용하지 않는다.
3.SysMemSlicePitch : 한 깊이 레벨의 시작에서 다음 깊이 레벨까지의 거리(byte)이다. 3D 텍스처 데이터에만 사용된다.

 

3.ID3D11Device::CreateBuffer를 호출해서 버퍼를 생성한다.
CreateBuffer 함수는 d3d11.h에서 찾을 수 있다.

HRESULT CreateBuffer(
	const D3D11_BUFFER_DESC* pDesc,
	const D3D11_SUBRESOURCE_DATA* pInitialData, 
	ID3D11Buffer** ppBuffer
);

1.pDesc : 생성할 버퍼를 서술하는 구조체
2.pInitialData : 버퍼를 초기화하는 데 사용할 자료
3.ppBuffer : 생성된 버퍼 반환

 

4.정점 버퍼를 파이프라인에 묶는다.(Input Assembler : IA)
ID3D11DeviceContext::IASetVertexBuffers을 이용하여 묶을 수 있다.

void IASetVertexBuffers(
	UINT StartSlot,
	UINT NumBuffers,
	ID3D11Buffer* const* ppVertexBuffers,
	const UINT* pStrides,
	const UINT* pOffsets
);

1.StartSlot : 정점 버퍼들을 붙이기 시작할 입력 슬롯의 인덱스. 총 16개의 입력 슬롯이 있다.(0 ~ 15)
2.NumBuffers : 입력 슬롯들에 붙이고자 하는 버퍼들의 개수.
3.ppVertexBuffers : 정점 버퍼들을 담은 배열의 첫 원소를 가리키는 포인터
4.pStrides : stride 배열의 첫 원소를 가리키는 포인터. 정점 버퍼의 한 원소의 byte 단위 크기이다.
5.pOffsets : offset 배열의 첫 원소를 가리키는 포인터

 

위 과정을 코드로 써보자.

struct Vertex
{
	XMFLOAT3 Pos;
	XMFLOAT4 Color;
};

Vertex vertices[] =
{
	{ XMFLOAT3(-1.0f, -1.0f, -1.0f), XMFLOAT4(1.0f, 0.0f, 0.0f, 1.0f)}
}

//정점 버퍼 구조체 설정
D3D11_BUFFER_DESC desc;
desc.Usage = D3D11_USAGE_IMMUTABLE;
desc.ByteWidth = sizeof(Vertex) * 8;
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
desc.CPUAccessFlags = 0;
desc.MiscFlags = 0;
desc.StructureByteStride = 0;

//버퍼 초기화 설정
D3D11_SUBRESOURCE_DATA subResource = { 0 };
subResource.pSysMem = vertices;

//정점 버퍼 생성
ID3D11Buffer* buffer = NULL;
HR(md3dDevice->CreateBuffer(&desc, &subResource, &buffer);

//생성한 정점 버퍼를 파이프라인에 바인드
UINT stride = sizeof(Vertex);
UINT offset = 0;
md3dImmediateContext->IASetVertexBuffers(0, 1, &buffer, &stride, &offset);

 

정점들의 그리기 연산을 실제로 시작하려면 ID3D11DevcieContext::Draw 메소드를 호출해야한다.

void ID3D11DeviceContext::Draw(UINT VertexCount, UINT StartVertexLocation);

1.VertexCount : 그릴 정점의 수

2.StartVertexLocation : 정점 버퍼의 첫번째 정점의 인덱스

 

(*주 1)D3D11_USAGE 열거형

렌더링 중 예상되는 리소스 사용을 식별한다. CPU 또는 GPU에서 리소스를 액세스할 수 있는지 여부를 반영한다.

typedef enum D3D11_USAGE
{
	D3D11_USAGE_DEFAULT = 0,
	D3D11_USAGE_IMMUTABLE = 1,
	D3D11_USAGE_DYNAMIC = 2,
	D3D11_USAGE_STAGING = 3
} D3D11_USAGE;

 

(*주 2)D3D11_BIND_FLAG 열거형

리소스를 파이프라인에 바인딩하는 방법을 식별한다.

typedef enum D3D11_BIND_FLAG
{
	D3D11_BIND_VERTEX_BUFFER = 0x1L,
	D3D11_BIND_INDEX_BUFFER = 0x2L,
	D3D11_BIND_CONSTANT_BUFFER = 0x4L,
	D3D11_BIND_SHADER_RESOURCE = 0x8L,
	D3D11_BIND_STREAM_OUTPUT = 0x10L,
	D3D11_BIND_RENDER_TARGET = 0x20L,
	D3D11_BIND_DEPTH_STENCIL = 0x40L,
	D3D11_BIND_UNORDERED_ACCESS = 0x80L,
	D3D11_BIND_DECODER = 0x200L,
	D3D11_BIND_VIDEO_ENCODER = 0x400L
} D3D11_BIND_FLAG;

D3D11_BIND_VERTEX_BUFFER : 정점 버퍼

D3D11_BIND_INDEX_BUFFER : 인덱스 버퍼
D3D11_BIND_CONSTANT_BUFFER : 상수 버퍼, 자원을 셰이더에서 사용할 수 있음
D3D11_BIND_SHADER_RESOURCE : 버퍼 혹은 텍스처, 자원을 셰이더에서 사용할 수 있음
D3D11_BIND_STREAM_OUTPUT : 스트림 출력 단계에 대한 출력 버퍼
D3D11_BIND_RENDER_TARGET : 출력 병합(OM) 단계의 결과를 렌더 타겟으로 바인딩
D3D11_BIND_DEPTH_STENCIL :  출력 병합(OM) 단계의 결과를 깊이 스텐실로 바인딩
D3D11_BIND_UNORDERED_ACCESS : 정렬되지 않은 액세스 리소스
D3D11_BIND_DECODER : 디코더 API에서 출력을 수신하는 데 2D 텍스처가 사용됨을 알림
D3D11_BIND_VIDEO_ENCODER : 비디오 인코더 API에서 입력을 수신하는 데 2D 텍스처가 사용됨을 알림

728x90

댓글