수학 - 행렬

Lev·2024년 3월 20일
0

📓TIL Archive

목록 보기
32/33

4 x 4 행렬

class float4x4
{
public:
	union
	{
		struct
		{
			float v00; 
			float v01; 
			float v02;
			float v03;

			float v10; 
			float v11; 
			float v12;
			float v13;

			float v20; 
			float v21; 
			float v22;
			float v23;

			float v30; 
			float v31; 
			float v32;
			float v33;
		};

		float4 ArrVector[4];
		float Arr1D[16] = { };
		float Arr2D[4][4];
	};

	float4x4()
	{
		Identity();	// 무조건 항등행렬로 생성
	}
	
	float4x4& operator=(const float4x4& _Value)
	{
		memcpy_s(Arr1D, sizeof(float) * 16, _Value.Arr1D, sizeof(float) * 16);
		// _Value.Arr1D에 존재하는 내용을 (sizeof(float) * 16) 크기만큼,
		// Arr1D의 (sizeof(float) * 16) 크기에 복사하라는 뜻
		
		return *this;
	}

	float4x4 operator*(const float4x4& _Value)
	{
		return ::operator*(*this, _Value);
	}
	
    // 3차원 변환행렬로써 사용할 경우...
	float4 LeftVector()		// X벡터
	{
		return -ArrVector[0].Normalize2DReturn();
	}
	
	float4 RightVector()	// X벡터
	{
		return ArrVector[0].Normalize2DReturn();
	}
	
	float4 UpVector()		// Y벡터
	{
		return ArrVector[1].Normalize2DReturn();
	}
	
	float4 DownVector()		// Y벡터
	{
		return -ArrVector[1].Normalize2DReturn();
	}
	
	float4 ForwardVector()	// Z벡터
	{
		return ArrVector[2].Normalize2DReturn();
	}
	
	float4 BackVector()		// Z벡터
	{
		return -ArrVector[2].Normalize2DReturn();
	}
};

using FMatrix = float4x4;

곱셈

행렬 1 ⇒ Y1 x X1
행렬 2 ⇒ Y2 x X2
(행렬 1 * 행렬 2) 연산을 수행할 경우…

  • X1 = Y2 이어야 곱셈이 성립한다.
  • 연산 결과는 Y1 x X2 의 크기를 갖는다.
  • 교환법칙은 성립하지 않는다.
/*
(1 x 4) * (4 x 4) 의 경우
a00 a01 a02 a03		x	b00 b01 b02 b03		=	ab00 ab01 ab02 ab03
						b10 b11 b12 b13
						b20 b21 b22 b23
						b30 b31 b32 b33

ab00 = a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30
ab01 = a00 * b01 + a01 * b11 + a02 * b21 + a03 * b31
ab02 = a00 * b02 + a01 * b12 + a02 * b22 + a03 * b32
ab03 = a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33
*/

float4 float4::operator*(const float4x4& _Other) const
{
	float4 Result;
	Result.X = (Arr2D[0][0] * _Other.Arr2D[0][0]) + (Arr2D[0][1] * _Other.Arr2D[1][0]) + (Arr2D[0][2] * _Other.Arr2D[2][0]) + (Arr2D[0][3] * _Other.Arr2D[3][0]);
	Result.Y = (Arr2D[0][0] * _Other.Arr2D[0][1]) + (Arr2D[0][1] * _Other.Arr2D[1][1]) + (Arr2D[0][2] * _Other.Arr2D[2][1]) + (Arr2D[0][3] * _Other.Arr2D[3][1]);
	Result.Z = (Arr2D[0][0] * _Other.Arr2D[0][2]) + (Arr2D[0][1] * _Other.Arr2D[1][2]) + (Arr2D[0][2] * _Other.Arr2D[2][2]) + (Arr2D[0][3] * _Other.Arr2D[3][2]);
	Result.W = (Arr2D[0][0] * _Other.Arr2D[0][3]) + (Arr2D[0][1] * _Other.Arr2D[1][3]) + (Arr2D[0][2] * _Other.Arr2D[2][3]) + (Arr2D[0][3] * _Other.Arr2D[3][3]);
	return Result;
}

float4& float4::operator*=(const class float4x4& _Other) 
{
	float4 Result;
	Result.X = (Arr2D[0][0] * _Other.Arr2D[0][0]) + (Arr2D[0][1] * _Other.Arr2D[1][0]) + (Arr2D[0][2] * _Other.Arr2D[2][0]) + (Arr2D[0][3] * _Other.Arr2D[3][0]);
	Result.Y = (Arr2D[0][0] * _Other.Arr2D[0][1]) + (Arr2D[0][1] * _Other.Arr2D[1][1]) + (Arr2D[0][2] * _Other.Arr2D[2][1]) + (Arr2D[0][3] * _Other.Arr2D[3][1]);
	Result.Z = (Arr2D[0][0] * _Other.Arr2D[0][2]) + (Arr2D[0][1] * _Other.Arr2D[1][2]) + (Arr2D[0][2] * _Other.Arr2D[2][2]) + (Arr2D[0][3] * _Other.Arr2D[3][2]);
	Result.W = (Arr2D[0][0] * _Other.Arr2D[0][3]) + (Arr2D[0][1] * _Other.Arr2D[1][3]) + (Arr2D[0][2] * _Other.Arr2D[2][3]) + (Arr2D[0][3] * _Other.Arr2D[3][3]);
	*this = Result;
	return *this;
}

