Game Development, 게임개발/게임 수학,물리

Geometry Pipeline, 오브젝트부터 스크린까지의 변환

게임이 더 좋아 2021. 11. 7. 00:53
반응형
728x170

**21.11.11 업데이트

**21.12.22 업데이트

 


 

게임의 오브젝트가 우리 스크린 위에서 실제로 움직이기까지 정말 많은 과정을 거친다.

그 과정들은 Transformation이고 특히 좌표 변환이 엄청나게 이루어진다. 

-> 행렬의 계산은 은근히 연산이 많기에 이를 해결한다면 렌더링에 도움이 될 것 같다.

알아보자

 


 

우선 요약하자면

 

Local  <-> World (Model Space)

World (Model Space) <-> View (Camera Space)

 

View (Camera Space) <-> 정규 뷰 볼륨, Canonical view volume (Proejection)

 

Canonical view volume <-> Screen

 

 


 

순서대로 알아보자

3D 모델의 폴리곤 메시가 가진 모델 공간의 Local 좌표에서 World 좌표로 바꾸고자 한다.

 

왜바꾸어야 하느냐?

** 쉽게 말하면 그래픽 카드에 각 모델을 그릴 수 있게 알려주는 것이다.(Local 은 안된다)

 

해당 변환은 World Transformation 이나 Model Transformation이라고 부른다.

 

단순이 로컬 좌표 벡터에 모델 변환 행렬을 곱해서 구해낸다.

각 오브젝트 고유의 상대좌표였던 것들이 이제는 절대적인 기준을 가진 World 좌표로 바뀌는 것이다.

 

 

다시 말하자면 

3D 폴리곤 메시에게는 각각의 좌표계가 있어서 

3D 폴리곤 메시를 x축 방향으로 2만큼 움직인다고 해도 해당 로컬 좌표계에 대해서 움직이는 것이라

우리가 생각하는 World 좌표계의 x축 방향대로 움직이지 않을 수 있다.

 

**다시 말해서 상대 좌표에서 절대 좌표로 바꾸는 것은 렌더링하기 위해 위치를 고정시키는 첫번째 변환이다.

 

Local에서 World로 바꿀 때 

크게 3가지 변환요소를 가지고 있다.

1. 평행이동 -> translation

2. 회전 -> rotation

3. 스케일 -> scale

 

다시 말해서 로컬 기저벡터를

우리가 알고있는 월드 기저벡터로 바꿀 때 일어나는 3가지 변환이라고 생각하면된다.

이렇게 되면 각각 오브젝트가 좌표계를 가지고 있었지만 변환 후에는 하나의 좌표계로 모두 표현할 수 있다.

 

-> 쉽게 말하면 로컬좌표계에서의 원점을 월드좌표계에서의 원점으로 바꾸기 위한 작업이라고 하면 된다.

-> 원점 이동 + 기저 벡터 회전 + 기저 벡터 크기 변환

 


 

월드 좌표료 변환이 되면 이제 뷰 변환이 이루어진다.

 

월드 좌표계로는 왜 부족하냐?

실제로 우리가 게임에서 보는 것은 카메라가 비추는 게임 속의 세상인 것이다.

즉,  우리가 보는 카메라가 어디에 위치하느냐에 따라 게임 속의 세상이 달라보일 것이다.

 

즉, World 에서는 고정적인 좌표계로 두었지만 우리가 눈을 어디다 두고 World를 쳐다보느냐에 따라

다시 해당 좌표계에서의 위치가 결정되기 때문이다.

다시 말해서 카메라는 카메라의 기저벡터를 가지고 있기 때문이다.

 

예를 들면 우리가 카메라로 다리가 길게 찍히는 것과 같다.

사실 우리가 숏다리여도 길게 나오는 이치다..ㅋㅋㅋ

 

다시 말하자면 World Space를 Camera Space로 바꾸는 것이다.

** View Space라고도 한다.

 

View Space로 바꾸기 위해서는 3개의 입력 값이 필요하다.

1. 카메라의 위치

2. 카메라가 바라보는 대상의 위치

3. 카메라의 위쪽을 가리키는 벡터(뒤집혀있는지 알려면 기준이 있어야겠지?)

 

-> DirectX에서는 카메라는 3가지 파라미터를 가진다.

-> 이 파라미터를 이용해 뷰 변환행렬을 얻음(Transpose된 행렬을 반환하기도 한다)

(EYE, 월드 공간에서의 카메라 위치)

(AT, 카메라가 바라보는 기준점)

(UP, 카메라를 기준으로 상단방향의 벡터, 일반적으로 y축)

 

-> 로컬좌표계의 변환과 같다.

카메라가 보는 시점(원점)이 다르니 일치시켜주면 된다.

 

월드 좌표계의 원점을 이동(원점을 이동하면서 대상의 위치가 바뀜)

다시 대상의 위치를 보정

그 후 카메라의 위쪽을 가리키는 벡터(일반적으로 y축)이 나오도록 기저벡터 설정(회전)

 


 

이제 끝났겠지?

 

라고 생각하지만 이제 우리는 Screen으로 화면을 보여줘야 한다.

Screen 자체는 3D가 아니라 2D이기 때문이다.

