개발하는 리프터 꽃게맨입니다.

[수학] 3차원 공간: 입체 공간의 생성 본문

컴퓨터 그래픽스/수학

[수학] 3차원 공간: 입체 공간의 생성

파워꽃게맨 2024. 7. 19. 00:06

1. 3차원 공간의 설계

3차원의 수학이 2차원과 다른 점은 3개의 축을 사용한다는 것이다.

그렇기 때문에 3차원에서의 변환은 2차원보다 더 복잡하며 고려해야 할 점도 많다.

 

3D로 표현된 사실적인 게임을 만들기 위해서는 3차원 공간의 수학을 이해해야 한다.

먼저 3차원 공간을 구성하는 좌표계를 먼저 정의하도록 하자.

 

3차원 공간은 2차원의 공간에 새로운 축을 추가해야 하는데, 이를 어떻게 설정하느냐에 따라 공간의 체계가 달라진다.

 

3차원 공간을 설게하는 방법은 크게 두 가지로 구분된다.

 

기본적으로 가로를 x축, 세로를 y축

모니터를 기준으로 앞뒤를 z축으로 둔다.

 

이 때,

나머지 한 축이 모니터에서 나오는 체계를 '오른손 좌표계'

나머지 한 축이 모니터 뒤편으로 향하는 체계를 '왼손 좌표게'

라고 한다.

 

좌표계를 정했다면, 세 축의 용도를 지정해야 한다.

일반적으로 2차원에서는 오른쪽을 양의 x축, 윗쪽을 양의 y축으로 정했지만, 3차원 공간에서는 이를 지정하는 방법이 프로그램마다 다르다.

 

3차원 공간의 좌표계를 설명할 때, 좌표계와 함께 위 아래 방향을 담당하는 축의 정보를 알려주면 유용하다.

3DS는 z업 오른손 좌표계

유니티 엔진은 y업 왼손 좌표계,

언리얼 엔진은 z업 왼손 좌표계

라고 표현한다.


2. 3차원 공간의 트랜스폼

3차원 공간의 좌표계 설정을 완료했다면 이를 기반으로 렌더링에 사용할 3차원 트랜스폼 체계를 설계할 수 있다.

3차원 공간의 트랜스폼은 기저벡터가 하나 더 증가했을 뿐, 2차원 공간의 트랜스폼 설계 방식과 크게 다르지 않다.

 

3차원 공간에서 이동 변환을 지원하기 위해 3차원 공간을 사용했듯이, 3차우너 공간 역시 이동 변환을 위해 4차원을 사용한다.

 

2차원 공간의 크기 변환은 직교하는 x축과 y축이 서로 독립적으로 동작했다.

2차원 또한 마찬가지로 세 축이 모두 독립적으로 동작한다.

 

 

그러므로 이런식으로 크기변환행렬을 만들 수 있다.

 

3차원 이동 변환 역시 모든 축이 독립적으로 동작한다.

따라서 다음과 같이 설계할 수 있다.

이런 식으로 이동변환행렬을 만들 수 있다.

 

이제 회전 변환행렬을 만들어 보자.

회전 변환은 강체 변환의 설징을 가진다고 설명했으며, 이는 3차원 회전 변환에서도 동일하게 적용되어야 한다.

 

강체 변환은

1) 각 기저 벡터가 동일한 크기가 1

2) 각 기저 벡터가 직교를 유지

3) 행렬식은 1

을 만족해야 한다.

 

이런 조건을 만족시키는 강체 변환은 3차원 공간을 구성하는 세 표준기저벡터가 동일한 크기와 직교성을 유지한 상태로 함께 움직일 수 있게 한다.

 

만약, 회전 변환으로 달라진 세 표준기저벡터값을 알 수 있다면, 이를 열벡터로 사용하여 회전 변환행렬 R을 만들 수 있을 것이다.

 

그러나 이런 방법으로 3차원 공간의 회전을 지정하면, 매번 3개의 변화된 표준기저 벡터 값을 계산해야 하기 때문에 매우 까다롭다.

 

