Make Unreal REAL.
article thumbnail
이득우의 게임 수학

 

3차원 공간에 투시 원근법의 원리를 적용하기 위해서는, 공간의 모든 점이 한 점을 향해 모이는 형태로 변경해야 한다.

 

이러한 변환을 원근 투영 변환(Perspective projection transformation)이라고 한다.

  • 우리 눈이 바라보는 방식으로 가상 공간을 변환하는 것이다.

 

카메라에서 눈에 보이는 범위를 화각(FOV, Field of View)이라고 한다.

 

 

원근 투영 변환은 x, y, z축이 모두 직교하는 정육면체 형태의 뷰 공간(View space)을 카메라의 한 점으로 모이는 사각뿔 형태를 가진 공간으로 변환하는 작업이다.

 

 

3차원 공간을 변환한 후에는 공간의 물체를 투영해 2차원 모니터 평면에 담아내야 한다.

 

이를 위해 모든 물체의 상이 맺히게 하는 가상의 평면을 투영 평면(Projection plane)이라고 하고, 카메라로부터 투영 평면까지의 거리를 초점 거리(Focal length)라고 한다.

 

 

원근 투영을 하기 전에 우선 투영 평면의 위치를 지정해야 한다.

  • 일반적으로 투영 평면의 위치는 계산의 편의를 위해 위/아래의 크기가 각각 1이 되는 지점으로 결정한다.

 

 

좌우와 상하의 화각이 동일하므로 투영 평면은 각각 [-1, 1]의 범위를 갖는 정사각형의 모습을 띄며 이 평면에 물체의 상이 맺힌다.

 

투영 편면에 대응하는 정사각형 영역은 가운데 중점을 원점으로 하는 2차원 평면의 좌표시스템을 가지는데 이를 정규화 장치 좌표계(NDC, Normalized Device Coordinate)라고 부른다.

 

 

투영 평면에 대응하는 NDC가 항상 일정한 값을 가지려면, 카메라의 화각이 변할 때 초점 거리는 달라질 수 밖에 없다.

  • 화각이 커질수록 초점 거리는 가까워지고, 화각이 작아질수록 초점 거리는 멀어진다.
  • 가만히 있는 필통에 가위를 물려 앞뒤로 움직인다고 생각하면 쉽다.

 

 

NDC에서 화각 α와 초점 거리 d와의 관계는 다음과 같다.

 

 

tan 함수를 사용해 초점 거리를 구했다면, 뷰 공간의 점을 투영 평면 위의 점으로 대응시키는 원근 투영 변환을 설계한다.

  • 행렬 곱의 장점을 살려 파이프라인을 최적화할 수 있도록 행렬로 설계해야 한다.

 

지금까지 진행한 공간 변환은 모두 x, y, z축이 서로 직교하고 크기가 동일한 정육면체 공간의 3차원 공간이었다.

  • 이렇게 세 축이 모두 직교하는 공간을 유클리드 공간(Euclidean space)이라고 한다.
  • 로컬 공간, 월드 공간, 뷰 공간은 모두 유클리드 공간이다.

 

정육면체 형태의 유클리드 공간은 원근 투영 변환에 의해 사각뿔 형태의 사영 공간(Projective space)으로 변환된다.

 

사영 공간의 x축과 y축은 여전히 직교하기 때문에 유클리드 공간과 동일한 성질을 갖지만, z축은 독립적으로 행동하지 않고 x축과 y축에 모두 영향을 준다.

  • 초점 거리(z축)에 따라 x축과 y축이 만드는 투영 편면의 면적이 달라지는 이유이다.

 

 

유클리드 공간이 사영 공간으로 변환되면서 x, y, z축이 모두 직교하는 체계가 달라지기 때문에, 원근 투영 변환 행렬은 표준 기저 벡터의 변화를 관찰하는 방법으로는 생성할 수 없다.

 

x값을 0으로 고정하고 뷰 공간의 점 P.v가 투영 평면에 투영된 점을 P.ndc라고 할 때, 두 점의 좌표는 다음과 같다.

 

 

