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

[DX11 물방울책 요약 정리] 챕터2: 행렬 대수 본문

컴퓨터 그래픽스/DirectX 11

[DX11 물방울책 요약 정리] 챕터2: 행렬 대수

파워꽃게맨 2024. 9. 7. 02:07

챕터2: 행렬대수

컴퓨터 그래픽스에서 우리는 행렬을 사용하여 크기 변환, 회전 변환, 이동 변환과 같은 기하학적 변환을 간결하게 설명하고, 또한 한 프레임에서 다른 프레임으로 점 또는 벡터의 좌표를 변경한다.

 

목표:

1. 행렬과 행렬에서 정의된 연산에 대해 이해한다.

2. 벡터와 행렬 곱셈이 어떻게 선형 결합으로 해석될 수 있는지 알아본다.

3. 항등 행렬, 전치, 행렬식, 역행렬이 무엇인지 배운다.

4. 행렬 수학을 위해 사용되는 XNA 라이브러리를 학습한다.

 

정의

m x n 행렬은 m 행, n 열로 구성된 실수들의 직사각형 배열을 의미한다.

행과 열의 곱은 행렬의 차원을 나타낸다.

 

행렬 내의 숫자들은 요소, 원소 등으로 불린다. 우리는 이중 첨자 표기법을 사용하여 요소가 속한 행과 열을 지정할 수 있다.

 

 

1.

A. 이 행렬은 4x4 행렬이다.

B. 이 행렬은 3x2 행렬이다.

 

2.

이중 첨자 표기법으로 행렬의 요소를 식별할 수 있다.

 

3.

행렬 u, v는 각각 1x3 행렬, 4x1 행렬이다.

해당 행렬은 하나의 행 또는 열만 포함하는 특수한 형태의 행렬로, 이러한 종류의 행렬을 각각 행벡터, 열벡터라고 부른다.

이를 통해서 벡터를 행렬로 자유롭게 변환할 수 있다.

 

행 벡터와 열 벡터의 경우, 이중 첨자 표기법을 사용할 필요없다.

 

 

때떄로 행렬의 행, 혹은 열을 하나의 벡터로 생각하기도 한다.

이러한 표기법에서는 참조하는 첨자에 *를 넣어서 열 전체, 혹은 행 전체를 참조하고 있음을 나타낸다.

 

이제 행렬에서의 동등성, 덧셈, 스칼라 곱셈, 뺄셈을 정의한다.

 

1. 동등성: 두 행렬에 각각 대응하는 요소들의 값이 모두 동일한 경우 두 행렬은 동일하다.

2. 덧셈: 두 행렬을 더할 때는 대응하는 요소들끼리 더한다.

3. 스칼라 곱셈: 스칼라와 행렬의 곱셈은 스칼라를 행렬의 모든 요소에 곱한다.

4. 뺄셈: 행렬의 뺄셈은 행렬 덧셈의 역원을 이용한다.

 

위 연산들은 모두 행과 열이 모두 같은 행렬들 사이에서 정의된다.

 

행렬 곱셈

행렬 A가 m x n 행렬이고, 행렬 B가 n x p 행렬일 경우, AB의 곱셈이 정의된다.

쉽게 말해서.. A의 열과 B의 행의 수가 같아야 한다.

 

 

새롭게 생성되는 행렬의 요솟값은 위와같이 정의된다.

행렬 C는 m x p 행렬이 된다.

 

위 두 행렬의 경우

A의 열과 B의 행이 일치하지 않기 때문에 곱셈이 정의되지 않는다.

2차원 벡터와 3차원 벡터끼리 내적이 정의되지 않기 때문이다.

 

해당 행렬은 곱셈이 정의된다.

 

반면, 행렬 곱셈 BA는 정의되지 않는다. 그 이유는 B의 열 수와 A의 행 수는 같지 않기 때문이다.

그렇기에 행렬 곱은 일반적으로 교환 법칙을 따르지 않는다는 것을 보여준다.

 

벡터-행렬 곱셈

 

이 경우, uA의 경우 (1 x 3) 행렬과 (3 x 3) 행렬 사이의 곱으로 계산된다.

이를 간단하게 벡터와 열벡터 사이의 내적으로 표현할 수도 있다.

 

책에서는 해당 식을 벡터 u와 행렬 A의 행 벡터들의 선형 결합과 같다고 표현한다.

 

결합 법칙