따라서 회전을 지정할 때에는 일반적으로 회전하는 중심축과 각으로 표현된 회전량을 지정하는 방식을 사용한다.

2차원에서는 회전축이 단 하나였기에 회전량만 사용해서 회전을 설계했지만, 3차원 공간은 무수히 많은 평면으로 구성되기 때문에 회전량만 지정해서 회전을 설계할 수 없다.

 

3차원 공간의 회전을 표현하는 대표적인 방법이 오일러 각이다.

 

1) 오일러 각

오일러 각은 3차원 공간에서 물체가 놓은 방향을 3개의 각을 사용해 표시하는 방법이다.

 

게임 엔진에서 오일러 각을 사용해 물체의 방향을 표시할 때는 표준기저벡터를 사용한다.

그렇기에 오일러 각은 표준기저벡터를 중심으로 회전하는 각의 크기로 지정된다.

세 표준기저벡터를 중심으로 회전하는 각을 모으면 다음의 3차원 벡터로 표현할 수 있다.

 

그러나 이렇게 만들어진 오일러 각의 정보는 범용적이지 못하다.

프로그램마다 x, y, z 축의 용도가 다르기 때문이다.

 

이런 문제를 해결하기 위해 x, y, z축 대신 회전의 움직임으로 회전 동작을 구분하고 각을 지정하는 방법을 사용한다.

방향에 따라 요, 롤, 피치 라고 한다.

 

이는 보통 항공기의 회전을 표현할 때 사용하는 용어로

세로축을 롤

가로축을 피치

수직축을 요

라고 부른다.

 

오일러 각을 사용해 3차원 공간의 회전을 표현할 수 있게 되었다.

렌더링 과정에서 3차원 공간의 회전을 사용하기 위해선 3차원 회전행렬을 생성해야만 한다.

 

오일러 각을 이용해서 회전행렬을 설계하는 방법을 생각해보자.

오일러 각은 표준 기저 벡터를 중심으로 회전한다. 이러한 회전은 동시에 일어나는 것이 아니고 세 번의 회전이 독립적으로 진행된다.

 

쉽게 생각하면, 축은 다르지만 연속된 3번의 회전이 발생하는 형태이다.

그래서, 최종 회전 행렬은 x축 기준 회전행렬, y축 기준 회전행렬, z축 기준 회전행렬을 구한 뒤 이를 모두 곱하여 얻을 수 있다.

 

예를 들어 x축 회전은 yz 평면의 회전을 의미한다.

 

동일한 방법으로 나머지 y축과 z축의 회전행렬 을 구하면 아래와 같다.

여기서 y축 회전행렬은 Ry의 모습만 사뭇다른 것을 관찰할 수 있는데, 그 이유는

x->y, y->z, z->x 순서로 세 축이 순환되기 때문이다.

즉, x->y, y->z, z->x 방향으로 각도가 증가한다는 의미

 

그런데 y축을 잡고 평면을 그리면

가로가 z축, 세로가 x축이 되어버린다.

즉, y축을 기준으로 하여 반시계방향 회전을 하면, 각이 증가하는 것이 아니라 각이 감소한다는 것

그렇기 때문에, y축을 기준으로하는 zx평면에서는 세타값이 작아질 수록 각이 증가한다.

 

여기서 각 세타에 -1 을 곱해주면, 세타 값이 증가하면 각이 증가하는 꼴을 만들 수 있다.

세타를 -세타로 바꾸고, 식을 정리하면 Ry의 식을 얻을 수 있다.

 

2) 회전행렬의 유도

각 기저 축의 회전행렬을 구했다면, 이를 순서대로 적용해 최종 회전행렬을 만들어야 한다.

행렬곱 사이에는 교환법칙이 허용되지 않기 때문에, 어떤 행렬을 곱하냐에 따라서 최종 행렬식에 차이가 발생할 수 있다.

 

