수업


주제

  • DirectX11 기반 3D 엔진에서 카메라 시스템을 유니티 스타일 컴포넌트 구조로 구현한다.
  • Transform, Camera, CameraScript를 조합하여 이동 가능하고 회전 가능한 카메라 객체를 만든다.
  • Camera가 View / Projection 행렬을 계산하고 이를 FX11 셰이더와 연동하여 화면에 반영한다.

개념

  • 카메라는 3D 공간을 투영하여 2D 화면에 보여주는 핵심 시스템이다.
  • View 행렬은 카메라 기준 좌표계로 변환하는 행렬이며, Projection 행렬은 원근감 표현을 위한 행렬이다.
  • 유니티 스타일 구조는 GameObject에 여러 Component를 부착하여 기능을 확장하며, 사용자 입력은 MonoBehaviour를 상속한 스크립트에서 처리한다.
  • DirectX11에서도 이와 유사한 구조로 카메라 시스템을 구성할 수 있다.

용어정리

용어설명
GameObject여러 Component를 조합하여 구성하는 씬의 기본 단위
Transform위치, 회전, 스케일을 관리하는 컴포넌트
CameraView/Projection 행렬 계산 및 갱신을 담당하는 컴포넌트
CameraScript키보드 입력을 처리해 카메라를 움직이는 스크립트 컴포넌트
XMMatrixLookAtLH카메라 위치, 시선 방향, Up벡터로 View 행렬 생성
XMMatrixPerspectiveFovLH시야각, 비율, 근거리/원거리 클리핑 값으로 Projection 행렬 생성
FX11DirectX11의 셰이더 효과 처리 시스템 (Effect 기반 technique/pass 사용)

코드 분석

1. Camera 클래스 구성

📁 Camera.h

class Camera : public Component {
public:
	Camera();
	virtual ~Camera();
	virtual void Update() override;

	void UpdateMatrix(); // View/Projection 행렬 갱신

	void SetNear(float value);
	void SetFar(float value);
	void SetFOV(float value);
	void SetWidth(float value);
	void SetHeight(float value);

	Matrix& GetViewMatrix();
	Matrix& GetProjectionMatrix();

private:
	Matrix _matview = Matrix::Identity;
	Matrix _matProjection = Matrix::Identity;

	float _near = 1.f;
	float _far = 1000.f;
	float _fov = XM_PI / 4.f;
	float _width = 0.f;
	float _height = 0.f;

public:
	static Matrix S_MatView;
	static Matrix S_MatProjection;
};

📁 Camera.cpp

Matrix Camera::S_MatView = Matrix::Identity;
Matrix Camera::S_MatProjection = Matrix::Identity;

Camera::Camera() : Super(ComponentType::Camera) {
	_width = static_cast<float>(GAME->GetGameDesc().width);
	_height = static_cast<float>(GAME->GetGameDesc().height);
}

void Camera::Update() {
	UpdateMatrix(); // 매 프레임마다 View/Projection 갱신
}

void Camera::UpdateMatrix() {
	Vec3 eyePosition = GetTransform()->GetPosition();                   // 카메라 위치
	Vec3 focusPosition = eyePosition + GetTransform()->GetLook();      // 바라보는 방향
	Vec3 upDirection = GetTransform()->GetUp();                         // 위쪽 방향

	S_MatView = XMMatrixLookAtLH(eyePosition, focusPosition, upDirection); // View 행렬
	S_MatProjection = XMMatrixPerspectiveFovLH(_fov, _width / _height, _near, _far); // Projection 행렬
}

2. CameraScript 구성

📁 CameraScript.h

class CameraScript : public MonoBehaviour {
public:
	void Start() override;
	void Update() override;

	float _speed = 10.f;
};

📁 CameraScript.cpp

void CameraScript::Update() {
	float dt = TIME->GetDeltaTime();
	Vec3 pos = GetTransform()->GetPosition();

	if (INPUT->GetButton(KEY_TYPE::W)) pos += GetTransform()->GetLook() * _speed * dt;
	if (INPUT->GetButton(KEY_TYPE::S)) pos -= GetTransform()->GetLook() * _speed * dt;
	if (INPUT->GetButton(KEY_TYPE::A)) pos -= GetTransform()->GetRight() * _speed * dt;
	if (INPUT->GetButton(KEY_TYPE::D)) pos += GetTransform()->GetRight() * _speed * dt;

	GetTransform()->SetPosition(pos);

	Vec3 rot = GetTransform()->GetLocalRotation();
	if (INPUT->GetButton(KEY_TYPE::Q)) rot.x -= dt * 0.5f;
	if (INPUT->GetButton(KEY_TYPE::E)) rot.x += dt * 0.5f;
	if (INPUT->GetButton(KEY_TYPE::Z)) rot.y -= dt * 0.5f;
	if (INPUT->GetButton(KEY_TYPE::C)) rot.y += dt * 0.5f;
	GetTransform()->SetLocalRotation(rot);
}
  • WASD: 전후좌우 이동
  • QE / ZC: 상하/좌우 회전

3. CameraDemo 클래스 구성

📁 CameraDemo.h

class CameraDemo : 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;

	Matrix _world = Matrix::Identity;

	shared_ptr<GameObject> _camera;
};

📁 CameraDemo.cpp

void CameraDemo::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());

	// 카메라 조립
	_camera = make_shared<GameObject>();
	_camera->GetOrAddTransform();
	_camera->AddComponent(make_shared<Camera>());
	_camera->AddComponent(make_shared<CameraScript>());

	_camera->GetTransform()->SetPosition(Vec3(0.f, 0.f, -2.f)); // 시야 안에 물체 보이도록
}

void CameraDemo::Update() {
	_camera->Update(); // 카메라 내부 컴포넌트 전부 업데이트됨
}

void CameraDemo::Render() {
	_shader->GetMatrix("World")->SetMatrix((float*)&_world);
	_shader->GetMatrix("View")->SetMatrix((float*)&Camera::S_MatView);
	_shader->GetMatrix("Projection")->SetMatrix((float*)&Camera::S_MatProjection);

	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);
}

핵심

  1. 카메라는 View / Projection 행렬을 매 프레임마다 자동 갱신한다.
  2. Transform + Camera + CameraScript의 조합은 유니티 구조 그대로 이식한 설계다.
  3. 카메라의 위치/방향은 Transform을 기준으로 조작되며, 입력은 Script에서 처리된다.
  4. 행렬은 FX11 기반 셰이더의 GetMatrix / SetMatrix로 GPU에 전달된다.
  5. 유지보수와 확장성을 고려한 컴포넌트 구조로 다른 오브젝트와도 동일하게 적용 가능하다.
  6. 모든 Update는 GameObject::Update() 호출만으로 처리된다.
  7. 언리얼 방식과도 호환 가능한 설계이며, 필요한 경우 Actor 상속 구조로 전환 가능하다.

profile
李家네_공부방

0개의 댓글