본문 바로가기

컴퓨터 그래픽스

컴퓨터 그래픽스 기초 - Rasterizer ([KUOCW] 한정현 교수님 강의)

이 포스팅은 [KUOCW] 한정현 교수님 강의 7장- 레스터라이저를 듣고 정리한 내용입니다.

선형대수학의 기초적인 지식이 요구됩니다.

Rendering Pipeline

지난 강의에서는 위의 Rendering Pipeline에 vertex shader의 연산으로 clip space까지 되는 과정을 설명했습니다.

이번 포스팅은 이 clip space가 Rasterizer로 가서 무슨 연산이 일어나는지 알아보겠습니다.

이 부분은 하드웨어로 고정된 연산이 이루어지는 부분으로 따로 프로그래밍이 불가능한 부분이라 개념을 알고 넘어가면 될거 같습니다.


 

  • Perspective Division

이전 포스팅에서는 vertex shader에서 아래 그림과 같이 Projection transform matrix(M_proj)을 통해 clip space로 가는 과정을 설명했습니다. 하지만 이전 포스팅에서 마지막 행이 (0,0,-1,0)인 이유를 Right-hand System(RHS)에서 Left-hand System(LHS)로 바꾸기 위함이라고 하고 넘어갔는데요. 한 가지 더 알아야 할 것이 있습니다.

Perspective Division: 오른쪽 아래 화살표에서의 연산, -z를 1로 만들어준다.

마지막 행이 (0,0,-1,0)이기 때문에 각 vertex의 마지막 성분은 위와 같이 -z 값이 나오게 되는데, 이를 1로 나타내주기 위해 -z로 모든 성분을 나누는 과정으로 Perspective Division이라고 합니다. 이 과정은 Rasterizer에서 수행됩니다. 이 과정을 통해 얻는 것은 바로 원근입니다.

위의 그림에서는 clip space에서의 빨간 두 선 l1과 l2rk Projection transform이 되고 Perspective Division(빨간 동그라미)이 되는 과정을 나타냈습니다. 위 그림에서 최종 결과를 나타내는 l'1과 l'2는 clip space에서 그 길이가 같지만 연산 후에는 그 길이가 다름을 알 수 있습니다. camera로부터 멀리 있던 선분이 더 짧아진 것이죠. 이처럼 Perspective Division은 상대적으로 멀리 있는 성분을 더 작게, 상대적으로 가까이 있는 선분을 크게 만드는 원근의 효과를 가지게 되는 것이죠. 이 결과로 얻은 좌표를 NDC(Normalized Device Coordinates)라고 부릅니다.


 

  • Back-face Culling

다음으로는 Back-face Culling입니다. 말 그대로 "뒷 면은 없앤다"라는 것인데요 camera에서 보기에 3D object의 뒷면에 해당하는 부분 어차피 보이지 않습니다. clip space를 만드는 view transform을 통해 View Frustum 밖의 object를 Culling 했듯, 보이지 않는 object의 뒷 면도 Culling 하자는 것이죠.

 

그렇다면 어떻게 컴퓨터가 object의 뒷면과 앞면을 구분하느냐? 답은 normal vector를 정의한 부분에서 알 수 있습니다. 앞서 컴퓨터 그래픽스에서는 이 Normal Vector의 방향이 object의 바깥쪽을 향하는 것이 원칙임을 알았습니다. 따라서 vertex의 순서가 시계 반대 방향(CCW)으로 고정되어 있었죠. 

Normal Vector의 방향을 알아내는 수식

여기서 vertex의 순서가 시계 반대 방향(CCW)인 것은 object의 정면에서 물체를 바라봤을 때입니다. 따라서 180도 뒤집어진 꼴인 object의 뒷면에 해당하는 normal vector를 가지고 있는 vertex(혹은 polygon)은 뒷면이라는 것을 알 수 있죠.

이를 수학적으로 정의하면 위의 각 vertex 간의 뺼샘으로 정의한 행렬의 determinant 값으로 나타낼 수 있습니다. 이 값이 음수면 뒷면이고, 양수면 정면, 그리고 0이면 옆면에 해당합니다.


 

  • Viewport

다음으로는 Viewport에 관한 설명입니다. Viewport는 쉽게 말해서 이제 모니터 속 공간(이지만 아직 3D)을 나타내는 공간이라고 생각하시면 됩니다. clip space는 보이는 물체를 솎아내고 Perspective Division를 통해 그에 맞는 원근을 표현했지만 이는 camera가 보는 시점에서의 기준입니다. 이제 우리는 모니터의 비율에 맞게 공간에 clip space의 정보들을 맵핑한다고 보시면 됩니다. Viewport를 정의하는 변수로는 w, h, minX, minY, minZ, maxZ가 있습니다. 아래 그림을 보면 쉽게 이해하실 수 있습니다.

