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

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

 

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

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

 

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

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

 

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

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

 

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

 

위의 그림에서 왼쪽은 카메라좌표계의 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는

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

 

게임 개발에서는 벡터 연산을 자주 사용한다. 이는 벡터로서의 접근이 직관적이며, 방정식이나 복잡한 계산을 피하고

문제를 훨씬 쉽고 간단하며 효율적으로 해결하게 해주기 때문이다. 그래서 물리 엔진을 만들 때

벡터 연산의 적용을 가장 우선적으로 염두해 두는 것이 일반적이다.

속도, 바람, 저항, 충돌, 위치 판단 등 많은 것들이 벡터로 표현된다.

 

벡터 연산에서 가장 기본은 바로 내적과 외적이다.

 

먼저, 벡터의 내적은 아래와 같이 정의한다.

A*B = |A| |B| cosθ

 

즉, A, B 벡터의 내적은 A 벡터와 B 벡터의 크기를 각각 곱한 다음 사이각의cosθ 값을 곱한 스칼라 값이 된다.

벡터와 벡터의 내적의 결과는 벡터가 아닌 스칼라 값이다.

 

1. 두 단위벡터가 평행하면 절대값 1이다.

벡터 두개가 평행하는 경우는 같은 방향으로 향하거나, 반대 방향으로 향하는 것이다.

따라서 cosθ 값이 1혹은 -1이다. 절대값이 취하면 1이 된다.

 

내적을 이용하는 예를 몇가지 들어보면

 

1) 주인공의 방향벡터가 있고, 적이 주인공의 앞에 있는지 뒤에 있는지 판별

나와 적의 거리 차이로 나오는 벡터 A와 나의 Forward 벡터 간에 내적을 하면

각도가 -90 - 90 사이에 있으면 앞에 있는 것이고, 반대는 뒤에 있는 것이다.

따라서 내적시에 cosθ 값이 0보다 크면 앞쪽에, 0보다 작으면 뒤쪽에 있는 것으로 판별이 가능하다.

 

내적에 대해서는 이 정도로 정리하고, 이제 외적에 대해서 알아보도록 하겠다.

 

벡터의 외적의 결과는 내적과 달리 또 다른 벡터이다.

외적은 행렬식으로 계산할 수 있는데, 주로 사용하는 3차원 벡터의 3*3 행렬식의 풀이는 다음과 같다.

 

또한,  AxB 외적 벡터의 방향은 수학에서는 오른손 법칙을 사용한다.

게임은 엔진이 사용하는 좌표계에 따라 다른데, OpenGL에서는 오른손 법칙, Unity는 왼손 법칙에 따르게 되어있다.

두 벡터의 외적의 결과는 역시 벡터이다. 그리고 외적 벡터의 크기는 두 벡터의 크기에 sinθ를 곱한 값과 같다.

 

외적의 특성은 다음 몇가지로 정리된다.


1) A와 B 벡터의 외적, AxB는 A와도 수직(perpendicular)이고, B와도 수직이다.
2) 내적과 달리 교환 법칙이 성립하지 않으며 순서를 바꾸면 반대 방향의 벡터가 나온다.
v x u = -(u x v)
3) 내적과 동일하게 분배 법칙은 성립한다.
u x (v + w) = (u x v) + (u x w)
4) 외적 벡터의 크기는 평행 사변형의 넓이이다. (밑변 * 높이로 구하는 평행 사변형 넓이에서 sinθ 값이 높이)
5) 두 벡터가 평행하면 크기는 0이다. sin0 의 값이 0이기 때문이다.

 

<외적을 실제 개발에서 적용하는 상황>

 

1) 평면의 법선 벡터를 구할 때.

삼각형의 세점을 알고 있다고 하였을 때, 벡터 2개를 구할 수 있게 되고, 그 두 벡터의 외적을 구하면 해당 삼각형이 속한 평면의 법선 벡터를 구해낼 수 있게 된다. 보통 모델링 데이터의 폴리곤 노멀 벡터를 구할 때 많이 사용한다.

 

2) 적이 캐릭터의 좌우 방향에 있는지 판별할 때.

월드 좌표계의 Up 방향 벡터를 캐릭터의 Forward 방향 벡터를 F, 캐릭터와 적간에 생기는 벡터를 A 벡터라고 하면,

Up · (A × F) 값, 즉 Det(Up, A, F) 값이 0보다 크면 오른쪽, 0 보다 작으면 캐릭터의 왼쪽에 있음을 판별할 수 있다.

이는 외적으로 생긴 벡터의 방향이 Up 벡터의 방향과 -90~90도

즉, 예각을 이루면 cos값이 0보다 큰 원리를 이용한 것이다.

+ Recent posts