DirectX/[Inflearn_rookiss] Part2: DirectX12

23. Orthographic Projection

헛둘이 2023. 2. 2. 12:21

직교투영은 원근투영과 다르게 깊이 값에 대해 크기를 보정해주지 않는다.

UI와 같은 고정된 화면을 만들 때 유용하게 사용된다.

 

*NDC 좌표계는 x(-1~1), y(-1~1), z(0~1)로 되어 있다.

- x, y만 봤을 때 가운데가 (0, 0)이고 우상단은 (1, 1)이 되어야 함

- 실제 크기인 width, height를 대입해보면 좌표는 우상단이 w/2, h/2이므로 이 값을 1, 1로 만들어 주어야 한다.

- 그러려면 x = 2x/w로 계산하고, y = 2y/h로 계산해야 한다.

- (x는 x를 (w/2)로 나눈 값이고, y는 y를 (h/2)로 나눈 값이다.)

- z는 비교적 조금 더 까다롭다.

- z = z / (f - n) - n / (f - n) 이 식에 z를 대입하여 계산해면 된다.

- 계산해보면 z가 n이면 0이 되고, f면 1이 된다. 

 


UI를 찍을 직교 카메라 추가

 

- 기존에는 원근투영으로 물체를 찍는 카메라만 두고 모든 물체를 그려냈지만

- 이번 예제에서 직교투영으로 물체를 찍는 카메라를 만들어서 UI를 그려낸다.

- 그럼 어떤 물체 A를 두고 얘를 원근투영으로 그릴지, 직교투영으로 그릴지 판단하는 기준은?

 

 

 

레이어 개념 도입

 

- 레이어는 Default, UI라는 종류가 있으며,

- GameObject가 Layer를 소유하고 있다.

- 카메라가 그려줄 때 이 Layer를 검사해서 그릴 지 말 지 결정하는 방식

- 카메라마다 비트플래그로 32비트 부호없는 정수형 하나를 들고 있고,

- 씬 매니저에서 카메라를 생성할 때 특정 레이어를 그릴지 말지 선택할 수 있다.

 

void SetCullingMaskLayerOnOff(uint8 layer, bool on)
{
	if (on)
		_cullingMask |= (1 << layer);
	else
		_cullingMask &= ~(1 << layer);
}
	
void SetCullingMaskAll() { SetCullingMask(UINT32_MAX); }
void SetCullingMask(uint32 mask) { _cullingMask = mask; }
bool IsCulled(uint8 layer) { return (_cullingMask & (1 << layer)) != 0; }

- 카메라에서 비트값을 처리하는 함수들 정의

 

uint32 _cullingMask = 0;

- 컬링 마스크라고 해서 유니티에 있는 개념인데, 어떤 레이어를 그려줄 지를 결정

 

 

uint8 _layerIndex = 0;

- 게임 오브젝트는 위와 같은 값을 가지고 있어서 이 값을 Get 함수를 통해 카메라가 검사한다

 

sphere->SetLayerIndex(GET_SINGLE(SceneManager)->LayerNameToIndex(L"UI"));
void Camera::Render()
{
	S_MatView = _matView;
	S_MatProjection = _matProjection;

	shared_ptr<Scene> scene = GET_SINGLE(SceneManager)->GetActiveScene();

	const vector<shared_ptr<GameObject>>& gameObjects = scene->GetGameObjects();

	for (auto& gameObject : gameObjects)
	{
		if (nullptr == gameObject->GetMeshRenderer())
			continue;

		if (IsCulled(gameObject->GetLayerIndex()))
			continue;

		if (gameObject->GetCheckFrustum())
		{
			if (_frustum.ContainsSphere(
				gameObject->GetTransform()->GetWorldPosition(),
				gameObject->GetTransform()->GetBoundingSphereRadius()) == false)
			{
				continue;
			}

		}

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