Chapter 3 : 래스터화

코승호딩·2022년 10월 22일
0

게임수학

목록 보기
3/3
post-thumbnail

파이프 라인 단계에서 픽셀 셰이더 바로 전 단계가 래스터라이저 단계이다.
정점 셰이더에 의해 처리된 정점들은 프르미티브로 묶여 고정 렌더링 파이프라인으로 들어간다.
각 프리미티브는 화면상에 2D 삼각형 정점 좌표가 결정되고 삼각형에 포함되는 픽셀마다 프레그먼트가 생성된다.

래스터화는 다음 단계로 구성된다.

  • 원근 나눗셈
  • 클리핑
  • 뒷면 제거
  • 뷰포트 변환
  • 스캔 변환

투영 변환을 통해 얻은 좌표에 원근 나눗셈을 하고 모든 정점들의 정보는 NDC로 바뀐다. 즉, 절두체에 보이는 점들은 x, y가 -1~1, z가 -1~0 또는 0~1로 표현된다. z축을 없애면 2D 좌표를 얻게 된다. 그 다음 클리핑을 할 수 있는데, x, y가 1보다 크거나 -1보다 작을때, z범위에 벗어날 때, 절두체를 벗어난 범위이므로 그리는 대상에서 제거를 한다. 2D좌표로 바뀌어져 있는 폴리곤에 대해 그 면이 카메라를 향하고 있는지 반대 방향을 향하는지 처리를 하는 것이 뒷면 제거이다. 그리고 화면에 있는 사각형 영역 즉 절두체에 보이는 점들을 뷰포트 영역 내부로 옮기기 위해서는 뷰포트 변환을 해야한다. 이를 통해 얻어지는 점들로 내부에 있는 픽셀을 찾는 것이 스캔 변환이다. 그리고 이 픽셀 하나하나들을 픽셀 셰이더로 넘겨 색상을 결정하는 것이 바로 Rasterization이다.


📌클리핑(Clipping)


폴리곤을 구성하는 점들의 집합이 절두체에 포함되지 않으면 제거하고 절두체에 포함되는 점들에 대해서만 처리를 하는 것이 클리핑이다.
다음 그림에서 t1은 완전히 제거하고 t2는 완전히 처리한다. t3의 경우 절두체에 바깥 부분만 잘라낸다.
-> 이 결과 정점의 일부가 제거되고 새로운 정점이 추가된다.


📌원근 나눗셈(Perspective Division)

다음과 같이 원근 나눗셈을 통해 NDC를 얻을 수 있다.
위 그림의 MprojP2 = (0, 1, -2)에 원근 투영 변환을 적용하면 (0, 1, 2, 2)라는 좌표를 얻을 수 있다. 여기서 w에 해당하는 2를 각각에 나눠 (0, 1/2, 1, 1)로 만드는 것이 바로 원근 투영이다. 이렇게 하면 비로소 원근 나눗셈을 통해 좌표를 1~-1 사이로 놓을 수 있고 결국 NDC를 얻게 된다.
따라서 클리핑이라는 것을 NDC에서 아주 스무스하게 편리하게 할 수 있다.


📌은면 제거(Back-face Culling)


다음 그림에서 n1은 카메라의 방향을 바라보지 않고 반대를 바라보기 때문에 백 페이스이고 따라서 렌더링하지 않는다. 은면이라고도 한다.
우리는 선형대수시간에 노말이라는 것을 배웠다. 두 벡터의 외적을 통해 법선 벡터를 얻을 수 있고 이 법선 벡터는 폴리곤 속 어느 면하고도 점하고도 수직이 될 것이다.
또한 시계방향일 경우와 반시계방향일 경우 벡터가 서로 반대 방향을 향하며 우리는 각각의 모델의 법선 벡터가 외부를 향해야 카메라 벡터에 맞아 렌더링 할 수 있다.
벡터의 노말을 통해 외적을 얻을 수 있고 이 노멀벡터와 카메라가 이루는 벡터의 내적이 0 또는 예각이면 카메라를 향하고 있으며 둔각일 시 카메라를 바라보고 있지 않으므로 이를 통해 은면을 판단할 수 있다.
요약하여 각 정점들의 나열 순서를 가지고 면의 법선 벡터를 구하고, 이 법선 벡터와 카메라 시선 벡터의 내적의 결과로 은면인지 전면인지 판단할 수 있다.
와인딩 오더에 따라 전면인지 은면인지 바뀐다.
오른손 좌표계에서는 반시계 방향이 바깥쪽을 향하는 노멀 벡터이므로 반시계 방향으로 와인딩 오더를 구성해야 한다.

