Clip Space

 

각 vertex shader 실행의 마지막에 OpenGL은 지정된 범위의 좌표를 받아들이고,

이 범위에서 벗어난 모든 좌표는clipped(자르다)된다.

clip된 좌표들은 폐기되고 남은 좌표들은 최종적으로 fragment가 되어 화면에 보이게 된다.

clip space에서 이름을 가져오는 위치이기도 하다.

 

눈에 보이는 모든 좌표들이 -1.0와 1.0 범위 안으로 지정하는 것은 직관적이지 않기 때문에

우리만의 좌표를 지정하고 작업을 수행한 후 그들을 다시 OpenGL이 원하는 NDC로 변환한다.

 

vertex 좌표를 view에서 clip-space로 변환하기 위해

우리는 좌표의 범위를 지정(예를들어 각 축에 대해 -1000에서 1000까지)하는 project matrix라고 불리는 것을 정의한다. 그런 다음 projection 행렬은 이 지정된 범위에 잇는 좌표들을 NDC(-1.0, 1.0)로 변환한다.

지정된 범위 밖에 있는 좌표들은 -1.0 ~ 1.0에 매핑되지 않으므로 clip된다.

projection 행렬에서 지정한 이 범위를 사용한다면 좌표 (1250, 500, 750)은 보이지 않게된다.

 x 좌표가 범위밖에 있어 NDC에서 1.0보다 높아지므로 clip되기 때문이다.

 

projection 행렬이 생성하는 viewing box는 절두체(frustum)라고 불리고

이 절두체 내부에 있는 각 좌표들은 유저의 화면에 나타나게된다.

지정된 범위에서 NDC(2D view-space 좌표로 쉽게 매핑가능함)로 변환하는 전체적인 과정은

projection(투영)이라고도 불린다.

 

projection 행렬이 3D 좌표를 2D에 매핑하기 쉬운 NDC로 투영하기 때문이다.

모든 vertex들이 clip space로 변환되었다면 perspective division이라고 불리는 마지막 작업이 수행된다.

여기에서 위치 벡터의 x, y, z 요소들을 벡터의 w 요소로 나누어진다.

perspective division은 4D clip space 좌표를 3D NDC로 변환하는 것이다.

이 단계는 vertex shader의 실행 마지막에 자동으로 수행된다.

 

이 단계 이후에는 결과 좌표들을 screen 좌표에 매핑하고 fragment로 변환하는 것이다.

projection 행렬은 view 좌표를 clip 좌표로 변환하기 위해 두개의 다른 형식을 받는다.

각 형식은 자신만의 고유한 절도체를 가진다.

우리는 정사영(orthographic) projection 행렬과 원근(perspective) projection 행렬 중에서 하나를 생성할 수 있게된다.

오브젝트는 로컬스페이스에 정의되어 진다.

로컬 스페이스에 정의되어진 오브젝트 월드변환에 의해 월드스페이스로 이동한다.

 

월드스페이스에는 렌더링할 대상의 물체들과 카메라, 광원등이 배치되고,

뷰행렬에 의해 뷰스페이스로 버텍스들이 변환되어 이동한다. 

 

뷰스페이스로의 변환을 다시 한 번 보자면, 카메라가 원점으로 이동하고

이동을 한 만큼 모든 물체도 같은 방향과 크기만큼 이동하게 된다.

 

그 다음, 카메라를 원점으로 이동시키는 이동변환,

카메라의 각 방향벡터를 새로운 축으로 하도록 회전변환이 이루어 진다.

 

카메라변환 다음으로, 투영변환이 이루어 진다.

 

위의 그림에서 왼쪽은 카메라좌표계의 xz 평면이고, 이 상태에서 투영변환된 것이 오른쪽의 xz 평면이다.

왼족그림에서 원점에 카메라가 있고, 카메라가 비출 수 있는 만큼의 공간의 공간이 빨간선이 둘러진 부분이고,

그림에서는 near 에서 far 까지의 공간이 카메라에 비춰진다.

