수업


✅ 주제

  • DirectX11의 상수 버퍼(Constant Buffer)를 활용하여, C++ 측에서 선언한 World/View/Projection 행렬을 GPU 셰이더로 전달하고,
  • 키보드 입력을 통해 객체를 이동시키며,
  • FX11의 SetMatrix/GetMatrix 함수로 셰이더와 연동하는 실습을 구현한다.

📚 개념

  • 상수 버퍼(Constant Buffer) 는 C++에서 정의된 행렬 값 등을 GPU의 HLSL 셰이더로 전달하기 위한 버퍼 구조다.
  • 이 강의에서는 FX11을 활용하여 별도의 cbuffer 선언 없이도 matrix 선언만으로 World/View/Projection 행렬을 GPU에 연결할 수 있다.
  • 키보드 입력을 받아 Translation 벡터를 조정하고, 이를 기반으로 Matrix::CreateTranslation()을 사용해 월드 행렬을 생성한다.
  • _shader->GetMatrix("변수명")->SetMatrix()를 통해 FX11 셰이더 내의 변수에 값을 전달한다.

📑 용어정리

용어설명
Constant BufferCPU → GPU로 고정 데이터를 전달할 때 사용하는 버퍼. 주로 행렬, 조명 정보 등
World/View/Projection Matrix각각 객체 위치/카메라 뷰/투영 설정을 표현하는 4x4 행렬
FX11DirectX11의 HLSL Shader를 효과적으로 관리하기 위한 Effect 프레임워크
SetMatrix / GetMatrixFX11 함수. 셰이더 내부 변수와 C++ 코드의 행렬 데이터를 연결할 때 사용
Matrix::CreateTranslation위치 이동 행렬을 생성하는 DirectXMath 함수
Delta Time프레임 간 시간 간격으로, 시간 기반 이동에 사용
RasterizerState와이어프레임 또는 솔리드 렌더링 설정 상태

🧩 코드 분석

1. Shader 구성 (03. ConstBuffer.fx)

matrix World;
matrix View;
matrix Projection;

struct VertexInput
{
	float4 position : POSITION;
	float4 color : COLOR;
};

struct VertexOutput
{
	float4 position : SV_POSITION;
	float4 color : COLOR;
};

VertexOutput VS(VertexInput input)
{
	VertexOutput output;
    output.position = mul(input.position, World);       // 월드 행렬 적용
    output.position = mul(output.position, View);       // 뷰 행렬 적용
    output.position = mul(output.position, Projection); // 프로젝션 행렬 적용
    output.color = input.color;
	return output;
}

float4 PS(VertexOutput input) : SV_TARGET
{
    return input.color;
}

RasterizerState FillModeWireFrame
{
    FillMode = Wireframe;
};

technique11 T0
{
	pass P0
	{
		SetVertexShader(CompileShader(vs_5_0, VS()));
		SetPixelShader(CompileShader(ps_5_0, PS()));
	}
	pass P1
	{
        SetRasterizerState(FillModeWireFrame);
		SetVertexShader(CompileShader(vs_5_0, VS()));
		SetPixelShader(CompileShader(ps_5_0, PS()));
	}
};

설명 요약

  • matrix로 선언된 World, View, Projection은 FX11 구조에 따라 자동 상수 버퍼로 처리된다.
  • VS 단계에서 mul을 통해 변환 행렬을 적용하여 최종 위치 계산.
  • PS에서는 색상만 단순 반환 (변환 영향 없음).
  • RasterizerState를 통해 wireframe 렌더링 모드도 설정 가능.

2. ConstBufferDemo 클래스 구성 (ConstBufferDemo.h)

class ConstBufferDemo : public IExecute
{
public:
	void Init() override;
	void Update() override;
	void Render() override;

	shared_ptr<Shader> _shader;
	shared_ptr<Geometry<VertexColorData>> _geometry;
	shared_ptr<VertexBuffer> _vertexBuffer;
	shared_ptr<IndexBuffer> _indexBuffer;

	Vec3 _translation = Vec3(0.f, 0.f, 0.f);       // 위치 벡터
	Matrix _world = Matrix::Identity;             // 월드 행렬
	Matrix _view = Matrix::Identity;              // 뷰 행렬
	Matrix _projection = Matrix::Identity;        // 프로젝션 행렬
};