Viewport

Clip space(NDC)를 Viewport로 옮기는 변환을 Viewport Transform라고 합니다. 이 변환은 affine transform에 해당되며, 아래 그림과 같이 scaling과 translation을 합친 형태의 Viewport Transform matrix를 통해 연산이 이루어 지죠. 여기서 특징은 Viewport에서는 (0,0)에 해당하는 지점이 좌 하단이 아니라 각 x, y, z축의 중심이라는 점을 유의해서 보시면 아래 수식이 이해가 될 것입니다. 또한 LHS임을 확인하실 수 있습니다. 이때 만들어진 Viewport의 정수 좌표들이 모니터의 픽셀 하나에 해당하는 값이 되는 거 같습니다.  

 

Clip space(NDC)에서 Viewport로의 변환


 

  • Scan Conversion - Color

마지막으로 Scan Conversion입니다. Scan Conversion 과정은 vertex(정점)로만 이루어졌던 공간을 화면에 나타낼 수 있게 그 사이에 픽셀들을 만드는 과정이라고 보시면 될 거 같습니다. 이 픽셀을 만드는 과정은 선형 보관법(interpolation)을 통해 이루어집니다. 간단하게 선형 보관법을 설명하자면 두 점의 중간 좌표의 값을 구할 때 거리에 따른 weighted sum을 통해 그 중간의 값을 결정한다고 이해하시면 됩니다.

여기서 z좌표가 없다고 생각하고(object가 하나뿐) RGB 색상 채널 중 R채널 기준으로 설명하겠습니다. 여기서 추측컨데, Viewport의 Z좌표는 object 간 앞뒤를 구분하기 위함 일거 같습니다. + 텍스처 맵핑시 원근을 포함합니다.

 

우선, 아래의 그림같이 v1(x1, y1)과 v3(x3, y3) 두 점을 기준으로 생각했을 때, Δy와ΔR를 구하고 그 비율 ΔR/Δy를 통해 y축으로 한 픽셀 올라갔을 때의 R값의 변화를 알아냅니다(중간). 또한 v1과 v2 각각 정수로 표현된 polygon 내 가장 가까운 좌표까지의 x좌표를 구하고 그 x좌표까지의 변화 Δx에 따른 y좌표의 변화 Δy인 Δx/Δy 통해 polygon내 가장 가까운 좌표가 어떤 R값을 가질지 결정합니다(오른쪽 위).

Scan Conversion에서 x와 y의 변화율을 통해 한 픽셀 증가할 때 마다의 RGB값의 증가/감소율을 계산한다.

지금까지 v1과 v3를 따르는 수평선 상의 값들을 아래의 왼쪽 사진과 같이 구했습니다. 이와 같은 방식으로 v1과 v2 그리고 v2와 v3사이의 값들을 구할 수 있습니다. 이렇게 픽셀이 있는 수평 선상을 scan line이라고 합니다. 그렇게 되면 아래 그림의 오른쪽 같이 mesh에 한 scan line 양쪽 끝에 해당하는 값들을 모두 알게 되었습니다. 그렇다면 또다시 interpolation을 통해 그 중간 픽셀들을 채울 수 있죠. 아래 그림에는 그 연산이 나타나 있습니다. 이렇게 두 번 linear interpolation을 수행했다 해서, 이 과정을 Bilinear interpolation이라고 합니다. 

이렇게 구해진 비율을 각 scan line에서 또 interpolation을 수행한다.

이 Bilinear interpolation과정을 RGB 채널에 적용하여 얻어진 결과는 아래 그림의 예시들과 같습니다. 

color interpolation 예시

 

  • Scan Conversion - Normal vector

또한 vertex 정보에는 위치인 좌표 정보, color인 texture 정보뿐만 아니라, normal vector도 있는데, 이 normal vector 또한 위와 같은 방식으로 Bilinear interpolation이 되어 중간의 값들로 표현됩니다. RGB 값이 3차원 normal vector를 나타내는 (n_x, n_y, n_z)로 바꿔서 적용됐다고 생각하면 이해가 되죠. 아래 그림처럼 각 vertex normal이 scan line을 따라 edge에 먼저 interpolation이 되고 각 scan line별로 양 끝 값에 의거하여 interpolation을 통해 중간의 normal vector 값을 도출해 낼 것입니다.


여기까지 Rasterizer가 수행하는 연산에 대해 알아보았습니다.

다음에는 Rasterizer를 통해 등장한 각 픽셀에 대한 연산을 수행하는 fragment shader를 알아보겠습니다.

감사합니다.

 

References

강의: [KUOCW] 한정현 교수님 강의

https://www.youtube.com/channel/UCfyXTCv0QlZxG1S1rteGI7A

강의 자료: 한정현 교수님 연구실 홈페이지
http://media.korea.ac.kr/books/