경우의 수는 다음과 같다.

  • x -> y -> z                 피치 -> 요 -> 롤
  • x -> z -> y                 피치 -> 롤 -> 요
  • y -> x -> z                 요 -> 피치 -> 롤
  • y -> z -> x                 요 -> 롤 -> 피치
  • z -> x -> y                 롤 -> 피치 -> 요
  • z -> y -> x                 롤 -> 요 -> 피치

어떤 방식을 택할 것인지는 소프트웨어 설계에 따라 다르다.

 

일반적으로는

z -> x -> y , 롤 피치 요 방식을 사용한다.

언리얼 엔진의 오일러 각도 동일한 순서를 사용한다.

 

그렇다면 각 회전행렬을 순서대로 곱해 오릴러 각에 대응되는 회전행렬 R을 생성할 수 있다.

어떤 벡터에 롤 -> 피치 -> 요 순서로 행렬연산을 하니, 최종 회전 변환 행렬은 

요 * 피치 * 롤 이어야 할 것이다.

 

그러면 각각을 곱해 오일러 각에 대응되는 회전행렬 R을 설계하면 결과는 다음과 같다.

(계산 과정은 생략한다.)

 

 

이렇게 계산된 회전행렬의 열벡터는 표준기저벡터가 회전 변환된 로컬 축을 의미한다.

따라서 오일러 각으로 변환된 각 로컬 축의 값은 다음과 같이 계산해 얻을 수 있다.

 

로컬 축 데이터는 물체의 현재 회전 상태를 나타내는 좌표 축이다.

회전 변환이 발생할 때마다 해당 로컬 축 데이터를 갱신하면 물체의 회전 상태를 정확하게 추적할 수 있고, 렌더링 로직에 필요한 회전행렬을 바로 만들어 낼 수 있다.

(로컬 축을 회전행렬로 바꾸는 방법은 매우 쉽다. 열기준벡터로 하여 정방행렬을 만들면 된다.)

 

또, 현재 회전 상태를 쉽게 얻어올 수 있기 때문에 충돌 감지, 물체 간의 상호작용을 판단할 때 유용하게 사용된다.

 

이 계산식으로 얻어낸 로컬 축 벡터를 각각

로 지정하고,

 

최종적인 회전행렬 R은 위와같이 나타낼 수 있다.

 

3) 모델링 행렬

3차원 공간의 T, R, S 행렬은 다음과 같이 구할 수 있다.

 

위 세 행렬을 순서에 맞게 미리 곱한 모델링 행렬은 다음과 같이 구할 수 있다.


3. 카메라 공간

3차원 공간의 카메라는 이동과 동시에 회전 기능을 지원해야 한다.

 

위 그림과 같이 월드 공간의 원점에 카메라가 있고, 카메라가 바라보는 방향에 오브젝트가 존재한다고 가정하자.

이 상황에서 카메라의 x축과 y축으로 최종 화면을 생성한다고 설정했을 때 화면의 x축 방향은 우리에게 익숙한 오른쪽이 아니라 왼쪽을 향하게 된다.

 

그래서 카메라가 만들어내는 화면을 y축을 180도 회전하여 뷰 공간을 구성한다.

 

이 경우 뷰 공간의 z축은 카메라의 뒤를 향하게 되고, 결과적으로 뷰 공간의 x축과 z축은 월드 공간의 x축, z축과 반대 방향을 가지게 된다.

 

그렇지만, 화면의 x와 y축은 우리에게 익숙한 데카르트 좌표계처럼 보여지게 된다.

이러한 좌표계는 카메라를 위한 좌표계이며, 뷰 좌표계라고 부른다. 

 

이와 같은 체계를 지닌 뷰 공간으로 변환해주는 뷰 행렬을 설계해보자.

뷰 행렬은 카메라의 모델링 행렬의 역행렬을 이용해서 구할 수 있다.

 

그러므로 뷰 행렬을 카메라의 좌표에 곱하면 다시 월드 원점으로 되돌려 놓는 것이 가능하다.

다르게 생각해면 월드 좌표에 뷰 행렬을 곱하면, 카메라는 가만히 있으면서 월드 전체가 움직이고 회전하는 듯한 효과가 발생할 것이다.

 