포인트

  • _translation은 위치 이동 누적값.
  • 모든 행렬은 기본적으로 단위행렬로 시작하며, _worldUpdate() 내에서 실시간 계산.

3. Init 함수 (ConstBufferDemo.cpp)

void ConstBufferDemo::Init()
{
	_shader = make_shared<Shader>(L"03. ConstBuffer.fx");

	_geometry = make_shared<Geometry<VertexColorData>>();
	GeometryHelper::CreateQuad(_geometry, Color(1.f, 0.f, 0.f, 1.f));

	_vertexBuffer = make_shared<VertexBuffer>();
	_vertexBuffer->Create(_geometry->GetVertices());

	_indexBuffer = make_shared<IndexBuffer>();
	_indexBuffer->Create(_geometry->GetIndices());
}

역할 요약

  • Shader, Geometry, VertexBuffer, IndexBuffer 초기화.
  • 정점 4개, 인덱스 6개 기반의 Quad 정의 (색상은 빨강).

4. Update 함수

void ConstBufferDemo::Update()
{
	float dt = TIME->GetDeltaTime();

	if (INPUT->GetButton(KEY_TYPE::A)) _translation.x -= 3.f * dt;
	else if (INPUT->GetButton(KEY_TYPE::D)) _translation.x += 3.f * dt;
	else if (INPUT->GetButton(KEY_TYPE::W)) _translation.y += 3.f * dt;
	else if (INPUT->GetButton(KEY_TYPE::S)) _translation.y -= 3.f * dt;

	_world = Matrix::CreateTranslation(_translation);
}

핵심

  • 키 입력(A/D/W/S)에 따라 x, y 좌표가 변화하고 _translation 값이 갱신된다.
  • 해당 값을 바탕으로 이동 행렬을 생성 (_world), 이후 Render()에서 셰이더로 전달된다.
  • DeltaTime을 곱함으로써 PC 사양에 관계없이 일정한 속도 유지.

5. Render 함수

void ConstBufferDemo::Render()
{
	_shader->GetMatrix("World")->SetMatrix((float*)&_world);
	_shader->GetMatrix("View")->SetMatrix((float*)&_view);
	_shader->GetMatrix("Projection")->SetMatrix((float*)&_projection);

	uint32 stride = _vertexBuffer->GetStride();
	uint32 offset = _vertexBuffer->GetOffset();

	DC->IASetVertexBuffers(0, 1, _vertexBuffer->GetComPtr().GetAddressOf(), &stride, &offset);
	DC->IASetIndexBuffer(_indexBuffer->GetComPtr().Get(), DXGI_FORMAT_R32_UINT, 0);

	_shader->DrawIndexed(0, 0, _indexBuffer->GetCount(), 0, 0);
}

상세 설명

  • _shader->GetMatrix("World") 등의 호출로 FX11에서 선언한 matrix 변수를 가져온 뒤,
    SetMatrix()를 통해 C++에서 계산한 행렬을 바인딩한다.
  • DrawIndexed() 호출을 통해 인덱스를 기반으로 사각형 출력.

🎯 핵심

  1. 상수 버퍼를 FX11 구조를 활용하여 간단하게 구현할 수 있다. matrix 선언만으로도 자동 관리된다.
  2. GetMatrix/SetMatrix 방식으로 셰이더 변수와 연동하면, 직접적인 cbuffer 선언 없이도 셰이더와 값 연동이 가능하다.
  3. Translation 벡터를 기반으로 월드 행렬을 생성하며, 키보드 입력을 통해 실시간 위치 이동이 가능하다.
  4. Vertex/Index Buffer를 바인딩하고 DrawIndexed를 호출하여 GPU 기반 렌더링을 수행한다.
  5. RasterizerState를 활용한 Wireframe 출력 가능 → pass 변경만으로 모드 전환 가능.
  6. UTF-8 BOM 없는 인코딩을 사용해야 쉐이더 컴파일 에러 방지할 수 있다.
  7. 매 프레임마다 GetMatrix 호출보다는 미리 변수로 저장해 사용하는 방식이 성능에 더 유리하다.

profile
李家네_공부방

0개의 댓글