/*
(4 x 4) * (4 x 4) 의 경우
a00 a01 a02 a03		x	b00 b01 b02 b03		=	ab00 ab01 ab02 ab03
a10 a11 a12 a13			b10 b11 b12 b13			ab10 ab11 ab12 ab13
a20 a21 a22 a23			b20 b21 b22 b23			ab20 ab21 ab22 ab23
a30 a31 a32 a33			b30 b31 b32 b33			ab30 ab31 ab32 ab33

ab00 = a00 * b00 + a01 * b10 + a02 * b20 + a03 * b30
ab01 = a00 * b01 + a01 * b11 + a02 * b21 + a03 * b31
ab02 = a00 * b02 + a01 * b12 + a02 * b22 + a03 * b32
ab03 = a00 * b03 + a01 * b13 + a02 * b23 + a03 * b33

ab10 = a10 * b00 + a11 * b10 + a12 * b20 + a13 * b30
ab11 = a10 * b01 + a11 * b11 + a12 * b21 + a13 * b31
ab12 = a10 * b02 + a11 * b12 + a12 * b22 + a13 * b32
ab13 = a10 * b03 + a11 * b13 + a12 * b23 + a13 * b33

ab20 = a20 * b00 + a21 * b10 + a22 * b20 + a23 * b30
ab21 = a20 * b01 + a21 * b11 + a22 * b21 + a23 * b31
ab22 = a20 * b02 + a21 * b12 + a22 * b22 + a23 * b32
ab23 = a20 * b03 + a21 * b13 + a22 * b23 + a23 * b33

ab30 = a30 * b00 + a31 * b10 + a32 * b20 + a33 * b30
ab31 = a30 * b01 + a31 * b11 + a32 * b21 + a33 * b31
ab32 = a30 * b02 + a31 * b12 + a32 * b22 + a33 * b32
ab33 = a30 * b03 + a31 * b13 + a32 * b23 + a33 * b33
*/