삼각형의 닮은꼴 성질로부터 비례식을 세워보면 다음과 같다.

  • 뷰 공간에서 카메라 앞에 위치한 점의 z값은 항상 음수이다.

 

 

비례식으로부터 투영 평면의 y값 nᵧ는 다음과 같고, y값을 0에 고정하면 nₓ도 구할 수 있다.

 

 

따라서 초점 거리와 뷰 좌표로부터 투영 평면 위의 점 P.ndc는 다음과 같이 구할 수 있다.

  • 결국은 초점 거리에 비례한다.

 

 

이제 NDC 좌표를 화면 해상도만큼 가로, 세로로 늘려주면 최종 스크린 좌표가 완성된다.

 

 

그런데 대부분의 경우 최종 화면의 크기 비율이 1:1로 균등하지 않기 때문에, 가로, 세로로 늘리면 물체가 찌그러지는 문제가 발생한다.

 

이때 가로, 세로의 비를 종횡비(Aspect ratio)라고 한다.

  • 모니터 화면은 보톤 16:10이나 4:3등의 비율을 갖는다.

 

 

다소 야매스러운 해결책이라고 생각할 순 있겠지만, 가장 간단한 방법은 화면의 종횡비를 미리 파악해 NDC에 점을 물체를 투영할 때, 늘어날 만큼의 비율을 뒤집어 먼저 찌그러트리는 것이다.

 

 

종횡비는 보통 하나의 축을 1로 고정하고 다른 축의 크기를 상대적으로 측정해 나타낸다.

  • 세로를 기준으로 할 때, 800 x 600 → 1.3333...

 

종횡비를 a라고 할 때, 투영 결과를 미리 찌그러트린 점 P.ndc의 좌표는 다음과 같다.

  • 세로를 기준으로 했으므로, x좌표에 역수를 곱해 좌우로 찌그러트리면 된다.

 

 

따라서 투영 행렬 P는 다음과 같이 설계할 수 있다.

 

뷰 공간의 점 P.view(x, y, z)의 값과 y값으로 만든 벡터를 v(x, y)로 지정하면, 최종적으로 P.ndc는 다음과 같이 계산할 수 있다.

 

 

그런데, 여기서 문제가 있다.

 

원근 투영 행렬에 뷰 공간의 점 P.view의 z값이 사용되다 보니, 변환할 점마다 새로운 행렬을 생성해야 한다는 점이다.

  • 이렇게 되면 행렬 곱을 통해 연산량을 줄이기 힘들다.
  • 따라서, 원근 투영 행렬은 카메라 설정만으로 만들 수 있어야 한다.

 

유도했던 투영 행렬을 살펴보면, 행렬의 구성 요소는 모두 -v.z를 분모로 한다.

  • 행렬에서 -v.z값을 제거하고, 대신 결괏값에서 -v.z를 나눠주는 식으로 해결할 수 있다.

 

NDC 좌표와는 다르지만, 카메라 설정만으로 구성된 -v.z를 나누기 전의 투영 행렬 P는 다음과 같다.

 

 

이렇게 원근 투영 행렬 P로 변환되는 좌표계를 클립 좌표계(Clip coordinate)라고 하며, 클립 좌표 P.clip은 다음과 같이 계산된다.

 

 

마지막으로, 클립 좌표의 점 P.clip의 각 요소를 -v.로 나눠주면 최종적으로 NDC 좌표를 얻을 수 있다.

  • 정점이 카메라와 같은 위치에 있다면 Z값은 0이 되는데, 이때는 계산이 불가능하므로 아주 작은 값으로 대체해줘야 한다.

 

'게임 수학 > 이득우의 게임 수학' 카테고리의 다른 글

깊이(Depth)  (0) 2023.05.15
동차 좌표계  (0) 2023.05.14
삼중곱(Triple product)  (0) 2023.05.12
로드리게스 회전 공식  (0) 2023.05.11
백페이스 컬링(Backface Culling)  (0) 2023.05.10
profile

Make Unreal REAL.

@diesuki4

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

검색 태그