행렬 곱셈은 몇 가지 좋은 대수적 특성을 가진다. 예를 들어, 행렬 곱셈은 덧셈에 대해 분배법칙을 만족한다.

 

더하여, 행렬 곱셈은 결합 법칙을 만족한다. 이 법칙으로 인해 원하는 행렬을 먼저 곱할 수 있다.

전치 행렬 Transpose Matrix

전치 행렬은 행렬의 행과 열을 교환하여 얻어낼 수 있ek.

따라서 m x n 행렬의 전치는 n x m 행렬이다.

 

 

전치관련 유용한 특성

 

항등 행렬 Identity Matrix

항등 행렬은 모든 대각 행렬은 모두 1, 나머지 요소는 모두 0인 정방행렬이다.

항등 행렬은 행렬 곱셈의 항등원 역할을 한다.

 

 

따라서, 어떤 행렬에 항등 행렬을 곱해서 기존 행렬이 유지가 되며, 항등 행렬 곱에 한해서 교환법칙을 만족한다.

 

행렬식 Determinant Of Matrix

행렬식은 정방행렬을 입력으로 받아 실수를 출력하는 특수한 함수이다. 정방행렬 A의 행렬식은 보통 det(A)로 표기된다.

행렬식은 위와같이 계산할 수 있는데

 

행렬식은 두 벡터가 만들어내는 평행사변형의 넓이와 같다.

책에서는 행렬식은 선형 변환에서 부피가 어떻게 변화하는지를 알려준다고 말한다.

 

또한 행렬식은 Cramer의 법칙을 사용하여 연립방정식을 푸는 데 사용된다. 그러나 우리의 목적인 주로 역행렬을 찾기 위해서 행렬식을 이용한다.

 

또한, 정방 행렬 A가 역행렬이 존재할 필요충분조건은 det(A) != 0이다.

즉, 정방행렬의 가역성을 증명할 수 있다.

 

행렬식을 정의하기 전에 소행렬식의 개념을 먼저 소개한다.

 

소행렬식이란 n x n 행렬 A가 주어졌을 떄, 소형렬식 Aij는 i번쨰 행과 j번째 열을 제거하여 얻는 (n-1)x(n-1) 행렬이다.

행렬의 행렬식은 재귀적으로 정의된다.

예를 들어, 4x4 행렬의 행렬식은 3x3 행렬의 행렬식에 의해 정의되며

3x3 행렬의 행렬식은 2x2 행렬의 행렬식

2x2 행렬의 행렬식은 1x1 행렬의 행렬식에 의해 정의된다.

 

1x1 행렬 A의 det(A)는 자명하게 det(A) = A11 로 정의된다.

행렬 A가 n x n 행렬일 때,  n > 1 인 경우 행렬식은 다음과 같이 정의된다.

2x2 행렬의 행렬식은 다음과 같이 정의된다.

 

3x3 행렬의 행렬식은 다음과 같이 정의된다.

마지막으로 4x4 행렬의 행렬식은 다음과 같이 정의된다.

3D 그래픽스에서는 4x4 행렬을 주로 사용하기 때문에, n > 4 인 행렬에 대해서는 살펴볼 필요는 없다.

 

수반행렬 Adjoint of matrix

A가 n x n 행렬일 때

는 Aij의 여인자(cofactor) 라고 부른다.

 

행렬 A의 모든 요소에 대해 Cij를 계산하고, 이를 대응하는 행렬 Ca의 ij-번째 위치에 배치하면, A의 여인자 행렬을 얻을 수 있다.

 

이러한 여인자 행렬 Ca에 대하 전치를 취하면, A의 수반 행렬을 얻을 수 있다.

다음 섹션에서 수반 행렬이 행렬의 역행렬을 계산하는 명시적 공식을 제공한다는 것을 배우게 된다.

 

역행렬

행렬 대수에는 나눗셈 연산이 정의되지 않지만, 곱셈에 대한 역원이 정의된다.

 

다음은 역행렬에 관한 중요한 정보들을 요약한 것 입니다.

1. 오직 정방행렬만이 역행렬을 가질 수 있다.

2. n x n 행렬 M의 역행렬은 M^-1 로 표기되는 n x n 행렬이다.

3. 모든 정방행렬이 역행렬을 가지진 않는다. 역행렬을 가지는 행렬을 가역적이라 하고, 그렇지 않은 행렬은 특이 행렬이라고 한다. 

4. 역행렬이 존재하지 않거나, 존재할 경우 유일하게 존재한다.

