본문 바로가기

게임수학

행렬

정의

행렬은 행과 열이 있는 격자 모양 배열 안에 스칼라를 나열한 것이다.  행렬 안에 나열된 스칼라를 요소라 부른다. 
프로그래밍 언어에서는 배열 인덱스의 첫번째 숫자를 0을 사용하는 0 베이스 인덱스가 많이 쓰이지만, 행렬 요소 지정에는 1행째를 1부터 시작하는 인덱스를 관례적으로 사용한다.

행렬의 종류

행과 열의 수가 같은 행렬을 정사각형렬이라고 한다. 게임 개발에서 사용되는 행렬은 대부분 정사각행렬로, 특정 행이나 열이 항상 변화하지 않는 등 최적화의 여지가 있는 경우에만 해당 행/열을 무시한다.

행렬 요소 m{ij|에 관해 i = j인 요소를 대각요소라고 한다. 또한 정사각행렬이고 대각 요소 이외의 요소가 모두 0인 행렬을 대각행렬이라고 한다. 대각행렬 중 대각요소가 모두 1인 행렬을 단위행렬이라고 한다. 유니티에서 Matrix4x4 클래스는 identity 프로퍼티는 단위행렬을 반환한다.

단위행렬

모든 요소가 0인 행렬은 모두 성분이 0인 벡터처럼 영행렬이라고 부른다.

영행렬

앞에서, 행벡터와 열벡터를 벡터로서는 같다고 말했지만, 기하하적으로는 행벡터와 열벡터로 크기와 방향이 변하는 게 아니므로 같다는 사실을 문제없이 받아들어야 한다. 하지만 행렬에서는 행렬과 벡터를 연산에서 함께 다룰 경우 행벡터와 열벡터를 개별적으로 봐야한다. 예를 들어, 행렬로 나타내보면 행벡터는 다음처럼 1 x n 행렬로 볼 수 있다.

[1, 2, 3]

또한 열벡터는 다음처럼 n x 1 행렬로 볼 수 있다.

이 둘은 행렬로서 서로 다르다는 점을 주의해야 한다.

행렬과 행렬의 연산

벡터의 경우, 스칼라와 벡터의 연산이 규정되어 있었는데, 행렬에서도 마찬가지로 다양한 연산을 적용할 수 있다. 예를 들어, 행렬끼리 덧셈을 하거나 행렬의 스칼라배 곱셈을 할 수 있다. 하지만 게임 개발에 쓰이는 행렬 연산은 대부분 행렬끼리의 곱셈뿐이다.

행렬끼리 곱한 결과는 행렬이 된다. 행렬의 곱셈은 A의 열수와 B의 행수가 같은 경우만 정의되어 있다. 결과인 행렬 M은 행수가 A인 행수, 열수가 B의 열수가 된다.(A, B 모두 정사각행렬인 경우에는 수가 모두 같다.)

 

M의 요소 e{ij}는 다음과 같이 정의된다.

시그마의 k = 1 부분은 k의 초기값을 1로 설정한다는 뜻이고, 위쪽 n은 i가 마지막에 가지는 값이다. k를 1부터 n까지 바꾸면 항이 여러개 생기는데, 생성된 수열의 각 항을 모두 더한 총합을 결과로서 출력한다는 뜻이다.

다시 말해, M의 요소 e{ij}는 k를 1부터 n까지 변화시켰을 때, a{ik}와 b{kj}의 곱의 총합이다.

 

단 각 스칼라 요소를 곱한 총합이라는, 이해하기 어려운 행렬의 곱의 정의보다는 더 이해하기 쉬운 방법이 있다. 요소별 곱의 총합이 벡터인 경우 내적 연산에 제공되는 정의를 이용하는 것이다.

벡터의 내적은 이처럼 a, b 각 벡터의 성분을 곱한 총합으로 정의되므로, 행벡터와 열벡터로서 행렬에서 잘라낸 부분을 생각해보면 필요한 계산과 서로 일치한다.

 

우선 행렬 A의 각 행에 해당하는 행벡터 R은 다음과 같다고 하자(x는 1부터 m).

그리고 행렬 B의 각 열에 해당하는 열벡터 C를 다음처럼 나타낸다.(y는 1부터 p)

이때 행렬 A, B의 곱인 행렬 M(행수는 m, 열수는 p)은 다음과 같다.

이처럼 각 요소가 각각의 행벡터, 열벡터의 내적이 되는 형식으로 나타낼 수 있다.

행렬의 곱에서는 교환법칙이 성립하지 않으므로, 다음과 같이 곱하는 순서에 의미가 있다

AB ≠ BA

반면 다음과 같이 결합법칙은 성립한다.

(AB)C = A(BC)

앞에서 소개한 단위행렬은 다른 행렬과 곱하더라도, 곱해진 행렬은 변화하지 않는다고 특별한 성질을 만족한다.

AI = IA = A

전치행렬

m x n 행렬 M에서 M의 i행 j열의 요소 m{ij|를 바꿔넣은 n x m 행렬을 m^T로 나타내고, 원래행렬 M의 전치행렬이라고 부른다. 정사각행렬에서 전치 조작은 대각요소를 축으로 삼아 나머지 요소를 반대쪽으로 이동한다.(정사각형행렬 이외에도 전치는 가능하며, 그런 경우 행수와 열수가 전치 전후에 바뀐다.)  Matirx4x4 클래스의 transpose 프로퍼티는 원래 행렬의 전치 행렬을 반환한다.행렬 M이 단위행렬 등의 대각행렬인 경우, 애초에 대각요소 이외에는 모두 0이므로, 전치행렬도 원래 행렬 그대로이다.

M^T = M

또한 행렬 M의 전치행렬을 다시 전치하면 원래 행렬이 된다.

(M^T)^T = M

그리고 행렬 M, N의 곱에 대해서는 다음과 같은 관계가 성립한다.

(MN)^T = N^TM^T

행벡터와 열벡터는 행렬로 봤을 때, 서로 다른 것이라고 앞에서 언급했지만, 행벡터를 전치한것이 열벡터고 열벡터를 전치하는 것이 행벡터다.

전치에 의해 행벡터와 열벡터를 서로 변환할 수 있는 점을 이용해서, v를 전치하여 열벡터v와 열벡터 w의 내적을 다음과 같이 행렬끼리의 곱으로 구할 수 있는 행렬 요소로서의 표현할 수 있다.

역행렬

전치행렬과 달리 정사각행렬로만 구할 수 있는 것이 역행렬이라는 개념이다. 행렬 M의 역행렬은 M^-1로 표기하고, M과 M^-1의 곱은 단위행렬 I과 된다.

단위행렬 I의 역행렬은 단위행렬 그 자신이다.

애초에 모두 0이 들어있는 행과 열을 포함하는 행렬은 어떤 행렬을 곱해도 단위행렬에 필요한 대각요소 1을 만들 수 없으므로, 역행렬이 존재하지 않는다. 즉 모든 행렬에 역행렬이 존재하는 것은 아니다. 그러므로, 역행렬이 존재하는 행렬을 특별히 가역행렬 또는 정칙행렬이라고 한다.

Matrix4x4 클래스의 inverse 프로퍼티는 원래 행렬의 역행렬을 반환한다.

전치행렬과 마찬가지로 역행렬에는 다음과 같은 성질이 성립한다.

또한 전치행렬의 역행렬은 역행렬의 전치행렬과 같다.

행렬과 벡터의 곱셈

행벡터를 1 x n 행렬, 열벡터를 n x 1 행렬로 볼 수 있다는 것은 이미 설명한 대로다. 다만 행렬로서의 차이가 문제가 되는 경우는 행렬과 벡터의 곱을 구하려 할 때다. 행렬과 벡터의 곱은 벡터가 된다.
원래 행렬 A와 B의 곱셈은 A의 열수와 B의 행수가 같아야 하며, 결과 행렬 M은 행수가 A의 행수, 열수가 B인 열수가 된다. 따라서 n차원의 행벡터 v에 행렬 M을 곱해 vM으로서 곱을 구하라면 우선 M은 n행이어야만 하고, 결과로서 n차원의 행벡터 u를 얻으라면 M은 n열이고 n x n인 정사각행렬이어야 한다. 역으로 M{v}로서 곱을 구하려면 v는 열벡터어야 한다. M이 정사각행렬이면 결과는 같은 차원의 열벡터가 된다.

 

벡터 u, v와 정사각형행렬 M의 곱에는 다음의 분배법칙이 성립한다.

또한 복수의 행렬 M, N, P를 벡터 v에 차례로 곱해나갈 때, 행렬 곱에는 결합법칙이 성립하므로, 다음처럼 행벡터 v의 경우는 왼쪽에서 오른쪽으로 열벡터 v^T인 경우는 오른쪽에서 왼쪽으로 곱해나간다고 볼 수 있다.

이처럼 벡터에 행렬을 곱할 때는 행벡터인지 열벡터인지 생각한 다음 계산해야 한다.

스위즐 연산

행렬과 벡터의 곱으로 벡터의 성분을 변경하는 스위즐 연산이 있다. 스위즐이란 셔플과 비슷하게 서로 뒤섞는다는 의미로, 여기서는 대상  벡터의  임의의 성분을 임의의 순서로 뽑아내 나열하는 것을 의미한다. 

행렬과 역벡터를 곱하면, 행렬의 각 행과 열벡터와의 내적이 결과 열벡터의 각 성분으로 들어온다. 다시 말해 행렬의 각 열의 성분 중 원래 열벡터 안에서 원하는 성분에 대응하는 위치의 성분이 1이고, 다른 요소가 모두 0이라면, 원래 열벡터의 원하는 성분의 수치만 결과 열벡터의 성분으로 들어오게 된다. 프로그래밍 기법으로 말하면 비트 마스크를 적용한 듯한 이미지다. 여기서는 0과 1 요소만으로 구성된 부울 행렬을 이용한다.

성분 중 하나를 벡터 전체에 벌어놓는 산포 스위즐도 할 수 있다.

스위즐 연산은 유니티 벡터에는 구현이 되지 않았지만, cpu에 내장된 SIMD 명령 세트와 cpu 프로그래밍을 위한 셰이딩 언어에는 구현된 경우가 많다.

행우선과 열우선

유니티에서 Matrix4x4 클래스를 설명을 보면 열우선이라고 되어있다.

사실 열우선이란 컴퓨터 구조에 따른 성질이지 수학 개념은 아니다. 하지만 게임개발자라면 행렬을 다룰 때 의식해야만 하는 주제이다. 
행렬은 컴퓨터 데이터로 표현하면 실제로는 메모리 상의 1차원 배열에 그 요소가 저장되고, 메모리 주소를 지정하여 지정된 요소에 접근한다. 이때 메모리에 1행씩 나열해나갈지 혹은 1열씩 내열해나갈지, 그 저장 방식에 따라 메모리 상에서 레이아웃이 다른 일련의 데이터가 될 수 있다.행우선 방식에서는 행렬의 1행씩 1차원 배열에 채워지고, 열우선 방식에서는 1열씩 1차원 배열에 채워진다.

 

TODO AOS SOA, 행렬식, 직교행렬

'게임수학' 카테고리의 다른 글

게임 앱 환경  (1) 2025.02.02
곡선  (0) 2025.02.02
벡터  (0) 2025.01.30
좌표계  (0) 2025.01.28
삼각함수  (1) 2024.04.06