또한 near는 좁고, far 부분은 넓은데, 그 이유는 원근을 나타내기 위함이다.

 

왼쪽 그림에서 빨간선으로 둘러진 부분을 절두체 공간이라고 한다.

투영변환은 이 절두체 공간을 오른쪽 그림과 같은 공간으로 변환하는 것을 말한다.

 

Direct3D에서는 변환과정을 하나의 4*4 행렬로 나타내는데, 투영변환 행렬은 아래와 같다.

 

n : 카메라에서 가장 가까운 절두체 면까지의 거리

f : 카메라에서 가장 먼 절두체 면까지의 거리

Width : 카메라에서 가장 가까운 절두체 면의 너비

Height : 카메라에서 가장 가까운 절두체 면의 높이

 

이제 구체적으로 위와같은 투영변환행렬의 유도과정을 살펴보겠다.

 

투영변환행렬에 의해 뷰스페이스의 점 P(x, y, z)를 (-1, -1, 0) ~ (1, 1, 1)로 표현되는

공간상의 점 Q(x, y, z)로 변환한다고 하고,

점 P의 x가 점Q의 X로 변환되는 과정을 살펴보겠다.

 

절두체공간의 xz 평면위에 정점P가 위의 그림처럼 위치한다고 할 때,

점 P를 near 상에 사영시키면, 사영된 점 T의 x좌표가 투영변환된 점 Q의 X이다.

 

사영된 점 T의 X 좌표는 닮음비를 이용해서 구해보겠다. 계산과정은 아래와 같다.

투영변환에 의해 정점이 이동되는 공간은 ( -1, -1, 0 ) ~ ( 1, 1, 1 )의 공간이므로,

[-1, 1]로 범위를 조정하는 계산을 추가로 해주겠다. 과정은 아래와 같다.

정리하자면, X는 아래와 같다.

위의 수식중, 중간의 식이 최종변환된 X의 수식이고,

마지막의 식이 나중에 행렬을 구할 때 계산편의상 X에 z를 곱해놓은 식이다.

마찬가지로 y에서 Y로의 변환은 아래와 같다.

마지막으로 z에서 Z로의 변환을 살펴보겠다.

z의 변환의 경우 x, y의 변환과는 계산과정이 다르지만 어렵지 않다.

위와 같은 형식으로 Z를 표기할 때

z가 n 일 경우 변환된 Z는 0 이고,

z가 f 일 경우 변환된 Z는 1이 된다.

따라서, A와 B를 구하여 대입하면

위와 같은 결과를 얻을 수 있다.

 

정리하자면

이제, (x, y, z, 1) 이 (zX, zY, zZ, z) 로 변환되도록 행렬을 구성하면 된다.
(X, Y, Z, 1) 를 (zX, zY, zZ, z) 로 편의상 바꿔놨다고 생각하면 될 것 같다.

이 때, right = - left 이고, top = - bottom 이므로, 행렬의 (3, 1)성분과 (3, 2)성분이 0 이 된다.
또, right-left = Width,  top - bottom = Height 로 정의하면, 최종 투영변환행렬이 아래와 같이 얻어지게 된다.

1. 점 a, b, c 들의 좌표로 선분 ab, bc, ca 구하기

 

삼각형이므로 우선 3개의 점과 각 점을 잇는 3개의 선분이 있다. 여기서 주목할 것은 3개의 선분이다.

이 선분을 이용해 점 p가 안에 있는지 바깥에 있는지를 확인하게 된다.

 

각 점들은 2차원 평면의 좌표로 (x, y)로 구성된다. 각각 (ax, ay), (bx, by), (cx, cy) 라고 하자.

선분 ab는 (ax, ay) - (bx, by)라는 형태로 표현할 수 있다.

 

이제 선분 ab, bc, ca의 길이를 구해보겠다.

두 선분이 직각인 삼각형의 기울어진 선분의 길이를 구하면 된다.