float4x4 operator*(const float4x4& _Left, const float4x4& _Right)
{
	float4x4 Result;
	const float4x4& A = _Left;
	const float4x4& B = _Right;
	
	Result.Arr2D[0][0] = (A.Arr2D[0][0] * B.Arr2D[0][0]) + (A.Arr2D[0][1] * B.Arr2D[1][0]) + (A.Arr2D[0][2] * B.Arr2D[2][0]) + (A.Arr2D[0][3] * B.Arr2D[3][0]);
	Result.Arr2D[0][1] = (A.Arr2D[0][0] * B.Arr2D[0][1]) + (A.Arr2D[0][1] * B.Arr2D[1][1]) + (A.Arr2D[0][2] * B.Arr2D[2][1]) + (A.Arr2D[0][3] * B.Arr2D[3][1]);
	Result.Arr2D[0][2] = (A.Arr2D[0][0] * B.Arr2D[0][2]) + (A.Arr2D[0][1] * B.Arr2D[1][2]) + (A.Arr2D[0][2] * B.Arr2D[2][2]) + (A.Arr2D[0][3] * B.Arr2D[3][2]);
	Result.Arr2D[0][3] = (A.Arr2D[0][0] * B.Arr2D[0][3]) + (A.Arr2D[0][1] * B.Arr2D[1][3]) + (A.Arr2D[0][2] * B.Arr2D[2][3]) + (A.Arr2D[0][3] * B.Arr2D[3][3]);

	Result.Arr2D[1][0] = (A.Arr2D[1][0] * B.Arr2D[0][0]) + (A.Arr2D[1][1] * B.Arr2D[1][0]) + (A.Arr2D[1][2] * B.Arr2D[2][0]) + (A.Arr2D[1][3] * B.Arr2D[3][0]);
	Result.Arr2D[1][1] = (A.Arr2D[1][0] * B.Arr2D[0][1]) + (A.Arr2D[1][1] * B.Arr2D[1][1]) + (A.Arr2D[1][2] * B.Arr2D[2][1]) + (A.Arr2D[1][3] * B.Arr2D[3][1]);
	Result.Arr2D[1][2] = (A.Arr2D[1][0] * B.Arr2D[0][2]) + (A.Arr2D[1][1] * B.Arr2D[1][2]) + (A.Arr2D[1][2] * B.Arr2D[2][2]) + (A.Arr2D[1][3] * B.Arr2D[3][2]);
	Result.Arr2D[1][3] = (A.Arr2D[1][0] * B.Arr2D[0][3]) + (A.Arr2D[1][1] * B.Arr2D[1][3]) + (A.Arr2D[1][2] * B.Arr2D[2][3]) + (A.Arr2D[1][3] * B.Arr2D[3][3]);

	Result.Arr2D[2][0] = (A.Arr2D[2][0] * B.Arr2D[0][0]) + (A.Arr2D[2][1] * B.Arr2D[1][0]) + (A.Arr2D[2][2] * B.Arr2D[2][0]) + (A.Arr2D[2][3] * B.Arr2D[3][0]);
	Result.Arr2D[2][1] = (A.Arr2D[2][0] * B.Arr2D[0][1]) + (A.Arr2D[2][1] * B.Arr2D[1][1]) + (A.Arr2D[2][2] * B.Arr2D[2][1]) + (A.Arr2D[2][3] * B.Arr2D[3][1]);
	Result.Arr2D[2][2] = (A.Arr2D[2][0] * B.Arr2D[0][2]) + (A.Arr2D[2][1] * B.Arr2D[1][2]) + (A.Arr2D[2][2] * B.Arr2D[2][2]) + (A.Arr2D[2][3] * B.Arr2D[3][2]);
	Result.Arr2D[2][3] = (A.Arr2D[2][0] * B.Arr2D[0][3]) + (A.Arr2D[2][1] * B.Arr2D[1][3]) + (A.Arr2D[2][2] * B.Arr2D[2][3]) + (A.Arr2D[2][3] * B.Arr2D[3][3]);

	Result.Arr2D[3][0] = (A.Arr2D[3][0] * B.Arr2D[0][0]) + (A.Arr2D[3][1] * B.Arr2D[1][0]) + (A.Arr2D[3][2] * B.Arr2D[2][0]) + (A.Arr2D[3][3] * B.Arr2D[3][0]);
	Result.Arr2D[3][1] = (A.Arr2D[3][0] * B.Arr2D[0][1]) + (A.Arr2D[3][1] * B.Arr2D[1][1]) + (A.Arr2D[3][2] * B.Arr2D[2][1]) + (A.Arr2D[3][3] * B.Arr2D[3][1]);
	Result.Arr2D[3][2] = (A.Arr2D[3][0] * B.Arr2D[0][2]) + (A.Arr2D[3][1] * B.Arr2D[1][2]) + (A.Arr2D[3][2] * B.Arr2D[2][2]) + (A.Arr2D[3][3] * B.Arr2D[3][2]);
	Result.Arr2D[3][3] = (A.Arr2D[3][0] * B.Arr2D[0][3]) + (A.Arr2D[3][1] * B.Arr2D[1][3]) + (A.Arr2D[3][2] * B.Arr2D[2][3]) + (A.Arr2D[3][3] * B.Arr2D[3][3]);

	/*
	for (size_t y = 0; y < 4; y++)
	{
		for (size_t x = 0; x < 4; x++)
		{
			for (size_t i = 0; i < 4; i++)
			{
				Result.Arr2D[y][x] += _Left.Arr2D[y][i] * _Right.Arr2D[i][x];
			}
		}
	}
	*/

	return Result;
}

항등행렬

: 곱했을 때 자기자신이 나오는 행렬

  • 교환법칙이 성립한다.
  • 3차원 변환행렬로 사용할 경우, 항등행렬에도 공간 정보가 포함되어 있다고 볼 수 있다.
/*
1	0	0	0
0	1	0	0
0	0	1	0
0	0	0	1

어떤행렬 * 항등행렬 = 어떤행렬
항등행렬 * 어떤행렬 = 어떤행렬
*/

void Identity()
{
	memset(Arr1D, 0, sizeof(float) * 16);
	// Arr1D의 주소값 위치부터 (sizeof(float) * 16) 크기만큼을 0으로 채우라는 뜻
	
	Arr2D[0][0] = 1.0f;
	Arr2D[1][1] = 1.0f;
	Arr2D[2][2] = 1.0f;
	Arr2D[3][3] = 1.0f;
}

전치행렬

: 행과 열을 바꾼 행렬

/*
00	01	02	03	-(전치)->	00	10	20	30
10	11	12	13				01	11	21	31
20	21	22	23				02	12	22	32
30	31	32	33				03	13	23	33
*/

void Transpose()
{
	float4x4 Result = *this;
	for (size_t y = 0; y < 4; y++)
	{
		for (size_t x = 0; x < 4; x++)
		{
			Result.Arr2D[y][x] = Arr2D[x][y];
		}
	}

	*this = Result;
}
profile
⋆꙳⊹⋰ 𓇼⋆ 𝑻𝑰𝑳 𝑨𝑹𝑪𝑯𝑰𝑽𝑬 ⸝·⸝⋆꙳⊹⋰

0개의 댓글