본문 바로가기

Library/Computer Graphics

Projection Transformation

투영 변환(projection transformation)은 모델뷰 변환(modelview transformation) 뒤에 이루어지는데, 이 변환은 뷰포트 변환(viewport transformation)을 위한 준비 단계이다. 즉, 임의의 가상의 3D 공간은 어쨌거나 최종적으로는 2D 공간에 투영(projection)되어야 하며, 투영 변환은 이를 위한 준비 변환이다. 물론, 직접 3D 공간 좌표를 2D 장치 좌표계로 변환하는 것은 뷰포트 변환이지만, 모델뷰 변환 바로 뒤에 뷰포트 변환을 할 수는 없다. 물체가 정의된 공간이 어느 만큼 보여져야 하는지 결정되지 않았고, 모델뷰 변환을 거친 뒤의 정점 정보를 직접 2D 장치 좌표계로 옮길 수 없기 때문이다.

또, 성능 측면에서 본다면, 실시간 렌더링 시스템에서 임의의 공간을 모두 그리는 것은 대단히 비효율적이다. 카메라를 예로 들어 설명한다면, 카메라 렌즈에 잡히는 영상은 제한적인데 영상 외의 모든 물체를 다 그리는 셈이다. 따라서, 모든 물체를 다 그리는 것보다 카메라 시점을 고려하여 투영 평면이 결정하고, 이 평면 외의 물체는 모두 제외하는 방법을 생각해 볼 수 있다. 이것을 클리핑(clipping) 처리라고 하며, 대부분의 그래픽 시스템은 더 효율적인 처리를 위해 정규화(normalization)된 결과를 클리핑한다.

투영 변환이 실제적으로 하는 일은, 관찰자에게 보여질 대상을 결정하여 일정한 체적(volume)을 생성하는 것이다. 이미 주어진 관찰자 시점(카메라 시점, 뷰)과 투영 방식, 투영 크기를 지정하면 이 정보를 바탕으로 보여질 공간을 결정할 수 있게 된다. OpenGL과 같은 경우, 시점을 결정하는 gluLookAt, 투영 방식을 결정하는 glOrtho, glFrustum과 같은 함수를 사용할 수 있다. 그리고 대부분의 그래픽 시스템은 투영 변환을 지정하면 생성된 체적을 일정한 크기로 정규화한다. 즉, 길이를 2로, 체적의 중심을 원점으로 이동시켜 변환한다. 대부분의 그래픽 시스템은 이 결과를 뷰포트 변환 단계에서 재정규화하는데, 이것은 다음의 뷰포트 변환을 좀 더 효과적으로 하기 위해서다(즉 정규화된 z 값이 [0, 1] 사이의 값을 가지도록 z축 방향으로 1 / 2으로 축소하고, 다시 z축 방향으로 1 / 2만큼 이동한다). 정규화가 파이프라인 처리를 좀 더 효율적으로 만드는 이유 중 하나는, 정규화된 결과가 평행 투영(orthographic projection)과 원근 투영(perspective projection) 모두 동일하게 처리할 수 있도록 만들기 때문이다. 클리핑 역시 정규화 뒤에 처리하면 훨씬 효과적으로 처리할 수 있다. 정규화된 체적을 정규화 가시부피(CVV : canonical view volume)라고 한다.

정규화를 하는 또 다른 이유는, 위에서도 언급했지만 최종 출력 장치의 출력 단위가 모델뷰 변환을 거친 뒤의 정점값 범위와 맞지 않을 수도 있기 때문이다. 예를 들어, 부동소수점 형식으로 정점 정보가 표현되었다면, 정수형 픽셀 위치 정보를 표현하는 프레임버퍼 장치는 직접 이 값을 사용할 수 없다. 따라서, 일정한 범위로 변환된 값들을 각각의 장치에 맞는 수치로 매핑할 필요가 있다. 정규화 된 값을 사용한다면, 실제 3D 모델 변환 과정에서는 실제 장치들의 좌표 특성에 상관 없이 장치 독립적으로 값을 다룰 수 있게 된다.


투영 변환까지는 3D 정점 좌표가 유지되는데, 이것은 최종적으로 2D 화면에 투영될 대상을 결정하기 위한 z-버퍼(z-buffer, 깊이 검사) 테스트를 위해서다. 관찰자를 기준으로, 관찰자와 가까운 물체와 먼 물체가 겹쳐 있을 때, 어떤 것이 보일지는 자명하다. z 값은 물체의 가시성 여부를 판단하고 뷰포트 변환이 이루어진 뒤 소실된다. 따라서 뷰포트 변환의 역변환은 가능하지 않다.

마지막으로, 투영 변환과 모델뷰 변환이 서로 다른 행렬 스택을 가진다는 사실을 생각해보자. OpenGL에서는 glMatrixMode(), DX에서는 SetTransform() 함수를 사용하여 어떤 변환을 적용할지 결정할 수 있다. 이것은, 모델뷰 변환과 투영 변환이 서로 독립적인 변환이기 때문이다(파이프라인 처리에서 서로 독립적이다). 즉, 모델뷰 변환은 전역 좌표계를 로컬 좌표계로 일치시켜 물에게 변환을 가하는 것이며, 투영 변환은 지정된 공간 전체에 대해 투영 행렬을 곱해 체적을 만들어내는 변환이다. 이 둘은 각각의 행렬 스택을 가지고 있으며, glMatrixMode(), SetTransform()은 다음에 올라오는 행렬이 어느 행렬 스택에 추가될지 결정한다.


역시, 투영 변환을 위한 Nate Robin의 GL Tutorial 프로그램들이 존재하는데, OpenGL의 해당 함수들의 파라미터가 어떻게 적용되는지 쉽게 알 수 있다.




Nate Robin의 GL Tutorial 프로그램들은 다음 링크에서 구할 수 있다.

http://www.xmission.com/~nate/index.html