(ax, ay) - (bx, by)의 선분을 아래의 그림과 같다고 보면,

 

? = √( |ay-by|^2  +|ax-bx|^2 )

? = sqrt(abs( ay - by )^2 + abs(ax - bx)^2)

 

선분 ab의 길이를 구하는 것은 간단하게 된다.

 

임의의 선분 A와 B를 가정하고 아래와 같이 생각해보겠다.

 

선분 aA와 선분 bB의 교점 c를 구한다.

단순히 삼각형을 구성하는 선분들 간의 교점이라면 이미 삼각형의 꼭지점들은 a, b, c가 그 교점들이지만,

이것은 점 p에 대해서 하기 위한 것이다.

즉 점 p로 부터 가상의 선을 그어 그 선이 삼각형을 구성하는 선분과 교차하는지 확인하기 위해 사용된다.

 

첫 번째로 선분 aA와 bB에 대해 기울기와 y 절편을 구한다.

 

기울기 = (y1 - y2) / (x2 - x1)

y 절편 = 기울기 * x1 + y1

 

위의 식으로 각각 기울기와 y 절편을 구한다.

 

s = 기울기

y = y절편 

 

기울기 : sa = (ay - Ay) / (Ax - ax)

y절편  : ya = sa * ax + ay

 

기울기 : sb = (by - By) / (Bx - bx)

y절편  : yb = sb * bx + by

 

두 번째로 구한 기울기와 y 절편으로 점 c의 좌표를 구한다.

 

cx = -( yb - ya) / ( sa - sb )

cy = yb + sb * -cx

 

이렇게 구한 교점은, 선분 a와 b를 무한히 연장한 직선으로 가정하고 교점을 구하게 된다.

 

이제 점 p가 삼각형내에 있는지 아닌지를 확인 해보겠다.

 

그림에서 빨간 점이 폐곡선 안에 있을 때와 바깥에 있을 때의 교점에 차이가 나는 것을 확인할 수 있다.

그 것은 한쪽 방향으로 그어진 p의 가상 직선은 안에 있을 때는 홀수개의 교점을 갖고,

바깥에 있을 때는 짝수개의 교점을 갖는다는 것이다.

컬링이란?

렌더링 최적화의 금언

- 폴리곤을 가장 빠르게 그리는 방법은 아예 그리지 않는 것이다.

- 모든 렌더링 최적화의 기본은 어떻게하면 폴리곤을 좀 더 적게 그릴 수 있을까 하는 것이다.

- 컬링이란 최종 씬에 보이지 않는 불필요한 폴리곤을 잘라내어 렌더링하지 않는 기법이다.

1. BackFace Culling : 후면 폴리곤 제거

(카메라에서 보이지 않는 뒷면의 폴리곤을 제거하는 기법)

 

- CPU에서 계산하는 소프트웨어적 처리 방법과 GPU에서 계산하는 하드웨어적 처리 방법이 있다.

- GPU가 발전한 지금은 걍 하드웨어에 맡기면 된다.

- 최종적으로 레스터라이즈된 삼각형의 정점이 시계 반대방향순서면 컬링된다.

- 시계방향으로 컬링하여 앞면 컬링을 할 수도 있다.

- 렌더 스테이트 설정으로 간단히 설정 가능

- 하드웨어 컬링은 파이프라인을 다 통과한 후 레스터라이즈 된 후 컬링된다.

- CPU에서 소프트웨어적으로 처리도 가능하다. 지금날의 GPU에서는 하드웨어에 맡기는 것으로도 충분하다.

 

폴리곤을 그리면 2개의 면을 가지게 되는데 거의 대부분의 상황에서 전면이 후면을 가리고 있다.

 

일반적으로 앞면과 뒷면에 대한 판단은 폴리곤을 그리는 순서에 따라서 결정되는데 기본적으로 DirectX는

뷰 스페이스에서 아래와 같이 시계방향이냐 시계반대방향이냐를 기준으로 앞면과 뒷면으로 판단한다.

 

+ Recent posts