게임 개발 자료/DirectX 스터디

DirectX 11 스터디 - 상수 버퍼 (Constant Buffer)

원생계 2023. 9. 8. 18:42

버텍스 데이터/매쉬 데이터를 건들지 않고, Shader 에 버퍼 데이터를 넘겨서 버텍스셰이더를 통해 변경되도록 처리해본다.

 

순서는 아래와 같다.

1. 상수버퍼 생성

2. DeviceContext 에 버퍼 매핑

3. 렌더 함수에서 버퍼 전달

 

아래는 수정한 코드 블럭들

// 멤버 선언
TransformData _transformData;
ComPtr<ID3D11Buffer> _constantBuffer;

// 구조체 선언
struct TransformData
{
	Vec3 offset;
	float dummy; // 16byte 로 정렬해야 하기 때문에 더미 멤버를 추가.
};

// 버퍼 생성
void Game::CreateContantBuffer()
{
	D3D11_BUFFER_DESC desc;
	ZeroMemory(&desc, sizeof(desc));
	desc.Usage = D3D11_USAGE_DYNAMIC; // CPU Write + GPU Read
	desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	desc.ByteWidth = sizeof(TransformData); // 구조체를 선언해준다.
	desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;

	HRESULT hr = _device->CreateBuffer(&desc, nullptr, _constantBuffer.GetAddressOf());
	CHECK(hr);
}


// 업데이트에서 버퍼 매핑
void Game::Update()
{
	// 1초동안 좌표가 이동하도록
	DWORD dwCurTime = ::timeGetTime();
	DWORD delta = dwCurTime - dwLastTime;
	float deltaSec = delta * 0.001f;
	dwLastTime = ::timeGetTime();
	_transformData.offset.x += 1.f * deltaSec;
	_transformData.offset.y += 1.f * deltaSec;

	if (_transformData.offset.x >= 1.f) _transformData.offset.x = 0.f;
	if (_transformData.offset.y >= 1.f) _transformData.offset.y = 0.f;

	// 버퍼 복사
	D3D11_MAPPED_SUBRESOURCE subResource;
	ZeroMemory(&subResource, sizeof(subResource));

	_deviceContext->Map(_constantBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &subResource);
	::memcpy(subResource.pData, &_transformData, sizeof(_transformData));
	_deviceContext->Unmap(_constantBuffer.Get(), 0);
}


// 렌더 과정에서 버퍼 전달
// Vertex Shader
_deviceContext->VSSetShader(_vertexShader.Get(), nullptr, 0);
_deviceContext->VSSetConstantBuffers(0, 1, _constantBuffer.GetAddressOf());

// 셰이더 코드에서 버퍼 활용
cbuffer TransformData : register(b0)
{
	float4 offset;
}

VS_OUTPUT VS(VS_INPUT input)
{
	VS_OUTPUT output;
	output.position = input.position + offset;
	output.uv = input.uv;

	return output;
}

1. 상수버퍼 생성

ID3D11Buffer 를 만들고, 생성한 버퍼로 복사할 구조체를 선언한다.

Usage 는 USAGE_DYNAMIC 으로. CPU 에서 쓰고, GPU 에서 읽는다.

BindFlags 는 CONSTANT_BUFFER

CPUAccessFlags 는 ACCESS_WRITE

 

2. DeviceContext 에 버퍼 매핑

Update() 함수에서 _deviceContext->Map() / Unmap() 함수 사이에 데이터를 복사해준다. 여기서 TransformData 의 offset 값은, 1초동안 위치가 계속 바뀌도록 수정함. 그래야 결과 확인이 용이하기 때문에.

 

유의해야할 것은, MAPPED_SUBRESOURCE 구조체를 통해서 전달한다는 점. Map 함수를 호출할 때 ID3D11Buffer 의 포인터가 subResource 구조체 안에 pData 로 전달.

 

3. 렌더 함수에서 버퍼 전달

Render() 함수의 VertexShader 아래에 _deviceContext->VSSetConstantBuffer 함수를 호출해서 D3D11Buffer 를 전달.

 

결과는 아래처럼, 1초마다 버텍스가 이동하는 것을 확인. 이 상수버퍼를 활용해서 메쉬를 셰이더에서 자유롭게 조작할 수 있음. 메쉬의 원래 버텍스 정보를 수정하지 않고도 가벼운 상수버퍼(Constant Buffer)를 전달함으로 인해 성능을 유리하게 가져갈 수 있음.

 

 

.


<리얼-타임 렌더링(REAL-TIME RENDERING) 4/e> 구입 링크
https://link.coupang.com/a/8VWas

 

리얼-타임 렌더링 4/e

COUPANG

www.coupang.com

<DirectX 12를 이용한 3D 게임 프로그래밍 입문> 구입 링크
https://link.coupang.com/a/8V4Wq

 

DirectX 12를 이용한 3D 게임 프로그래밍 입문:게임 개발 중심으로 익히는 대화식 컴퓨터 그래픽 프

COUPANG

www.coupang.com

유니티 에셋 스토어 링크

https://assetstore.unity.com?aid=1011lvz7h 

 

에셋스토어

여러분의 작업에 필요한 베스트 에셋을 찾아보세요. 유니티 에셋스토어가 2D, 3D 모델, SDK, 템플릿, 툴 등 여러분의 콘텐츠 제작에 날개를 달아줄 다양한 에셋을 제공합니다.

assetstore.unity.com

(링크를 통해 도서/에셋 구입시 일정액의 수수료를 지급받습니다.)


728x90
반응형