김서버의 프론트엔드 일기
컴퓨터 그래픽스 5 - 래스터라이저 본문
정점쉐이더 -> 래스터라이저 -> 프레그먼트 쉐이더 -> 출력 병합기 -> 출력
gpu 렌더링 파이프라인에서 정점처리를 마무리 되고 나면, 그 다음 래스터라이저 단계를 진행된다. 래스터라이저는 프로그래머가 코딩을 하는 부분이 없고, GPU에서 알아서 처리하기 때문에 프로그래머가 신경을 써줄만한 요소는 잘 없다.
하지만 정점쉐이더(vertex shader) 프로그래밍 이후에 어떻게 처리가 되어, 우리가 코딩해야하는 프레그먼트 쉐이더(fragment shader)까지 도달하는지 알아볼 필요는 있다.
래스터라이저 개요
정점쉐이더가 출력한 정점들은 프리미티브라는 개체로 다시 조립이 된다. 이 프리미티브는 스크린에 그려질 형태로 변환된 후 프래그먼트로 분해되는데 이를 래스터화라고 부른다. 프래그먼트는 컬러 버퍼의 픽셀을 갱신하는 데 필요한 데이터를 말하고, 정점들에 저장된 노멀과 텍스쳐 좌표등은 프리미티브를 따라 보간되어 각 프래그먼트에 할당 된다.
결국 프리미티브를 조립하고 래스터화를 하게 되는데, 하드웨어가 알아서 하게 된다. 이 때, 클리핑, 원근 나눗셈, 뒷면 제거, 뷰포트 전환, 스캔 전환의 작업을 수행한다.
클리핑
클리핑은 정점처리가 완료 되면 2x2x2 크기의 클립 공간이 만들어지게 된다. 이러한 공간에서 삼각형들의 좌표는 클립공간 안에 있을 수도있고, 일부만 들어있을 수도 있고, 아예 바깥에 있을 수도 있다.
이렇게 배치되어있는 삼각형들 중에서 클립공간에 따라서 삼각형들을 자르거나 이후 연산에서 없애버리는 등으로 최적화 하는 것을 클리핑이라고 한다.
원근 나눗셈
m11 | 0 | 0 | 0 | X | x | = | m11x |
0 | m22 | 0 | 0 | y | m22y | ||
0 | 0 | m33 | m34 | z | m33z + m34 | ||
0 | 0 | -1 | 0 | 1 | -z |
Mproj 의 첫 3개 행 중에서 0이 아닌 원소들을 m11, m22, m33, m34로 가정했다. Mproj 와 3차원 벡터를 4차원으로 한 (x,y,z,1)의 벡터 곱은 위 결과와 같이 나오게 된다. 하지만 마지막 w좌표는 1이 나와야 하지만, 아핀변환과 달리 Mproj의 마지막 행은 (0,0,0,1)이 아니라 (0,0,-1,0)이다. 따라서 Mproj 에 의해 변환된 정점의 w좌표는 -z가 된다. 실제로 마지막 좌표 숫자는 3차원 벡터를 4차원으로 할 때, 더미는 1로 채워야 하기 때문에, 위와 같은 마지막이 -z가 될 수는 없다.
그렇기 때문에 유효한 벡터로 만들기 위해서는 모든 벡터에 -z만큼을 나누어야 한다.
m11x | * -(1/z) | -m11x / z |
m22y | -m22y / z | |
m33z + m34 | (-m33 - m34) / z | |
-z | 1 |
이렇게 원근 나눗셈 결과로 얻은 카테시안 좌표를 정규화된 장치 좌표 혹은 NDC라고 부른다. 정규화라는 이름을 붙인 이유는 이 좌표의 x,y,z 범위가 모두 [-1, 1]이기 때문이다.
뒷면 제거
가상 카메라를 등지고 있는 삼각형은 뒷면이라고 부른다. 이런 부분들은 카메라에 보이지 않기 때문에 불필요한 데이터이니 제거 되는 것이 좋다.
뒷면을 제거하기 위한 원리는 다음과 같다. 삼각형 A라는 것의 노멀 혹은 수직벡터 n이고 카메라와 삼각형의 정점을 연결하는 벡터를 c라고 했을 때, n과 c의 내적을 계산하면, n과 c의 결과에 따라서 뒷면을 판단할 수 있다.
- n * c > 0 앞면
- n * c === 0 변만보이는 삼각형
- n * c < 0 뒷면
실제로 구현이 되는 것은 투영 변환 이후에 나타나는 삼각형 좌표 조합을 보고 판단하게 된다.
만약 투영한 삼각형의 좌표가 시계방향으로 정렬이 되어 있을 경우, 오른손 좌표계를 생각해보면 뒤집혀져있는 것으로 알 수가 있다. 그러므로 뒷면이라고 판명이 나고 반시계 방향일 경우 앞면으로 판정할 수가 있다.
많은 그래픽스 프로그래밍에서는 자르는 삼각형을 시계, 반시계로 설정할 수가 있다. 왜냐하면 일반적으로 앞면을 보고 싶을 수 있지만, 반대로 내부구조를 보거나 할 때에는, 앞을 잘라서 보아야 하기 때문이다.
뷰포트 변환
컴퓨터 스크린 위의 윈도우는 자신의 좌표계를 가지는데, 이를 윈도우 공간 혹은 스크린 공간이라 부른다.
뷰포트는 모니터의 왼쪽 하단 부터 가로와 세로사이즈를 받아서 뷰포트를 그리고 그 안에 NDC로 변환된 좌표계를 집어 넣어서 모니터에 그릴 준비를 하게 된다.
이 때, w / h는 종횡비라고 하는데 이는 뷰 프러스텀 파라미터 aspect와 동일하게 설정하는 게 좋다.
쉽게 말하면 롤이나 브라우저 같은 프로그램을 켰을 때, 그 프로그램의 크기로 생각하면 된다.
하지만 뷰포트에는 w,h 뿐만 아니라 z축이 있고 z축은 스크린 안쪽을 향하게 한다. 이런 이유는 색의 opacity로 생기는 색의 합성, 그리고 삼각형이 겹친 부분을 보여주어야 하는 것 등을 계산하기 위해서 필요하게 된다.
w/2 | 0 | 0 | minX + (w/2) |
0 | h/2 | 0 | minY + (h/2) |
0 | 0 | (maxZ - minZ) / 2 | (maxZ + minZ) / 2 |
0 | 0 | 0 | 1 |
축소확대와 이동의 결합한 삼각형의 점 좌표 (x,y,z,1)과 행렬 곱셈을 해야하는 행렬식이다.
위식까지 곱셈을 하게 되면 필요한 삼각형들을 스크린 공간으로 옮겨지게 된다.
스캔 전환
이제 공간을 잡았으면 마지막으로 삼각형을 색칠하는 스캔 전환이 수행된다. 이 단계에서는 삼각형 내부를 채우는 프래그먼트를 생성한다. 구체적으로 말하면 삼각형이 차지하는 스크린 공간의 픽셀 위치를 결정하고, 삼각형의 정점별애트리뷰트를 보간하여 각 픽셀 위치에 할당하게 된다.
스캔 전환은 실시간 그래픽스의 핵심 사항이고, 이를 정확히 이해해야 GPU 파이프라인의 다음 단계인 프래그먼트 쉐이더를 작성할 수 있다.
삼각형의 꼭지점끼리의 선은 우선적으로 변을 따라 RGB값을 선형보간 된다.
각 꼭지점이 RGB 컬러가 있다고 했을 때, 꼭지점을 잇는 선분들의 RGB값을 보간하면서 삼각형의 픽셀들을 채워 나가면서 색의 변환을 자연스럽게 만들어 주게 되는 것이다. 그리고 이 선분의 색상을 그리는 것은 스캔라인을 따라서 값을 할당 해주면 선을 모니터에 출력할 수 있게 된다.
스캔라인은 모니터를 생각했을 때, 모니터는 사각형이고, 출력하는 것은 원 모양의 전구가 반짝 거리는 것이다. 그리고 전구를 가지런하게 정렬이 되어있다. 전구 가지런히 배치되어있는 배열의 선으로 쭈욱 긋는 가이드 라인을 스캔라인이라고 부른다.
이제 우리는 삼각형 두 꼭지점의 선분에 따라서 색상을 그렸다. 하지만 삼각형의 내부도 채워야한다. 그러기 위해서는 먼저 그린 변을 기준으로 일직선으로 다른 변을 만날 때 까지 다시 선형보간으로 RGB값을 각각 정해주면 된다.
이렇게 선형보간을 두 꼭지점을 긋는 변에서 한 번, 그리고 변과 스캔라인이 만나는 점부터 시작해서 수평으로 맞은편 꼭지점 까지 다시 한 번. 총 두 번의 선형보간을 하기 때문에 이를 겹선형보간이라고 부른다.
그럼 이제 위에서 겹선형보간을 통해서 삼각형 내부의 스캔라인까지 모두 RGB 값이 계산이 완료 되면, 모니터 전구에 RGB값을 던져주며 반짝반짝 빛나면서 우리 화면에 보이게 되도록 준비를 하면, 이제 프래그먼트 쉐이더 단계로 넘기게 된다.
래스터라이저의 단계는 사실 GPU가 알아서 계산해주는 부분이라 프로그래머가 크게 신경쓰지 않아도 되는 부분이긴 하다. 대부분 GPU를 만드는 회사에서 고민을 해서 그 위에서 개발을 하는 것이 일반적이다.
개인적으로는 이 래스터라이저단계를 공부하면서 브라우저의 z-index나 opacity 등의 동작이 어떻게 이뤄지고 있는지 조금이나마 다가가며 이해를 할 수 있는 단계의 공부가 되었다.
'공부하는거 > 컴퓨터 그래픽스' 카테고리의 다른 글
컴퓨터그래픽스 - 4 정점처리 (0) | 2022.09.09 |
---|---|
컴퓨터그래픽스 - 3 (좌표계의 변환) (0) | 2022.09.06 |
컴퓨터 그래픽스 - 2(모델링) (0) | 2022.08.31 |
컴퓨터 그래픽스 - 1 (수학 기초) (0) | 2022.08.24 |