-
[컴퓨터 그래픽스] Vertex Processing컴퓨터그래픽스 2024. 2. 16. 13:48
저번에 Polygon mesh에 관한 글을 포스팅 했다. 오늘은 GPU가 Polygon mesh를 입력받아 우리 스크린에서 매끄럽고 다채로운 이미지로 보이기까지의 과정을 설명하려고 한다.

대략적인 과정은 다음 순서를 따른다
- GPU가 polygon mesh를 입력으로 받는다
- 3차원 polygon mesh를 스크린에 맞게 2차원으로 바꾼다
- 2차원 polygon mesh을 채우는 pixel의 색상을 결정한다 ( 이때 픽셀의 색상은 컬러 버퍼-color buffer에 기록된다 )
- 컬러 버퍼는 주기적으로( 여기서 말하는 주기가 런타임인지는 조금 더 공부해야 알 것 같다) 스크린으로 복사된다.
요런 일련의 과정을 GPU 랜더링이라 하는데 이는 컴구시간에 배운 파이프라인 구조로 되어있다.
저 과정들을 수행하기 위해선 여러 프로그램들이 요구된다. 정점 쉐이더, 레스터라이저, 프래그먼트쉐이더, 출력 병합기 순으로 총 4개인데,
정점 쉐이더와 프래그먼트쉐이더를 직접 작성해 줘야 하고, 레스터라이저와 출력 병합기는 우리가 쓰는 하드웨어에 고정된 상태로 존재한다.
위 4가지 프로그램들의 역할은 앞으로 쓸 2~3개의 포스팅에서 차차 설명하기로 하고, 오늘은 정점 쉐이더(Vertex Shader)의 역할을 중점적으로 설명하려고 한다.
정점 쉐이더 ( Vertex Shader )
진짜... 내용도 많고 어려워서 처음으로 벽느낀 파트이다. 수강 당시에는 벽을 넘진 못하고 그냥 몸통박치기로 뚫어서 내 몸도 피투성이가 된 느낌이었다. 오브젝트 공간에서 월드 공간으로의 변환은 저번 포스팅에 설명했다. 이때, [L|t] 부분에서 L은 누적된 선형 변환, t는 누적된 이동을 뜻했는데, 요 L을 가지고 정점의 Normal 또한 변환시켜 줘야 한다.
그런데 그냥 L그대로 오브젝트 공간에서의 normal에 적용하면 문제가 발생할 수 있다. 만약 L이 non-uniform scaling을 포함한다면 문제가 발생하게 된다. 때문에 어떤 경우라도 normal의 변환은 L의 역전치행렬(inverse transpose)을 적용해야 한다. 역전치행렬은 말 그대로 L의 역행렬의 전치행렬이다.
정점 쉐이더의 역할 중 첫 번째 단계로 오브젝트공간 -> 월드공간 변환을 수행하며 정점과, 노말을 월드 공간으로 변환시켰다.
그 다음 단계는 View transform을 통해 월드공간의 물체를 카메라 공간으로 바꿔주는 것이다.
먼저 카메라 공간에 대해 설명을 해야겠다.
우리가 보통 게임을 할때 스크린으로 보는 화면은 바로 특정 카메라가 어떤 물체를 바라보는 관점이라 할 수 있다. 게임을 할때 다양한 시야에서 물체를 바라보는 것은 실시간으로 카메라가 그 위치를 바꿔가며 물체를 바라보는 것이라 할 수 있다. 때문에 월드 공간에서의 특정 영역을 스크린에 나타내기 위해선 가상 카메라의 위치와 방향을 설정해야 한다.

카메라의 위치와 방향은 EYE. AT. UP 세 개의 파라메터로 정의된다. EYE는 카메라의 위치(position), AT은 카메라가 바라보는 방향, UP은 카메라의 정수리 방향으로 뻗어있는 벡터이다. 이중 UP은 월드 공간의 수직 방향, 즉 월드 공간의 기저 xyz 중 y축과 동일하게 설정된다.
카메라 공간의 기저를 uvn 이라 하자. uvn은 EYE AT UP을 통해 계산되고, 카메라 공간은 {u, v, n, EYE} 행렬로 표기한다.
- n은 AT과 EYE를 잇는 벡터의 정규화 버전이다.
- u는 UP과 n을 cross product 하고, 이를 정규화 시켜서 얻는다
- v는 n과 u의 cross product 이다.
카메라 공간을 정의했으니, 이제 world space -> camera space의 공간 이전에 대해 설명해보겠다.
한 줄로 요약하자면,
월드 -> 카메라 공간 이전은 카메라 좌표계 {u, v, n, EYE}를 월드 좌표계 {x, y, z, O}로 포개놓는 것이다.
(요 개념이 바로 View transform 이다. View transform == Camera transform )