이것이 뷰 행렬 설계의 핵심이며, 뷰 행렬이 카메라의 모델링 행렬의 역행렬인 이유이다.

 

그러면 카메라의 모델링 행렬부터 구해보자.

카메라에는 크기가 존재하지 않기 때문에, 카메라의 트랜스폼은 '회전' 과 '이동' 만 지원하면 된다.

 

카메라의 트랜스폼에 저장된 위치 값을 t, 로컬 축 값을 각각 x, y, z 라고 하자.

그러면 이동 행렬 T와 회전행렬 R은 다음과 같다.

이제 뷰 행렬을 구하기 위한 역행렬을 계산해보자.

회전 행렬은 전치 연산이기 때문에 손쉽게 역행렬을 구할 수 있다.

이동 행렬도 덧셈의 역원인 반대수를 사용해 구할 수 있다.

 

이 역행렬들을 이용하여 최종 뷰 행렬을 완성해보자.

 

먼저 카메라의 모델링 행렬을 살펴보자.

일반적으로 카메라는 회전을 먼저하고 이동을 한다.

 

그러므로 모델링 행렬의 역행렬은 다음과 같이 구할 수 있을 것이다.

두 행렬을 곱한 결과는 다음과 같다.

마지막으로 y축으로 180' 회전시키면 최종 뷰 좌표계를 만들 수 있다.

간단하게, x축 기저와 z축 기저를 반전시켜서 계산할 수 있다.

 

그러면 최종적인 뷰 좌표계는 다음과 같다.


4. 오일러 각의 특징

오일러 각 방식은 장점과 단점이 명확하게 존재한다.

 

1) 장점

  • 직관적인 회전체계를 제공한다.
    설정할 값도 세 가지 뿐이고, 직관적인 표준기저벡터를 회전축으로 사용하기 때문에 회전을 설계하기가 용이하다.

  • 적은 용량으로 3차원 공간의 회전 정보를 기록할 수 있다.
    텐서를 사용해 3차우너 공간의 회전을 표현하려면 최소 9개의 실수 데이터가 필요하지만, 오일러각은 3개의 데이터만있으면 된다

2) 단점 : 짐벌락 현상

오일러 각을 사용해 3차워 공간의 회전을 다룰 때에는 특정 상황에서 회전 움직임이 제한되는 짐벌락 현상을 감안해야한다.

 

 

짐벌락 현상은 세 개의 회전축이 하나의 축을 따라 정렬되어 회전의 자유도가 감소하는 문제를 뜻한다.

 

오일러 각을 사용하면 각 회전축은 독립적으로 회전한다.

어떤 회전축의 회전이 다른 축에 영향을 미치지 않는다.

 

그렇기에 특정한 회전 상황에서는 두 축이 동일한 평면에 놓일 수 있다.

이 경우 회전의 자유도가 감소하게 된다.

 


추가.  회전 보간의 계산

3차원 공간에서 시작 회전과 끝 회전을 지정하고 시간에 따라 두 회전 사이를 부드럽게 전환하는 기능을 구현해보자.

이를 구현하기 위해서는 경과된 시간에 따라 회전이 변화되도록 중간 회전 값을 계산할 수 있어야 하는데, 이를 회전 보간이라고 한다.

 

중간 회전 값은 다음과 같이 선형 보간의 식을 사용해 얻을 수 있다.

선형 보간식이 성립하려면 두 각의 회전 변환을 곱한 결과가 두 각의 합의 회전 변환과 동일해야한다.

즉, 3차원 공간에서 선형 보간식을 사용하는 데 문제가 없으려면, 두 오일러 각의 회전 변환을 곱한 결과가 두 오일러 각의 합의 회전 변환과 동일한지 확인하면 된다.

 

1) 하나의 축을 기준으로 회전할 경우

y축을 기준으로 회전 (요) 한다고 해보자.

2개의 회전변환이 있다고 하고, 회전량을 a, b로 한다.

Ra ㆍ Rb 는 요 회전이므로, Ryawa ㆍ Ryawb 와 동일하다. 피치와 롤은 모두 항등행렬이다.