View 좌표계에서 다시 Projection 변환을 통해서 Clip Space로 바꾼다.

(View Volume이라고도 함)

** 투영 변환이라고도 말한다.

[Game Developer, 게임개발자/게임 수학,물리] - 게임수학 - 동차좌표계, Homogeneous coordinates **

 

++여기서 원근감을 주느냐에 따라 직교투영, 원근 투영이 나눠진다.

 


왜 Clip Space냐?

 

우리가 보는 것은 카메라 렌즈가 담고있는 것만 본다.

즉, 카메라가 해당 방향을 바라보고 찍어도 해당 방향에 있는 모든 것이 나오는 것이 아니라

카메라 렌즈에 담긴 것들만 나오는 것이다.

-> 화각을 생각하면 쉽다.

우리가 해당 방향으로 몸을 틀었다고 해서 해당 방향의 모든 것들을 볼 수 있는 것은 아니다.

결국 나머진 잘려서 나오게 된다. 그래서 클립 스페이스라고 한다.

 

결국 카메라가 보는 것은 near plane부터 far plane까지 보게 되는 것이다.

저것이 사각뿔이 잘린 것과 같다해서 view frustum, 뷰 프러스텀이라고도 부른다.

즉, 카메라에 너무 가까워도 안보이게끔 하고 너무 멀어도 보이지 않게끔 한다.

또한 저 사각뿔에 벗어난 부분은 보이지 않는다.

-> 실제로 뷰 프러스텀에 들어있지 않은 물체를 GPU에서 계산하지 않게해서 렌더링 성능을 높일 수 있다.

이를 뷰 프러스텀 컬링, view frustum culling이라고 한다.

 

**near보다 가까운 것은 보이지 않고 far보다 먼 것은 보이지 않는다.

-> 잘린다, clipping된다.

 


 

왜 이런 식으로 해야하냐..?

 

우리 눈과 다르기 때문이다.

** 우리눈엔 세균이 육안으로 관찰되지 않는 것이지 보인다고 말할 수 있다.

즉, 있는 것이지만 육안으로는 인지하지 않을 뿐이다.

하지만 컴퓨터에서는 Continuous한 영역이 아니기 때문에

우리가 near plane과 far plane을 정해주어야 한다.

**화각, FOV란 말은 사진을 찍다보면 들어봤을텐데

FOV가 크다는 말은 근평면과 원평면의 크기 비율에서 원평면이 커지는 것을 의미한다.

-> 화각이 크다 == 넓은 영역을 담을 수 있다.

 

다시 돌아와서

시야 바깥쪽의 정보를 버리고, 뷰 프러스텀을 정규 뷰 볼륨, canonical view volume으로 바꾸는

즉, 각 정점 좌표가 정규화된 정육면체로 변환하는 것이 바로 프로젝션 변환이다.

 

변환에는 4가지 파라미터가 있다.

1. FOV, field of view (화각)

2. 종횡비(가로, 세로 비율)

3. near plane

4. far plane

**그리고 카메라의 시점을 꼭짓점으로하는 뷰 프러스텀을 만드는 것이다.

 

변환 후 좌표계는 정규화 디바이스 좌표계, Normalized Device Coordinates 로 바뀐다.

** 원근을 주기 때문에 원근 분할이라고도 부른다.

**또한 여기서는 x,y,z 말고도 w좌표를 사용하는데

요약하자면 Image Processing에 무한원점 개념을 더해 유용하게 쓰이기 위해 좌표를 추가한 것이다.

(동차좌표계)

 

??? 아니 근데.. 왜 View frustum 을 다시 직육면체로 변환해야 하는데..?

우리의 모니터를 보자.

 

평면인가? 

맞다.

 

그렇다면 우리는 near plane과 far plane 중 어느 것을 선택해서 봐야하는가..?

아니다. 그냥 보는 것이다.

 

그리고 near plane은 작고 far plane은 작은데...? 뭔가 이상한데??

 

즉, 우리는 모니터에 담기 위해서 크기도 통일해야 함은 물론

멀수록 작게 가까울수록 크게 보이도록 바꿔줘야한다.

**물론 Orthographic일 때는 near plane의 크기와 far plane이 같은 크기를 가져서 원근감이 없다.

 

그래서 우리는 우선 3차원이지만 정육면체인(near plane과 far plane을 같게 만드는 but 비율대로)

정규 뷰 볼륨으로 바꾸는 작업을 해주는 것이다.

그렇게 함으로써 Far와 Near의 비율대로 (1:1이면 직교투영) 을 해주는 것이다.

 


 

그제서야 이제 Screen에 띄울 준비를 다 마쳤다.

 

우리는 이제 마지막으로 2D인 Screen으로 바꾸어서 사용자에게 보여줘야 한다.

이를 Viewport Transformation이라 한다.

변환하면 Screen 좌표계로 바뀌게 된다.

z값을 단순히 사라지게하는 것이 아니라 버퍼(z-buffer or depth buffer) 에 저장하여

심도를 파악하는데 쓰인다. (원근감을 말한다.)

**심도는 depth 깊이감을 말한다.

728x90
반응형
그리드형