5.조망과 투영_1

Download Report

Transcript 5.조망과 투영_1

5.2 뷰 프레임과 뷰 변환
5.2.1 가상 카메라 정의
5.2.1 가상 카메라 정의하기
1 ) 어디에 있는가
카메라의 위치. 다른 말로 시점, 뷰 위치, 뷰 공간 원점.
2) 어디를 바라보는가
뷰 방향 벡터. Vdir 이라고 불리는 벡터.
카메라의 위치에서 부터 바라보는 임의의 위치 까지의 벡터.
즉, 게임에서 캐릭터가 바라보는 방향.
그러나 방향 벡터는 하나로 제한 해야 함. 이에 View Up, View Side 벡터
가 필요. 이 세 벡터들은 서로 직교.
우측 그림에서 보면
View Dir 벡터가 Z 축
View Side 벡터가 X 축
View Up 벡터가 Y 축
OpenGL 은 오른손 시스템을 사용하기 때문에 Z축의 진행방향이 –Z 축.
5.2.2 카메라 조작하기
View Dir, Up, Side 구하기
Dir : 바라보는 위치 – 카메라의 위치
Up : 적절한 직교 기저를 만들기 위해 정보를 조작. 즉, 월드의 Up 을 사용. ( k 로 가정 )
Vup = k – ( k ∙ Vdir ) Vdir
Side : Dir 과 Up 의 외적으로 구함.
Vside = Vdir x Vup
@ 정규 직교 기저를 생성할 수 없는 문제.
뷰벡터와 월드Up이 평행하다면 Vup 구할 수 없음.
Vup = k – ( k ∙ Vdir ) Vdir
= k – ( 1 ) Vdir
=0
여기서 k 와 Vdir 이 평행하다면 내적값은 1.
반대의 방향일땐 내적값은 -1. 방향이 반대 이므로 이 역시 0.
= k – ( -1 ) Vdir
=0
5.2.3 뷰 변환 만들기
Void LookAt( const IvVector3& eye, const IvVector3& lookAt, const IvVector3& up )
{
// 뷰벡터 계산
IvVector3 viewDir = lookAt – eye;
IvVector3 viewSide;
IvVector3 viewUp;
viewDir.Normalize();
viewUp = up – up.Dot( viewDir ) * viewDir;
viewUp.Normalize();
viewSide = viewDir.Cross( viewUp );
// 전치 회전 행렬 구성
IvMatrix33 rotate;
rotate.SetRows( viewSide, viewUp, -viewDir );
// 이동 변환
IvVector3 eyeInv = -( rotate * eye ); // p.196
// 4x4 행렬구성
IvMatrix44 matrix;
matrix.Rotation( rotate );
matrix( 0, 3 ) = eyeInv.x;
matrix( 1, 3 ) = eyeInv.y;
matrix( 2, 3 ) = eyeInv.z;
}
// 뷰 -> 월드 변환 설정
::SetViewTransform( matrix.mV );
5.3 투영 변환
5.3.1 정의
3차원에서 2차원으로 변환하는 과정을 투영 이라고 함.
하나의 벡터에서 또 다른 벡터로의 투영을 위해 내적을 사용.
즉, 게임상 물체를 구성하는 정점들을 2차원 스크린에 나타내기 위한 프로젝션 평면 또는 뷰 평면이라고 불리는
임의의 평면위로 투영.
투영의 종류
1. 원근 투영
2. 평행 투영
3. 사선 평행
4. 사선 원근
– 우리가 흔히 사용하는 투영
– CAD 등에서 사용하는 시야가 없는 투영
투영 – 건물 조감도에서 사용하는 투영
투영 – 거울에 렌더링되는 공간… 추가로 엔젤 아담스 얘기가 나오는데… 못찾겠음 ㅡㅡ;
5.3.2 시야 절두체 ( View Frustum )
* 무한한 월드를 뷰평면 디스플레이 장치에 사상하는것은 불가능.
* 이때 시야 절두체를 사용하여 해당 절두체 안에 있는 물체만 뷰 평면에 투영.
* 절두체의 위쪽 평면과 아래 평면 사이의 각을 수직시야 ( Field of View ) 라고 함.
* 시야, 뷰윈도우 크기, 뷰 평면 거리 사이엔 하나의 관계가 성립. 이들중 두개가 주어지면 나머지 하나를 구할
수 있음.
* 일반적으로 60~90 도에 해당하는 시야를 사용.
* 평행 투영엔 시야의 개념이 존재 하지 않음.
5.3.3 정규화된 장치 좌표계( Normalized Device Coordinates )
3차원에서 2차원으로 투영할 시에 뷰 평면 공간에 대한 프레임이 필요.
원점으로 뷰윈도우의 중심을 사용.
넓이와 높이의 절반의 크기를 가지는 기저 벡터 생성. 이는 위 그림처럼 left = -1, right = 1, top = 1, bottom = -1
5.3.4 동차 좌표계
http://blog.naver.com/neosafe/130044604300 참조
3D에서의 필요한 벡터는 기본적으로 3차원좌표계이다.
이것을 4차원 좌표계로 확장하는데 추가되는 개념이 바로 동차 좌표계이다.
동차좌표는 결국은 4x4 행렬과의 연산 때문에 필요하다.
이동,크기,회전을 모두 담은 행렬은 최소 4x4 행렬일 수밖에 없다.
이 행렬과 정상적인 연산을 하기 위해서는 '벡터도 행렬' 이므로 1x4 또는 4x1형태를 맞춰줘야 한다.
그렇다면 처음부터 끝까지 동차좌표계가 1이면 된다.
게다가 당연히 1이라는 표시만 해주면 되는 기호는 생략 가능한데 굳이 따라다니는 아래와같다.
동차좌표는 방향과 점의 구분시켜준다.
x,y,z(DirextX는 D3DXVECTOR3)의 형태의 3차원 좌표계 구조체는 이게 점인지 방향인지 구분이 모호하기 때문
에 동차 좌표계가 포함된 4차원좌표계로 표시하게 되면(0은 방향,1은 위치) 좀 더 그 의미가 확실해진다.
┌
│
│
└
1 ,0
0 ,1
0 ,0
0 ,0
, 0
, 0
,1
, 0
,
,
,
,
0
0
0
1
┐
│
│
┘
-
x축 벡터
y축 벡터
z축 벡터
이동관련 벡터
0은 방향을 의미하는 벡터로써 위치,방향으로서 서로 다른 벡터인지 구분 가능하다.
(방향벡터가 방향이 같고 위치가 다르다라는 것은 확대 또는 축소인 상태이다.)
1은 위치를 의미하는 벡터로써 위치가 서로 다른 벡터인지 구분가능하다.
그러므로,
0의 동차항을 가지고 있는 벡터는 확대,축소(크기변화),방향변경(방향변화) 가능하고
1의 동차항을 가지고 있는 벡터는 이동(위치변화)가 가능하다.
결국 동차좌표계가 0이면 방향변화,크기변화라고 표현 할 수 있지만 위치변화라고는 말할 수 없다.
동차좌표계가 1이면 위치변화 라고 표현할 수 있지만 방향이나 크기변화라고는 말할 수 없다.
type A는 투영행렬에 대한 이론을 간략하게 설명해 놓은 그림인데 우리가 결국 원하는 것은 3차원의 점들이 2차원인
빨간상자안에 모인 위치들인 것이다.
type B는 점들의 위치보다는 시점으로부터의 방향이 중요한 것이 무슨 말인지 이해하기 위한 그림이다.
동차좌표라는 것은 마치 '지도의 축소비율'처럼 축소나 확대에 관한 비례개념처럼 보여지기도 하고 이 좌표가 1이
되서 완전한 위치의 형태(변환 끝)로 변형되었는지도 의미하게 된다.
5.3.5 원근 투영
그림에서 가장 왼쪽에 있는 점이 투영중심[시점]이고 수직선이 뷰 평면이다.
뷰 절두체 평면들 중 하나위에 놓인 뷰 좌표계에서 점 Pv를 가지고 있고 뷰 평면위에 놓인 대응하는 점
Ps를 구하길 원한다고 가정해 보자.
Ps의 y좌표를 찾는 것은 간단하다.
윈도우의 상단에 부딪힐 때 까지 투영의 선이 그 평면을 따라가도록 한다.
뷰 윈도우의 높이가 2이고 0에 중점이 맞추어져 있기 때문에 Ps의 y좌표는 뷰 윈도우 높이의 절반인 1이 된다.
d는 어떻게 구할 수 있을까?
y뷰 절두체 평면들의 절단면은 투영의 중심으로부터 뷰 윈도우의 범위 (1,d),(1,-d)를 통과하는 선들로
표현될 수 있다. 이러한 선들 사이의 각도가 시야 fov이다.
이때 음의축 위에 놓인 영역만 고려함으로써 문제를 단순화할 수 있다.
즉, 시야를 fov/2의 각으로 이등분 하는 것이다.
z축과 Ps사이의 거리가 1이라는 것을 알기 때문에 1/d = tan( fov/2)로 설정할 수 있따.
이는 d = 1/tan(fov/2) 가 되며 이는 cot(fov/2)와 같다.
따라서 고정된 뷰 윈도우 크기에 대해서, 시야의 각을 알기만 하면 거리 d를 구할 수 있다.
위 방법으로 상단 뷰 절두체 평면위에 놓인 임의의 점에 대한 좌표를 구할 수 있다.
이러한 2D 절단면인 경우에 모든 점들이 하나의 점 (1,-d)로 투영된다.
마찬가지로 아래쪽 y 절두체 평면 위에 놓인 점들은 (-1,-d)로 투영될 것이다.
그렇지만 뷰 공간 안에 일반적인 점 (Yv,Zv)를 가지고 있다고 가정하자.
그것의 투영도 또한 뷰 평면 위에 놓일 것이라는 것을 알고 있기 때문에 Zndc좌표는 -d일 것이지만
Yndc는 어떻게 구할 수 있을까?
만약 임의의점 (Yv,Zv)를 가지고 있다면 그림에서 대응하는 직각 삼각형의 빗변의 길이가 Yv, 그리고
-Zv이다(-Z축을 바라보고 있으므로). 투영된 점의 경우에 직각 삼각형의 변들의 길이는 Yndc와 d이다.
닮은꼴 삼각형 이므로 다음을 얻는다.
Yndc/d = Yv / -Zv
Yndc에 대해서 풀면 다음을 얻는다.
Yndc = dYv / -Zv
이것이 Y방향에서 좌표를 알려준다.
만약 뷰 영역이 정사각형이라면 x방향에 대해서도 같은 식을 사용할 수 있지만 대부분 그렇지 않다.
뷰 영역의 종횡비에 의해서 이것을 수정해야만 하며 이는 a = Wv/Hv로 정의 된다.
여기서 Wv와 Hv는 각각 뷰 사각형의 너비와 높이다. NDC뷰 윈도우 높이가 2이고 종횡비에 의해
NDC 뷰 너비를 수정한다고 가정할 것이다. 마찬가지로 닮은꼴 삼각형이므로 다음과 같은 공식을얻는다.
aXndc/d = Xv/-Zv
Xndc에 대해 풀면
Xndc = dXv/-aZv.
그래서 최종 투영 변환 공식은 다음과 같다.
Xndc = dXv/-aZv, Yndc = dYv/-aZv
여기서 주목해야 하는 것은 z좌표로 나눗셈을 수행한다는 것이다.
이로 인해 행렬 연산으로 전체 변환을 표현할 수 없다는 것이다.
이제 동차 공간에서 변환이 나와야 한다.
이를 위해서 w값으로 다른 좌표들을 나누어야만 한다.
만약 w값에 -Zv를 사상하도록 행렬을 설정한다면, 변환의 비선형적인 부분을 다루기 위해서
동차 나누기를 이용할 수 있다. 동차 나누기 이전에 그러한 상황을 일련의 선형 방정식들로
정리 할 수 있고 다음과 같다.
x = d/a * x
y = dy
z = dx
w = -z
4차원 선형 변환으로 이것을 다룰 수 있다
기저벡터들을 살펴보면 e0가 (d/a, 0, 0, 0)으로 e1이 (0, d, 0, 0), e2가 (0,0,d,-1), e3가(0,0,0,0)으로
사상되는데, w가 이 공식 어디에도 사용되지 않는다.
이것에 근거한 동차 원근 행렬은 아래와 같다.
[ d/a 0 0 0 ]
[ 0 d 0 0]
[ 0 0 d 0]
[ 0 0 -1 0 ]
기대했던 것처럼 변환된 w값은 더이상 1이 아니다.
이 행렬의 가장 우측열이 0이므로 이 행렬은 역또한 가지지 않는다.
이것이 기대한 결과인데 정보의 한 차원을 잃어버리기 때문이다.
동일한 투영의 선을 따라 놓인 뷰 공간에서 개별적인 점들이 NDC공간에서 하나의 점으로 사상될 것이다.
따라서 NDC 공간에서 하나의 점이 주어진다면, 뷰 공간에서 그것의 원래 위치들을 재구성하는 것은 불가능하다.
실제 이 행렬이 어떻게 동작하는지 살펴보면, 만약 뷰 공간에서 일반적인 점에 이 행렬을 곱한다면
결과는 아래와 같다.
[ d/a 0 0 0 ] [x]
[dx/a]
[ 0 d 0 0 ] [y]
=
[ dy ]
[ 0 0 d 0 ] [z]
[ dz ]
[ 0 0 -1 0 ] [1]
[ -z ]
이를 w로 나누면 다음과 같이 된다.
Xndc = dx / -az
Yndc = dy / -z
Zndc = -d
지금까지 x와 y를 투영하는 것을 다루어 왔고 z에 대해서는 완전히 무시했었다.
이전 유도과정에서 모든 z값들은 투영 평면에 거리의 음인 -d로 사상된다.
차원을 잃어버리는 것이 개념적으로 일리가 있지만 (결국 3D 공간에서 2D 평면으로 투영하므로) 실용적인
이유 때문에 z버퍼나 또 다른 깊이 비교를 위해서 z값들을 유지하는 것이 낫다.
뷰 윈도우 안에 X와 Y값들을 [-1,1]의 구간으로 사상할 것이므로, 마찬가지로 z값에 대해서
근단면과 원단면 위치안에 놓이도록 사상한다.
근단면과 원단면을 시점에상대적인 n과 f로 지정할 것이고 그래서 근단면 위에 놓인 점들은 -n인
Zv값을 가지고 -1인 Zndc값으로 사상된다. ( 참고로 Dx의 경우는 깊이에 대한 사상범위가 [0,1]이므로
Zndc가 0으로 사상된다.) 원단면 위에 놓인 그러한점들은 -f인 Zv값을 가지고 1로 사상될 것이다.
xy좌표들을 구하기 위해서 사용한 것과 약간 다른 방법으로Zndc에 대한 공식을 유도할 것이다.
구간 [-n, -f]를 [-1, 1]로 사상하기 위해서 두 가지 변환들이 존재한다.
첫번째 그 구간으로 그만큼 비례 축소하는 것이고 두번째는 그것을 [-1,1]로 이동하는 것이다.
통상적으로 이것은 일련의 선형 변환과정이지만, 최종적인 w 나눗셈과 같은 곤란한 문제가 있다.
대신에, 비례 축소와 이동 인자에 대한 미지수를 가진 원근 행렬을 만들 것이고
미지수들에 대해서 해를 구하기 위해서 -n과 -f에 대한 최종값들을 안다는사실을 사용할 것이다.
첫 원근행렬은 아래와 같다.
[
[
[
[
d/a
0
0
0
0
d
0
0
0 0]
0 0]
A B]
-1 0 ]
여기서 A와 B는 각각 미지수인 비례 축소와 이동 인자들이다.
만약 근단면 위의 점 (0,0,-n)에 이 값을 곱한다면 다음과 같다.
[
[
[
[
d/a
0
0
0
0
d
0
0
0
0
A
-1
0 ] [0]
0 ] [0]
B ] [-n]
0 ] [1]
=
[0]
[0]
[ -An + B ]
[n]
w를 나누면 다음을 얻는다.
Zndc = -A + B/n
근단면 위의 임의의 점이 -1인 정규화된 장치 좌표로 사상된다는 것을 알고 그래서 Zndc에 -1을 대입해서
B에 대해서 풀수 있다.
B = (A-1)n
이제 원본행렬과 원단면 위의 임의의 점(0,0,-f)를 곱하는 것으로 대체하면 다음과 같다.
[
[
[
[
d/a
0
0
0
0
d
0
0
0
0 ] [0]
0
0 ] [0 ]
A (A-1)n] [-f]
-1
0 ] [1]
[0]
= [0]
[ -Af + (A-1)n ]
[f]
그렇게 하면 다음과 같은 Zndc를 얻는다.
Zndc = -A + (A-1)n/f
=-A + A(n/f) - n/f
= A(n/f-1)-n/f
Zndc를 1로 설정하고 A에 대해서 풀면 다음을 얻는다.
A(n/f-1)-n/f = 1
A(n/f-1) = 1 + n/f
A = (1 + n/f) / (n/f-1)
=(n+f)/(n-f)
B = (A-1)n 이 식에 대입하면
B = (2nf)/(n-f) 가 된다.
따라서 최종 행렬은
[
[
[
[
d/a
0
0
0
0
0
0
]
d
0
0
]
0 (n+f)/(n-f) 2nf/(n-f)]
0
-1
0
]
생성한 이 행렬은 OpenGL 함수 gluPerspective()를 호출함으로써 생성되는 행렬과 동일하다.
이 함수는 시야를 통해 시야,종횡비, 그리고 근단면과 원단면 설정을 인자로 받고 원근 행렬을
만들고 그것을 현재 행렬에 곱한다.
위에서 말했듯이 이는 OpengGL의 경우로 축약된다.
Directx는 z방향에 대해서 [0,1]로 사상한다.
[
[
[
[
d/a
0
0
0
0
d
0
0
0
0
f/(f-n)
1
0
]
0
]
-nf/(f-n)]
0
]
Direct3D 의 원근 투영 행렬
5.3.6 사선 원근
일반적인 원근의 예는 glFrustum() 호출을 통해서 생성.
이때 사용되는 값들은 z축에 중심을 두고 있지 않음.
이로 인해 사선투영을 생성 하기위해 이를 사용.
y 방향에서 볼때 투영 평면의 뷰 윈도우의 구간이 [-1, 1]
이었다면, 사선 원근에서의 구간은 [ b, t ] 에 놓이므로
적절한 NDC 공간을 가지도록 조정.
( t + b ) / 2 에 위치한 위도우 중심을 원점으로 이동.
p.212 그림 15.16a
구간을 ( t -b ) 의 크기에서 비례 축소 인자 2 / ( t - b ) 를 사용해서 2의 크기로 변경하기 위해 비례 축소.
y 에 NYv / -Zv 를 대입해서 단순화.
이러한 과정을 x 에 대해서도 수행.
원본 원근 행렬에서 동일한 A 와 B 를 사용. 최종 투영행렬
5.3.7 직교 평행 투영
OpenGL 에선 glOrtho() 를 통해 행렬 생성.
점( Yv, Zv ) 는 점 ( Yv, -n ) 으로 투영.
평행 투영이기 때문에 Z 로 나누기 또응 d 로 비례축소가 없고 Y 값을 직접 사용.
유사한 과정이 Xndc 공식 제공. Zndc 는 Z값이 음수이고 n 과 f 값들이 양수이므로 z 값을 부정
5.3.8 사선 평행 투영
Z 방향으로 2, Y 방향으로 1 단위 거리 이동.
YZ 평면에서 Y축 1, -Z축 2 단위로 이동하는 벡터 ( 1, -2 )를 점 P 에 대한 투영 선에 대한 공식.
L(t) = P + t ( 1, -2 )
선과 근단면의 교차 점.
Pz - 2t = -n
t에 대해서 풀면
t = 1 / 2 ( n + Pz )
L ( t ) 의 y 좌표에 대한 공식에 대입.
y’ = Py + 1 / 2 ( n + Pz )
범위 변환에 대입.
추가적인 Z 쉬어를 제외 하면 직교 변환과 동일.
5.4 제외와 오려내기
5.4.1 왜 제외와 오려내기를 수행하는가
뷰 프러스텀을 아예 벗어나는 물체들은 렌더링, 시뮬레이션, 충돌 판정같은 과정에서 제외 하여 속도를 향상 시킬 수
있음.
오려내기는 물체의 일부가 뷰 프러스텀에 들어갈경우 보여지는 부분만 렌더링.
이러한 불필요한 작업을 없애는것이 좋더라도 또다른 이유로 여전히 제외와 오려내기를 수행 해야 함.
투영에 의한 물체의 반전
시점 뒤를 지나는 선분의 투영 - 시각적으로 원하는 결과는 아니지만 수학적으론 정확한 형태
P-Q 선분이 투영되어 P’ - Q’ 되었으나 선분이긴 하지만 최단거리의 선분이 아닌 형태로 변형.
앞서 있었던 변형과 같지만 P’ - Q’ 점을 최단거리로 이은 잘못된 선분
앞선 현상에 대해 오려내기로 인해서 보여지는 부분의 선분만 그려지며 올바른 투영의 형태가 됨
즉, 시점 뒤에 있는 물체를 원근 투영시에 반전되지 않고 정상적으로 투영되게 하기 위해서라도 오려내기는
필요함.
또한, Z = 0 인 평면 위에 놓인 정점일 때도 원근 행렬을 통해 동차 공간으로 변환할때 0 으로 나누는 유효하지
않은 연산 발생.
이러한 논제들의 모두를 제거하기 위해서 뷰 프러스텀안 에 놓이지 않는 근단면이 필요.
5.4.2 제외
11장에서 더 자세히 알아본다고 함… 중요!!!
뷰 프러스텀의 6개 평면에다가 물체들의 정점을 평면의 방정식에 대입하여 평면의 안쪽에 있는지 바깥쪽인지를 판별
하여 모든 정점이 밖에 있으면 제외, 모든 정점이 안에 있으면 제외 하지 않음.
ax + by + cz + d < 0
ax + by + cz + d > 0
<- 모든 정점이 이러면 밖에 있는것
<- 모든 정점이 이러면 안에 있는것
그러나 모든 정점을 비교하는건 비용이 많이 들게 되므로 해당 물체의 모든 정점을 포함하는 바운드 스피어 등을
사용 해서 과정을 줄임.
제외에는 이것 말고도 여러가지가 있으며 6장에서 다룰 후면 제외 같은것 도 있음.
5.4.3 일반 평면 오려내기
한마디로 표현하자면 선분과 평면의 교차점 구하기.
선의 공식
평면 공식
P+t(Q-P)
ax + by + cz + d = 0
즉, 선의 공식을 구해서 평면 공식에 대입하면 됨!
단순화 하기 위해 Q - P 를 V 로 표시.
X ->
Px + t ( Q - P )
Px + tVx
약간 변형된 Blinn 표기법
t = BCP / ( BCP - BCQ )
임의의 평면에 대해서 선분이 오려내기 되는 네 가지 경우
최종 오려내기는
5.4.4 동차 오려내기
블린과 뉴웰은 투영 할때 투영된 점들의 몇가지 성질을 이용해 오려내기를 단순화 할 수 있다고 함.
w의 나눗셈 이후에 보이는 점들은 NDC 구간 [ -1, 1 ] 안에 존재.
-1 ≤ x/w ≤ 1
-1 ≤ y/w ≤ 1
-1 ≤ z/w ≤ 1
이 공식에 w 를 곱해 w 를 나누기 이전에 구간을 제공.
-w ≤ x/w ≤ w
-w ≤ y/w ≤ w
-w ≤ z/w ≤ w
즉, 6개의 평면들에 의해 경계.
평면들에 대해서 점들을 오려내는것 대신에, RP3 공간에서 이러한 단순 평면들에 대해서 점들을 오려 낼 수 있음.
W = X 인 평면 평가는 W - X. 평면의 전체 집합은 임의의 점 P 에 대해서
BCP-x = W + X
BCPx = W - X
BCP-y = W + Y
BCPy = W - Y
BCP-z = W + Z
BCPz =W - Z
5.5 화면 변환
렌더링을 위한 준비 단계에서 물체를 변환하는 최종 단계는 NDC 프레임에서 화면( 장치 프레임 )에 사상 하는것.
NDC 프레임에서 좌하단은 ( -1, -1 ), 우 상단은( 1, 1 ) 의 범위를 갖는다.
실제 장치 공간 좌표계는 좌상단 ( 0, 0 ) 에서 우하단 ( Width, Height ) 범위에 놓인다. ( 일반적으로 Width 와
Height 는 같지 않다. )
좌측은 NDC, 우측은 화면 영역으로 그림처럼 NDC 에서 화면 영역으로 사상해야 한다.
이것은 Y 방향을 반전하고 왼쪽 상단 모서리가 원점이 되도록 이동해서 화면과 같은 크기를 가지도록 NDC 영역을
비례 축소 하는것으로 구성된다.
NDC 윈도우는 2 유니트의 높이를 갖고, 화면 은 H 높이를 갖는다.
따라서 NDC 윈도우를 단위 높이로 비례 축소하기 위해 2로 나눈다. 거기에 화면 높이를 비례 축소 하기 위해 H 를
곱한다.
Y’ = H / 2 * Yndc
원점에 중심을 맞춰야 하므로 부정을 해서 축을 반전할 수 있다.
Y’’ = - H / 2 * Yndc
마지막으로 화면 상단을 원점으로 사상하도록 아래 방향으로 이동.
Y = - H / 2 * Yndc + H / 2
X 는 반전 되지 않음.
X = W / 2 * Xndc + W / 2
화면의 일정 부분만 다루는 등의 xy 에서 일반화된 화면 변환.
X = W / 2 * Xndc + W / 2 + Sx
Y = H / 2 * Yndc + H / 2 + Sy
Z 는 0 에서 D 까지 범위이고 여기서 D 는 항상 1. [ -1, 1 ] 에서 [ 0, D ] 로의 사상.
Z = Ds / 2 * Zndc + Ds / 2
화면 변환의 행렬.
투영에서 선택된 종횡비 a 가 화면 변환의 종횡비 W / H 와 일치하지 않을경우 이미지가 왜곡 된다.
특히 디스플레이가 오프스크린 버퍼와 다른 종횡비를 가질때 발생.
해결책은 오프스크린 종횡비와 관계 없이 화면의 종횡비로 설정. 오프스크린 버퍼에서 이미지는 왜곡
되겠지만 디스플레이로 출력될때 비례 적으로 늘어날 것이다.
5.6 피킹
2D 화면 좌표를 통해 3D 공간에서 교차하는 물체를 판별하는것.
이 장에선 판별하기 위해서 사용할 수 있는 형태로 변환 하는 방법 설명.
자세한건 11 장!!!
Ps 가 투영 평면 위에 클릭 위치. 시점에서 Ps를 통과하는 반직선 ( 픽 반직선 ) 을 그린다면 클릭 위치 앞쪽에
놓인 모든 물체를 통과한다. 어떤 물체를 클릭했는지를 판별하는건 투영평면 위에 점을 생성 하는 것 에서 부터
시작한다.
화면 공간 점 ( Xs, Ys ) 를 NDC 공간 점 ( Xndc, Yndc ) 로 변환. 이는 P.231 의 [ 식 5.5 ], [ 식 5.6 ] 의 역만 필요.
최종 화면 공간에서 뷰 공간으로 변환 공식
이들은 연립 방정식이므로 3 x 3 행렬로 표현
이때 선택 해야 할것이 있음.
첫째. 뷰 프레임에서 교차 판별
모든 물체가 뷰 프레임으로 변환해서 픽 반직선에 대해서 평가.
둘째. 월드 프레임에서 판별
픽 반직선을 월드 프레임으로 변환하고 각 물체의 월드 좌표에 대해서 평가.
셋째. 로컬 프레임에서 판별
월드 프레임에서의 판별은 이미 월드 위치와 경계 정보가 생성 되었으므로 교차 평가에만 집중한다면 충분히
효과적. 그러나 일반적으로 모델 정점들을 월드 프레임으로 변환 하지않고 로컬 공간에서 평가.
그러기 위해선 뷰 변환의 역을 통해 뷰 공간 점을 변환해야 함.
Pw = Mview->world * Pv
로컬 투 월드 행렬의 역을 곱함으로 이것과 시점 E 를 월드 좌표계에서 로컬 좌표계로 변환 할수 있음.
Pl = Mworld->local * Pw
El = Mworld->local * E
로컬 공간에서 픽 반직선에 대한 공식.
R( t ) = El + t ( Pl - El )
역시 자세한건 11장에서…