이미 알고있는 내용이지만, 월드 -> 카메라 -> 투영행렬을 거쳐 3차원의 정점이 2차원의 점으로 변환되는 과정을 마치 정점이 수도파이프를 통과하는 과정처럼 묘사한거다.
사실, 투영이 끝난 다음에는 클리핑과 뷰포트변환과징이 있지만, 이 그림에서는 안그렸다
여기서는 각 좌표계의 행렬 유도 과정을 살펴본다
월드변환행렬
월드변환행렬은 로컬좌표계를 3차원 절대 좌표계인 월드좌표계로 변환하는 행렬이다.
- 이동, 회전, 크기변환행렬등이 대표적인 예다.
로컬좌표계 : 메시를 모델링할 당시의 좌표계
이 로컬좌표계에 월드변환행렬을 적용하면 위와같은 좌표가 된다
모든 메시마다 각자의 고유한 로컬 좌표계가 있기 때문에, 이를 월드좌표계로 변환하려면 메시마다 변환행렬이 있어야한다, 이 변환행렬값은 일반적으로 3D 모델링 도구에서 추출한다
카메라 변환 행렬
월드변환행렬이 로컬좌표계의 원점을 월드의 원점을 기준으로 하는 변환이라면, 카메라 변환 행렬의 역할은 카메라가 존재하는 곳을 원점으로하고, 카메라가 바라보는 방향을 기준으로 한 새로운 카메라 좌표계를 만든 뒤, 이 좌표계로 월드좌표계를 변환하는 것이다.
카메라 변환 행렬은 이동행렬과 좌표축 변환행렬로 구성된다.
이동행렬은 카메라 좌표의 역방향 행렬이다. 간단히 말해서, 좌표값의 부호만 바꿔주면 되는 것.
- 직관적으로 상상해보자, 카메라가 오른쪽으로 1m 이동하면, 결과적으로 카메라를 제외한 모든 물체들이 좌측으로 1m 이동한것과 같다.
행렬로 표기하면 다음과 같다.
[ 1 0 0 0]
[ 0 1 0 0]
[ 0 0 1 0]
[-Cx -Cy -Cz 1]
여기서 C = (Cx, Cy, Cz)는 카메라의 좌표다.
그림을보고
카메라의 위치를 c = (0,0,-1), 카메라가 향하는 위치를 (1,1,10)이라고하면, 카메라의 방향벡터 n = (1,1,11)로 나타낼 수 있다.(카메라가 원점에 Z는 한칸뒤니까 물체에 닿는데 까지 걸리는 벡터는 11)
그리고, 카메라의 위쪽 방향을 나타내는 상방벡터가 (0,1,0)이라면 카메라의 우측을 나타내는 벡터는 v=(0,1,0)*n (상방 * 카메라방향)으로 나타낼 수 있다. 그리고, 다시 u벡터를 구하면 u = n * v로 구할 수 있다.
p = 목표물의 좌표, c = 카메라의 좌표, up = 상방벡터(일반적으로 (0,1,0))일 때, 새로운 카메라 좌표계의 축 n, v, u는 다음과 같다. (n : 카메라 방향, v : 카메라 우측벡터, u : 카메라 상방)
n축(z축) = normalize(p - c)
v축(x축) = normalize(up * n)
u축(y축) = n * v
n축(z축)에서 z축이란, 내가 이해하기 쉽게 왼손 좌표계의 x, y, z축과 같은 위치라는 것
u,v축도 마찬가지로 x, y축에 대응된다.
이렇게 얻어낸 2개의 행렬을 월드좌표계에 적용하면 된다.
수식으로 보자.
뷰좌표 = 월드좌표 * 이동행렬 * 좌표계 변환 행렬(전 강좌 : 행렬 참고)
[ 1 0 0 0] [Vx Ux Nx 0]
[ 0 1 0 0] [Vy Uy Ny 0]
[x', y', z', 1] = [x, y, z, 1] * [ 0 0 1 0] * [Vz Uz Nz 0]
[-Cx -Cy -Cz 1] [ 0 0 0 1]
여기에 결합법칙을 적용하면 다음과 같이 된다.
[ Vx Ux Nx 0]
[ Vy Uy Ny 0]
[x', y', z', 1] = [x, y, z, 1] * [ Vz Uz Nz 0]
[-(CxVx+CyVy+CzVz) -(CxUx+CyUy+CzUz) -(CxNx+CyNy+CzNz) 1]
정리하면
[ Vx Ux Nx 0]
[ Vy Uy Ny 0]
[x', y', z', 1] = [x, y, z, 1] * [ Vz Uz Nz 0]
[-(CㆍV) -(CㆍU) -(CㆍZ) 1]
결과적으로 얻어내고자 하는 최종 카메라 변환 행렬은 아래와 같다
[ Vx Ux Nx 0]
[ Vy Uy Ny 0]
[ Vz Uz Nz 0]
[-(CㆍV) -(CㆍU) -(CㆍZ) 1]
투영변환행렬
투영변환이란, 3차원 좌표계를 2차원 좌표계로 바꾸는 변환이야. 그림자를 생각하면 돼
그림자의 실체는 3차원이지만 정작 그림자는 2차원 평면에 투영되거덩
투영을 하기 위해서는 투영될 공간을 설정해야해,
전체 카메라 좌표중에서 실제로 보여질 부분을 선택해야한다는거야.
두가지 방법이 있는데, 직교투영, 원근투영 두가지야.
직교투영은 그냥 Z값을 지워 2차원으로 만들었다고 생각하면 이해하기 쉬울거야
직교투영의 행렬
[2/w 0 0 0]
[ 0 2/h 0 0]
[ 0 0 1/f-n 1]
[ 0 0 -n/f-n 0]
f : far, n : near
원근투영은 거리에 따라 물체가 멀어지는것을 표현한 변환방법으로, 시야 절두체를 변환하는 것이다
원근투영의 시야
원근투영의 행렬
[2n/w 0 0 0]
[ 0 2n/h 0 0]
[ 0 0 f/f-n 1]
[ 0 0 -fn/f-n 0]
원근투영이 가장 많이 사용되니까. 원근투영 유도과정을 한번 보자.
원근투영은 위 그림처럼 근평면과 원평면으로 둘러싸인 시야 절두체를 (-1, -1, 0) ~ (1, 1, 1)의 좌표계로 변환하는게 목적이야.
이를 위해서, 카메라 좌표계의 임의의 한 점 P = (Px, Py, Pz)가 투영 좌표계의 P' = (Px', Py', Pz')로 어떻게 변환되는지를 유도하면 되는것이다.
먼저 카메라 좌표계의 시야 절두체 내의 점을 카메라 좌표계의 근평면에 투영하기위한 점의 방정식을 구해보자....
OP 직선의 방정식
z = Pz/ Px * x [식 4-3]
근평면의 XZ 평면에서의 직선 방정식
z = n [식 4-4]
[식 4-3] = [식 4-4]로 놓으면 Px'의 값을 구할 수 있다.
x = nPx / Pz [식 4-5]
마찬가지로 Py'의 값을 구하면
x = nPy / Pz [식 4-6]
시야 절두체의 점은 left <= x <= right, bottom <= y <= top을 만족하므로 이 값을 [-1, 1] 사이의 값으로 변환하려면 간단하게 다음과 같은 함수를 만들 수 있다.
2
x' = (x-l)r-l - 1 (단, l = left, r = right) [식 4-7]
2
y; = (y-b)t-b - 1 (단, b = bottom, t = top) [식 4-8]
[식 4-7]에 [식 4-8]을 대입하면..
( nPx ) 2
x' = ( Pz - l ) r - l - 1
nPx 2 2l r-l
= Pz * r-l - r-l - r-l
2n Px ( 2l r-l)
= r-l * Pz - (r-l + r-l)
2n ( Px ) (r+l)
= r-l ( Pz ) - (r-l) [식 4-9]
마찬가지로,
2n ( Py ) (t+b)
y' = t-b ( Pz ) - (t-b) [식 4-10]
이제, z'의 값을 구해보자, z는 near <= z <= far인데, 이 값을 [0, 1] 사이의 값으로 변환하여야 한다, 이때 [식 4-9]와 [식 4-10]을 보면 z값이 분모에 있으므로, 다음과 같은 수식을 만족하는 A, B항을 찾는다.
A
z' = z + B [식 4-11]
near -> 0이므로 z = n, z' = 0을 대입하고 far -> 1 이므로 z = f, z' = 1을 대입해서 [식 4-11]을 전개하면 다음과같아.
A A
0 = n + B, 1 = f + B 단, n = near, f = far [식 4-12]
[식 4-12]를 A, B에 대해서 정리하면
A A
1 = f - n
( 1 1 )
1 = A( f - n )
( n - f )
1 = A( fn ) [식 4-13]
이제 A를 [식 4-12]에 다시 대입하면
fn
n - f
0 = n + B
fn
0 = n(n - f) + B
f
B = f - n [식 4-14]
[식 4-11]에 [식 4-13]과 [식 4-14]를 대입하면..
fn 1 f
x' = (n-f)(Pz) + f-n [식 4-15]
이제 점 P' = (x', y', z')를 동차 좌표계의 P'4 = (x'Pz, y'Pz, z'Pz, Pz) 점으로 변환하면 다음과 같다.
(2n) (r+l)
x'Pz = (r-l)Px - (r-l)Pz
(2n) (t+b)
x'Pz = (t-b)Py - (t-b)Pz
전화나 임베디드시스템, PDA같은데다가 포팅할라면 무조건 알아야한다.
'Graphics > DirectX' 카테고리의 다른 글
Direct 3D - 조명모델 (0) | 2014.07.12 |
---|---|
Direct 3D - 사원수 (Quaternion) (0) | 2014.07.08 |
Direct 3D - 행렬 (0) | 2014.06.19 |
Direct 3D - 행렬기초 (0) | 2014.06.19 |
Direct 3D - 벡터 (0) | 2014.06.19 |