R(a+b) 도 역시 요 회전이므로 Ryaw(a+b) 이다.

Ryaw(a+b) = Ryawa ㆍ Ryawb 

이므로, 오일러 각에서 한 축만 사용할 경우 선형 보간식을 사용할 수 있다.

 

2) 두 개 이상의 축을 사용할 경우

두 오일러 각에 대응하는 회전 변환 Ra와 Rb를 곱한 결과는 두 오일러 각을 합한 회전 변환 R(a+b) 와 다르다.

그러므로 두 축 이상을 사용하는 오일러 각은 선형 보간식을 사용할 수 없다.

 

즉, 일반적으로 한 축만 회전만 하는 경우 회전 보간은 오일러 각으로 충분히 구현 가능한데반해, 비행기 조종 같은 3차우너 공간에서 2개 이상의 기저축이 결합된 방식으로 회전을 진행하는 경우 오일러 각 방식을 사용해 회전 보간을 구현하기 까다롭다.


5. 연습문제

1. 3차원 공간에서 좌표계를 정의할 때는 축을 어떻게 설정하느냐에 따라 공간의 체계가 달라진다.
이 중 모니터 앞을 뚫고 나오는 방향을 양의 z축으로 하는 좌표계를 [                  ] 좌표계

모니터 뒷편으로 향하는 좌표계를 [               ] 좌표계라고 한다.

 

2. 3차원 이동변환 행렬, 크기변환 행렬의 기본 변환 행렬을 각각 적어라

 

3. 강체 변환이 되기위한 조건은?

4. 2D에서는 회전을 다룰 때 각도만 입력하면 회전 변환 행렬을 설계할 수 있었다. 3D에서는 왜 '각도' 혹은 '회전량' 만으로 부족한가? 3D에서 회전을 다루는 일반적인 방법은 무엇인가? 해당 방법의 장점과 단점은 무엇인가?

 

5. 일반적으로 오일러 각은 [                ] 를 중심으로 회전하는 각의 크기로 지정된다.

 

6. 오일러 각이 모든 프로그램에서 범용적이지 못한 이유를 쓰고

아래 빨간 박스에 올바른 단어를 기입하시오

 

7. 오일러 각을 이용해서 회전을 수행하면, 기저벡터를 회전축으로 각각 독립적인 회전을 하게 된다.

그러면 최종적인 회전 변환 행렬은 x축 기준 회전, y축 기준 회전, z축 기준 회전 행렬의 곱으로 나타낼 수 있다.

 

y업 오른손법칙 좌표계에서 x축 기준 회전, y축 기준 회전, z축 기준 회전 행렬은 어떻게 되는지 각각 구하고

요 -> 피치 -> 롤 순서로 회전행렬을 수행할 때 최종적인 회전행렬을 구하라

각도는 알파, 베타, 감마를 사용한다.

 

8. 오일러 각을 이용하여 3차원 회전변환을 수행하는 설계에서, 각각의 물체는 로컬 축 데이터를 가지고 있다.

로컬 축 데이터가 의미하는 것은 무엇이며, 로컬 축 데이터를 저장함으로써 취할 수 있는 장점은 무엇인가?

 

9. 카메라가 물체를 바라보고, 카메라의 x, y축으로 화면을 나타냈을 때 문제점은 무엇이며, 해결방법은 무엇인가?

 

10. 다음 행렬의 역행렬을 구하고시오
(1)

(2)

 

11. 뷰 행렬을 얻기 위해서 카메라 모델링 행렬의 역행렬을 구하는 이유는 무엇인가?

 

12. 3D 세계에서의 회전변환과 이동변환의 역행렬을 구하고, 카메라의 모델링 행렬과 뷰 행렬을 각각 구하시오.

 

13. 짐벌락 현상의 해결책은 무엇인가?

 

14. 오일러각에서 두 개의 축 이상을 사용하는 회전 선형 보간 구현이 하나의 축을 사용하는 경우보다 힘든 이유는?