View Matrix
View transform을 수행하는 행렬를 View Matrix라고 하는데 간단하게, 요 뷰 매트릭스를 월드 공간에 있는 좌표에 적용하면 카메라 공간으로 바뀐다! 식의 중간에서 왼쪽 메트릭스는 회전, 오른쪽 메트릭스는 이동을 의미한다 (affine matrix)이다. 과정을 줄글로 설명하면, eye를 월드 공간의 원점과 맞추고, 기저 uvn이 월드공간 기저 e1e2e3와 맞도록 회전시키는 것이다.
오른손 좌표계와 왼손 좌표계
그래픽스 프로그램에 따라 어떤 좌표계를 쓰는지가 다르다.
OpenGL, OpenGLES의 경우 오른손 좌표계, Direct3D는 왼손 좌표계를 사용한다. 때문에 OpenGL 기반 게임을 Direct3D로 포팅하면 좌우가 반전되는 문제가 발생한다!. 이를 해결하기 위한 방법은 그냥 물체와 카메라 파라메터의 z좌표의 부호를 바꿔주는 것이다. 중요한 내용은 아닌데 그냥 책에서 갑자기 이 이야기를 하길래 적어봤다.
투영 변환 (Projection Transform)
이제까지 오브젝트 공간 -> 월드 공간 -> 카메라 공간 으로 의 공간 이전을 정리했다.
이제 마지막으로 투영 변환을 정리하면 끝난다!
먼저 뷰 프러스텀 (view frustum) 에 대해 설명해보겠다.

사진에서 피라미드 모양의 카메라 가시 영역 중 뾰족한 머리 부분을 제외한 나머지 유한한 크기의 영역이 바로 view frustum 이다.
뷰 프러스텀에선 네 가지 중요한 파라메터들이 있다
- fovy - y축 기준의 시야각을 말한다
- aspect - 종횡비이다 (사진 참고)
- n - near의 약자 (z축 기준이다) -> z = -n
- f - far의 약자 (z축 기준이다) -> z = -f
카메라는 음의 z쪽을 바라본다는 것을 항상 주의하자!

뷰 프러스텀 바깥에 놓인 물체 ( 회색 영역 바깥) 는 보이지 않는 것으로 처리된다. 애매하게 영역에 걸친 경우 Clipping 이라는 기법을 써서 polygon mesh를 잘라 일부 영역만 보이게 된다. 이는 레스터라이저에서 수행하는데 나중에 정리할 것이다.
투영 변환이란?

투영 변환은 왼쪽과 같은 뷰 프러스텀을 오른쪽 처럼 생긴 클립 공간(clip space)로 바꾸는 변환을 말한다. 클립 공간은 2X2X2 크기의 정육면체 공간이라 할 수 있다.

투영 변환은 왜 하는 것인가? 그것은 바로 원근법의 구현에 있다. 투영 변환 전 l2의 길이는 l1의 길이보다 길었다. 그러나 투영 변환 이후에는 두 길이가 같아졌다. 이는 가까이 있는 물체를 더 크게 보이게 하고, 멀리 있는 물체를 더 작게 보이게 하는 원근법의 구현이라 할 수 있다.
투영 변환의 행렬식은 다음과 같다.

아까 설명했던 네개의 파라메터로 정의된다. 이것도 외우느라 엄청 힘들었다 ㅜㅜ
우리가 컴퓨터 그래픽스에서 다루는 대부분의 행렬식은 affine transform인 것에 반해 요 친구는 마지막 행이 0001이 아니기 때문에 아핀 변환이라 할 수 없다.

투영 변환은 정점 쉐이더가 수행하는 마지막 변환이다. 우리는 이제까지 오브젝트 공간 -> 월드 공간 -> 카메라 공간 -> 클립 공간 순서로 공간 이전을 했다. 그 과정에서 월드 변환, 뷰 변환, 투영 변환을 물체에 적용했다. 투영 변환까지 마치고 나면 이는 래스터라이저로 넘어가게 되고, 레스터라이저는 우리가 보는 스크린의 크기에 맞게 2x2x2 크기의 정육면체 뷰 볼륨을 확대한다.
그런데 래스터라이저는 모든 물체가 왼손 좌표계를 따른다는 것을 전제로 하고 있다. 그러나 클립 공간은 오른손 좌표계이다. 때문에 오른손 좌표계를 왼손 좌표계로 변환해주는 작업을 한번 해야 하한다. 그 과정에서 정점 z좌표의 부호를 변경하게 된다.
'컴퓨터그래픽스' 카테고리의 다른 글
[컴퓨터 그래픽스] Lighting (0) 2024.02.16 [컴퓨터 그래픽스] Image Texturing (0) 2024.02.16 [컴퓨터 그래픽스] Rasterizer (0) 2024.02.16 [컴퓨터 그래픽스] Spaces and Transforms (0) 2024.02.16 [컴퓨터 그래픽스] Modeling(polygon mesh) (0) 2024.02.16