Camera

ㅋㅋ·2022년 7월 21일
0

DirectX12강의

목록 보기
20/39

SimpleMath.cpp, .h, .inl

Git으로 공유 중인 DirectXTK12 내에서 제공하는 수학 관련 클래스

계산 최적화 및 행렬의 전치, 역행렬, up vector, right vector 등을 쉽게 구할 수 있도록 도와주고

행렬 변환 시 필요한 것들을 만들 수 있음

해당 라이브러리는 오른손 좌표계를 기준으로 만들어져 있음


class Component
{
public:
	...

public:
	virtual void Awake() { }
	virtual void Start() { }
	virtual void Update() { }
	virtual void LateUpdate() { }
	virtual void FinalUpdate() { }

	...
};

유저 스크립트에서 사용되지 않고 엔진에서 사용할만 FinalUpdate 함수 추가

모든 메쉬들의 업데이트가 끝난 뒤 행렬 계산을 위함


position, rotation, scale

최상위 객체의 경우 월드 좌표계를 기준으로하는 값이지만,

하위 객체일 경우 parent 객체의 로컬 좌표계를 기준으로하는 값임


class Transform : public Component
{
public:
	...

private:
	Vec3 _localPosition = {};
	Vec3 _localRotation = {};
	Vec3 _localScale = { 1.f, 1.f, 1.f };

	Matrix _matLocal = {};
	Matrix _matWorld = {};

	weak_ptr<Transform> _parent;
};

transform에서 자신의 local 정보들과 parent를 정의

void Transform::FinalUpdate()
{
	Matrix matScale = Matrix::CreateScale(_localScale);
	Matrix matRotation = Matrix::CreateRotationX(_localRotation.x);
	matRotation *= Matrix::CreateRotationY(_localRotation.y);
	matRotation *= Matrix::CreateRotationZ(_localRotation.z);
	Matrix matTranslation = Matrix::CreateTranslation(_localPosition);

	_matLocal = matScale * matRotation * matTranslation;
	_matWorld = _matLocal * _parent->GetLocalToWorldMatrix();
}

FinalUpdate 함수에서 자신의 정보들을 가지고 행렬들을 만든다.

SRT를 곱하여 local 변환 함수를 만들고

local에서 world 변환 행렬을 곱하여 world 좌표계 행렬을 만든다.

추후 회전 행렬은 사원수로 교체


struct TransformParams
{
	Matrix matWVP;
};

Transform 클래스에서 관리하던 TransformMatrix를 위와 같이 변경


cbuffer TRANSFORM_PARAMS : register(b0)
{
    row_major matrix matWVP;
};

TransformMatrix를 사용하던 쉐이더 파일 수정

쉐이더에서 행렬을 접근하는 방식과 DirectX에서 행렬을 접근하는 방식이 다르기 때문에

row_major와 같이 명시적으로 알려줘야 함


VS_OUT VS_Main(VS_IN input)
{
    ...

    output.pos = mul(float4(input.pos, 1.f), matWVP);
    
    ...

    return output;
}

입력된 좌표 값과 MVP 행렬을 곱하여 투영 위치를 계산

해당 값은 위치이기 때문에 1.f를 추가


enum class PROJECTION_TYPE
{
	PERSPECTIVE,
	ORTHOGRAPHIC,
};

카메라가 가지는 두 가지 타입


class Camera : public Component
{
public:
	...

private:
	PROJECTION_TYPE _type = PROJECTION_TYPE::PERSPECTIVE;

	float _near = 1.f;
	float _far = 1000.f;
	float _fov = XM_PI / 4.f;
	float _scale = 1.f;

	Matrix _matView = {};
	Matrix _matProjection = {};

	...
};

카메라는 기본적인 near, far, fov 등의 투영 시 필요한 값들을 가지도록 정의


void Camera::FinalUpdate()
{
	_matView = GetTransform()->GetLocalToWorldMatrix().Invert();

	...

	if (_type == PROJECTION_TYPE::PERSPECTIVE)
		_matProjection = ::XMMatrixPerspectiveFovLH(_fov, width / height, _near, _far);
	else
		_matProjection = ::XMMatrixOrthographicLH(width * _scale, height * _scale, _near, _far);

	...
}

카메라의 월드 변환 행렬의 역행렬을 구함 => camera view 변환 행렬

DirectX 함수를 이용하여 투영 변환 행렬을 구한다.

(SimplaMath 투영 변환 행렬은 오른손 좌표계 기준)


void Transform::PushData()
{
	Matrix matWVP = _matWorld * Camera::S_MatView * Camera::S_MatProjection;
	CONST_BUFFER(CONSTANT_BUFFER_TYPE::TRANSFORM)->PushData(&matWVP, sizeof(matWVP));
}

PushData 함수가 불릴 때 constant buffer에 MVP 변환 행렬을 업로드


void MeshRenderer::Render()
{
	GetTransform()->PushData();
	_material->PushData();
	_mesh->Render();
}

MeshRenderer에서 렌더링 시 transform과 material의 데이터를 GPU에 업로드 후

mesh를 렌더링 한다.

또한 Render 함수가 update 함수에서 불렸는데

이를 게임 로직 업데이트 부분과 렌더링 부분을 나누기 위하여 해당 부분을 삭제함


void Engine::Update()
{
	...
	GET_SINGLE(SceneManager)->Update();

	Render();

	...
}

void Engine::Render()
{
	RenderBegin();

	GET_SINGLE(SceneManager)->Render();

	RenderEnd();
}

엔진에서 update로 로직과 렌더링을 모두 하던 부분을 분리

임시적으로 scene manager가 오브젝트들을 렌더링 하도록 구현

void SceneManager::Render()
{
	...

	const vector<shared_ptr<GameObject>>& gameObjects = _activeScene->GetGameObjects();
	for (auto& gameObject : gameObjects)
	{
		if (gameObject->GetCamera() == nullptr)
			continue;

		gameObject->GetCamera()->Render();
	}
}

Scene에서 카메라 객체를 찾아 카메라를 렌더링

=>

light 추가 후 수정


shared_ptr<Scene> SceneManager::LoadTestScene()
{
	...

	shared_ptr<GameObject> camera = make_shared<GameObject>();
	camera->AddComponent(make_shared<Transform>());
	camera->AddComponent(make_shared<Camera>());
	camera->GetTransform()->SetLocalPosition(Vec3(0.f, 100.f, 0.f));
	scene->AddGameObject(camera);
}

Scene에 카메라를 추가하여 테스트

0개의 댓글