23. Orthographic Projection
직교투영은 원근투영과 다르게 깊이 값에 대해 크기를 보정해주지 않는다.
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();
}
}