은면 제거는 비용이 많이 든다.
그러나 클립 공간으로 바꾸면 벡 페이스를 비교적 쉽게 계산할 수 있기 때문에 레스터화 단계에서 은면 제거를 하는 것이다.

시계방향 - 뒷면, 반시계방향 - 앞면
행렬식 계산을 통해 앞면인지 뒷면인지 알 수 있는데, 행렬식이 양수이면 반시계방향, 행렬식이 음수이면 시계방향이다. 0이면 변만 보인다.

오픈지엘과 다렉은 서로 시계방향과 반시계방향이 다르다.


좌표계


3ds MAX와 같은 모델링 툴에서는 Z축이 업벡터이다. 따라서 오픈지엘로 가져오면 y축이 업벡터인 오픈지엘에서는 넘어져 보인다.
따라서 Max에서 물체를 익스포트 할때 물체를 고정한 채,yz축을 x축을 중심으로 90도 회전 시키면 된다.


그러면 이제 Max에서 다렉으로 넘어가보자.
yz축 대칭 이동은 이미 수행완료라 가정하자.
Max는 오른손, 다렉은 왼손 좌표계이다.
따라서 그대로 모델을 다렉에 가져다 놓으면 물체는 z의 부호가 바뀐 채로 임포트 된다.
바로 xy평면에 미러링 되는 것이다.
이 문제는 간단하게 물체를 내보낼 때 xy평면으로 반사하면 끝이다.
xy평면 반사는 z의 부호만 바꿔주면 끝이다.
정확한 설명으로 그림을 제시한다.

우선 x축을 중심으로 90도 회전해야 하기 때문에 z와 y의 좌표가 서로 바뀐다.
다음으로 오른손 좌표계를 왼손 좌표계로 변경하므로 xy평면에 미러링 된다.
마지막으로 z좌표만 바꿔주면 깔끔하게 원상복귀 된다.

그러나 사실 합쳐보면

!!!! 이것만 해주면 끝이었다.
y-z 스왑만 해주면 끝나는 문제
그러나 주의해야할 점이 있다.
이 상태에서 렌더링 하면 이미지는 뒷면이 제거 대신에 앞면이 제거된다;;;
-> yz-스왑은 삼각형 정점의 CCW순서를 변경하지 않았기 때문에 2D에서 CCW정렬 삼각형이 앞면이다.
그런데 LHS에서는 CCW를 뒷면으로 가정하여 컬링하기 때문이다.
해결법은 재정열하지 않고 컬링 모드를 CW 정렬 삼각형을 뒷면으로 컬링하도록 하면 된다.


📌뷰포트(Viewport)


스크린에 어떤 영역으로 매핑할 것인지 나타내는 사각형 영역을 뷰포트라 한다.
원근 투영 나눗셈을 하고 나면 z값이 크기가 1인 형태로 노말라이즈가 된다.

뷰포트 변환을 해보자
노말라이즈된 절두체와 뷰포트의 y축은 반대이다. 따라서 y축 반사를 우선 진행한다.
그리고 뷰포트의 너비와 높이의 반만큼을 늘려줘야 한다.
다음으로 MaxZ - MinZ를 통해 z를 구해준다.
마지막으로 이동을 위해 MinX, MinY에 너비와 높이의 절반을 더해준 값을 변환으로 곱해준다.
결국 오른쪽 맨 위와 같은 식이 완성된다.
대부분 MinX와 MinY값이 0인 경우, MaxZ, MinZ가 0 1 인 경우이므로 결국 최종적으로 결과가 나온다.


📌스캔 변환(Scan Conversion)

래스터라이저에서 마지막 단계인 스캔 변환이다.

먼저 삼각형이 차지하는 공간의 픽셀 위치를 결정한다.
다음으로 삼각형 정점별 속성을 보간하여 각 픽셀에 대한 속성을 계산하는 것이다.

위와 같이 삼각형 내부의 컬러를 입히려고 한다.
그런데 삼각형 내부의 프래그먼트에 모든 컬러 값을 저장해두는 것은 비효율 적이다.
따라서 정점 속성의 컬러값으로 선형 보간을 하여 기울기에 따라 자동으로 색상이 정해지도록 하는 것이다.