5. 행렬과 그 행렬의 역의 곱은 항등행렬이다 

6. 행렬과 그 행렬의 역을 곱할 때는 교환법칙이 성립한다.

7. 역행렬은 행렬 방정식에서 다른 행렬을 구할 때 유용하다.

만약 v'와 M이 알려져 있을 때, M이 가역적이라고 가정하면, 벡터 v를 얻어낼 수 있다.

 

역행렬을 구하는 공식은 수반 행렬과 행렬식으로 표현할 수 있다.

2x2 행렬의 역행렬을 구해보자.

작은 행렬의 경우, 수반 행렬 방법이 계산 효율적이다.

그러나 더 큰 행렬의 경우 가우스-조던 소거법과 같은 다른 방법이 사용된다.

 

그러나 3D 컴퓨터 그래픽스에서 사용되는 행렬은 특별한 형태를 가지며,

역행렬을 미리 계산할 수 있다.

그러므로 역행렬을 구하는 데 CPU 사이클을 낭비할 필요가 없다.

 

마지막으로 역행렬의 유용한 대수적 성질을 알아보자.

증명도 첨부하였음

 

DirectXMath.h 살펴보기

 

수학 클래스에서 4x4 행렬을 나타내기 위해 XMMATRIX 구조체를 사용한다.

XMMATRIX는 XMVECTOR 인스턴스를 사용하여 SIMD를 지원한다.

또한 XMMATRIX는 행렬 곱셈을 위한 연산자 오버로딩, 행과 열을 지정하여 행렬 요소에 접근하거나 수정할 수 있는 괄호 연산자를 제공한다.

 

 

여러 생성자를 사용하는 것 외에도, XMMatrixSet 함수를 사용하여 생성할 수 있다.

 

 

벡터 때와 마찬가지로, 행렬을 클래스 데이터 멤버로 저장할 때는 XMFLOAT4X4 타입을 사용할 것을 권장한다.

 

행렬 함수

더보기
#include <iostream>
#include <DirectXMath.h>
using namespace DirectX;
using namespace std;

ostream& operator<<(ostream& os, FXMMATRIX mat)
{
	XMFLOAT4X4 m = {};
	::XMStoreFloat4x4(&m, mat);

	os <<
		m(0, 0) << " " << m(0, 1) << " " << m(0, 2) << " " << m(0, 3) << '\n' <<
		m(1, 0) << " " << m(1, 1) << " " << m(1, 2) << " " << m(1, 3) << '\n' <<
		m(2, 0) << " " << m(2, 1) << " " << m(2, 2) << " " << m(2, 3) << '\n' <<
		m(3, 0) << " " << m(3, 1) << " " << m(3, 2) << " " << m(3, 3) << '\n';

	return os;
}

int main()
{
	XMMATRIX matrix{
		XMVECTOR{15,2,8,4},
		XMVECTOR{5,6,7,8},
		XMVECTOR{9,10,1,2},
		XMVECTOR{3,4,6,6}
	};
	cout << matrix << endl;

	//항등행렬
	XMMATRIX iMat = ::XMMatrixIdentity();
	cout << iMat << endl;

	//항등행렬인가?
	if(::XMMatrixIsIdentity(iMat)) cout << "항등행렬!" << endl;

	//행렬곱
	XMMATRIX multied = ::XMMatrixMultiply(iMat, matrix);
	cout << multied << endl;

	//행렬 덧셈
	cout << iMat + matrix << endl;

	//행렬 뺄셈
	cout << iMat * matrix << endl;

	//스칼라 곱셈
	cout << 2 * matrix << endl;
	
	//스칼라 나눗셈
	cout << matrix / 2 << endl;

	//전치행렬
	cout << ::XMMatrixTranspose(matrix) << endl;

	//행렬식
	cout << ::XMVectorGetX(::XMMatrixDeterminant(matrix)) << endl;

	//역행렬
	//DirectX는 역행렬을 Cramer의 법칙을 사용하여 구한다.
	//해당 공식을 사용하는 과정에서 행렬식을 구해야하기 때문에
	//행렬식이 필요하다면, 해당 함수를 통해서 동시에 받을 수 있다.
	//만약 행렬식이 필요하지 않다면, nullptr 를 넣으면 된다.
	XMVECTOR det = {};
	cout << ::XMMatrixInverse(&det, matrix) << endl;
	cout << ::XMVectorGetX(det) << endl;

	return 0;
}