우선 각 점의 컬러 값을 얻어야 한다. 이미 두 점은 R값을 가지고 있으며 이를 활용하여 선형 보간을 시작하자
우선 맨 위의 점 y값이 1.6에서 오른쪽 아래 점 7.2까지 가는데 컬러인 R이 얼마나 증가하는지 확인해 보자

  • y의 증가량 5.6
  • R의 증가량 56

따라서 R을 y로 나누면 10이 되고, 즉, y의 값이 1 증가할 때 R의 값은 10이 증가한다.
맨 위 점의 y 값은 1.6이다. 그렇다면 y값이 2.0인 해당 점은 어떤 R 값을 가질까?
매우 쉽게 y의 값이 1 증가할 때 R의 값이 10 증가하였으므로 y의 값이 0.4 증가한다면 R의 값은 4증가 하였을 것이다.
따라서 y가 2.0일때 R의 값은 192가 된다.
이제 삼각형 내의 프래그먼트가 생성될 픽셀 즉 스캔 라인에 대한 R값을 위와 같은 방식으로 X의 증가량에 대한 R의 증가량으로 구한다.

다음과 같이 x의 증가량은 6.9 - 3.4 = 3.5이다.
이 때 R의 증가량은 202 - 97 = 105이다.
따라서 105 / 3.5 = 30이고 x가 1 증가할때 R의 값이 30만큼 증가한다.
편한 계산을 위해 x의 값이 4.0일때는 0.6증가하였고 R의 값은 18만큼 증가하였다.
따라서 x의 값이 4일때 R의 값은 97 + 18 = 115이다.
이후 부터 x가 1 증가할 때마다 30씩 늘려주면 된다.

이와 같이 정점을 이용해 프래그먼트를 생성하는 것을 정점의 속성을 이용한 보간(interpolation)이라고 한다.
이 보간은 컬러 뿐 아니라 노멀, 텍스처, 좌표, 깊이 등도 보간이 된다.


📌Top-Left Rule


다음과 같이 두 삼각형이 공유하는 변 위에 픽셀이 존재할 때, 어느 삼각형 픽셀을 소유해야하는지를 결정해야한다.
삼각형 변은 오른쪽, 왼쪽, 위쪽, 아래쪽으로 구분된다.

  • Top-left : 픽셀이 삼각형의 위쪽 혹은 왼쪽 변에 놓이면 픽셀은 그 삼각형의 소유이다.

따라서 p2는 맨 아래 삼각형의 위에 놓여 있으니 t3의 소유이다.
p1은 t1의 왼쪽 변에 놓여 있으므로 t1의 소유이다.


📌원근 보정


위 그림은 fovy = 90, 종횡비 1, 근평면 1, 원평면 2인 절두체를 투영변환 하였을 때의 모습이다.
각각의 점을 투영변환 시 저런 값을 가지게 된다.
그림을 보면 v1~v2 : v2~v3는 1:1이 되어야 한다. 그러나 원근 투영을 하였을 때에는 1:1이 아닌 3:4가 나온다.
바로 원근 투영을 하면 선분의 거리 비율이 왜곡이 된다.
따라서 스캔 변환 보간 시 API에서 원근 보정해야 한다.


📌depth value


Zn을 0으로 Zf를 1로 원근 투영 변환을 생각해보자.
Zn은 당연히 0에 가깝고 Zf는 아주 큰수이다.
이 두 원평면, 근평면을 0과 1 즉 절반이 0.5가 되도록 노말라이즈를 해야한다.
그러나 원근 보정에서 보듯 왜곡이 일어나 거리의 비가 1:1이 되지 못하고,
위 그림의 식에 따라 Zn에서 Zf가 원근 투영 변환이 적용 되었을 때, 증가량이 분수함수로 나타나고 이는 즉, 한쪽에 치우친다.
값만 놓고 보면 Zn과 Zf의 중간에 해당하는 0.5조차 1에 아주 가까워진 값을 갖게 된다.
이렇게 되면 생기는 문제가 있다.
0에 가까운 depth보다 1에 가까운 depth가 훨씬더 많아진다.
따라서 컴퓨터의 실수 표현의 문제로 인해 depth test에 오류가 생긴다.
예를 들어 카메라에서 멀리 떨어져 있지 않은 값들도 depth값을 1의 값으로 가질 수 있다.
굉장히 문제닷..!!
그래서 원근 보정이라는 것이 필요하며 depth라는 것이 1에 급격히 가까워 질 수 있다는 것을 알아야 한다.


📌객체 피킹(Object Picking)


렌더링된 결과 2D 스크린 상에서 객체를 마우스 커서로 선택하는 것을 말한다.
응용 프로그램에서는 2D 픽셀 좌표를 사용해 마우스로 객체를 선택해야 한다.

마우스 픽셀 좌표가 주어지면 시작점과 방향 벡터 0, 0, 1를 갖는 광선을 찾고 이를 이용해 카메라 공간의 점을 찾고 카메라 공간의 점으로부터 월드 좌표계에 있는 오브젝트를 찾고 그 물체를 찾아서 가장 카메라 가까이에 있는 물체를 표현하면 그것이 피킹의 과정!


다음과 같이 스크린 공간에서 방향 벡터(0, 0, 1)을 갖는 광선을 월드/오브젝트 공간으로 변환한 후, 광선과 교차하는 월드 공간의 물체를 찾아낸다.


위 그림과 같이 연장된 선분을 찾는 것이 우리의 목적이다.


카메라 스페이스에서 (Xc, Yc, -n)의 광선의 벡터를 보자
-n은 근평면에 위치해있기 때문에 -n을 나타낸다.
따라서 (Xc, Yc, -n)를 프로젝션, 스크린 변환을 하면 결과적으로 (x, y, 0)이 되어야 한다.
따라서 다음과 같이 변환을 통해 카메라 공간 광선의 방향벡터를 얻을 수 있다.

이렇게 얻은 카메라 공간 광선 방향벡터를 월드 공간 방향 벡터로 변환을 해야한다.
따라서 카메라 변환의 역변환이 필요한데, 회전 행렬의 역행렬은 전치행렬 이므로 방향 벡터에 회전 행렬의 역행렬을 계산해주면
월드 공간 방향벡터로 변환이 완료 된다.


찾은 광선을 통해 확장을 하며 충돌하는 물체를 찾고 그 중 카메라에 가장 가까운 물체를 선택한 것으로 한다.
모든 물체에 대해 교차 검사를 수행하면 굉장히 많은 시간이 걸리 것이다.
따라서 모든 삼각형에 대해 교차 검사를 수행하는 것은 무리무리다.
해결 방법은 물체를 구성하는 메쉬로부터 바운딩 볼륨을 만든다.

  • AABB : 가장 쉽게 생각할 수 있는 것이 AABB의 바운딩 박스이다.
    이는 월드 좌표계와 수직 또는 평행을 이루며 이를 통해 충돌 검사를 한다.
    물체가 회전을 하면 그 크기로부터 매번 바운딩 박스를 새로 만든다.
  • OBB : 물체가 회전을 하면 바운딩 박스도 같이 회전을 하는 바운딩 박스
  • 바운딩 스피어 : 구를 만들어 물체가 회전하더라도 방향성이 없어 항상 같은 모양

이렇게 바운딩 볼륨을 광선이 뚫고 지나갔다면 내부에 있는 물체와 충돌했을 가능성이 있다.
만약 광선이 바운딩 볼륨을 뚫지 않는다면 절대로 물체 내부와 교차할 일이 없다.
따라서 바운딩 볼륨을 써서 충돌 검사를 하는 이점은 충돌되지 않는 오브젝트들을 빠르게 제거할 수 있다는 것이다.

그런데 만약 볼륨을 뚫었는데 실제로 오브젝트를 교차하지 않은 경우가 있다.
잘못된 판단이 생길 수 있기 때문에 1단계로는 바운딩 볼륨과 교차 검사를 하고,
이 교차된 바운딩 볼륨 안에 있는 오브젝트들의 폴리곤과의 교차 검사를 2차적으로 수행한다.
따라서 2단계 교차 검사를 하는 것이 일반적이다.

  • 바운딩 볼륨을 하면 부정확한 교차가 일어날 수 있지만 실제로는 광선하고 충돌이 되지 않은 나머지 오브젝트들은 빠르게 제거할 수 있다는 것이 엄청난 장점이다.

바운딩 볼륨을 생성하기 위해서는 2차원 xy 평면에서 x의 최대 최소, y의 최대 최소를 통해 직사각형을 찾으면 이 직사각형을 둘러 싸는 원을 찾거나 무게중심을 이용하면 외접원을 만들 수 있다.

바운딩 구와 광선 교차검사를 하기 위한 매개 변수 방정식 표현이다.
t가 가장 작은 것이 카메라와 가장 가까운 점이다.

바운딩 구와 광선 교차 검사에서 얻은 작은 t의 범위는 n과 f의 사이이다.


2차 테스트에서 삼각형과 물체와의 교차 검사를 진행해야 한다.

profile
코딩 초보 승호입니다.

0개의 댓글