[ Goal ] DirectXMath 라이브러리 이해
1. 행렬
- 행벡터, 열벡터 들로 이루어진 배열로써 각 벡터는 원소로 구성되어있다.
- 3차원 컴퓨터 그래픽에서 행렬은 비례나 회전, 이동같은 기하학적 변환을 간결하게 서술하는데 사용된다.
더보기
행렬에 대해 자세한 내용이 필요하면 아래의 링크를 참고
- 행렬 곱셈에서 결합법칙의 중요성
- A : 10000 x 3 행렬 ( 좌표값 ) B : 3x3 행렬 ( 회전 행렬 ) C : 3x3 행렬 ( 이동 행렬 )
- (AxB)xC 의 계산량 : 10000 * 9 + 10000 * 9 = 180000
- Ax(BxC) 의 계산량 : 10000 * 9 + 3*9 = 90027
- 즉 결합에 따라 계산량이 반으로 줄어들 수 있다. ( 속도 향상 )
- 행렬식
- 행렬식은 정방행렬을 입력받아 실수값을 출력하는 특별한 함수이다.
- 행렬식은 기하학적으로 3차원 입체의 부피와 관련이 있다.
- 역행렬
- 행렬 대수는 나눗셈을 정의 하지 않지만 곱셈의 역원은 정의한다. 이를 역행렬이라 한다.
- 역행렬은 방적식의 해를 구할때 유용하게 사용된다.
- n차원의 역행렬을 구하는 방법은 대학 수준의 선형대수학 수업을 들으면 된다..
- DirectX에서 주로 다루는 3차원 그래픽에서는 역행렬을 구하는 공식은 거의 필요없다. 이유는 주로 사용되는 행렬의 역행렬이 거의 미리 알수 있는 특별한 형태이기 때문이다.
- 전치 행렬
- 전치행렬은 행렬의 행들과 열들을 맞바꾼 것이다.
- 주로 행렬곱에 있어서 차원을 맞추기 위해 사용한다.
2. DirectXMath 라이브러리의 행렬
- 3차원 그래픽에서 점과 벡터를 변환할때는 1x4 벡터와 4x4 행렬을 사용한다.
2.1 사용 라이브러리
- DirectXMath.h = DirectXMath 라이브러리를 사용하기 위한 필수 라이브러리
- DirectXPackedVector.h = 몇가지 추가적인 자료 형식을 위한 라이브러리
2.2 행렬 형식들
- DirectXMath 에서 XMMATRIX 형식을 사용한다. 이는 XMVECTOR가 4개 모인 형식이다.
#if (defined(_M_IX86) || defind(_M_X64) || defined(_M_ARM)) && \
defined(_XM_NO_INTRINSICS_)
struct XMMATRIX
#else
__deslspec(align(16)) struct XMMATRIX
#endif
{
// SIMD 활용을 위해, 행렬을 4개의 XMVECTOR로 표현
XMVECTOR r[4]
XMMATRIX() {}
// 행벡터 4개를 지정하여 행렬을 초기화
XMMATRIX(FXMVECTOR R0, FXMVECTOR R1, FXMVECTOR R2, CXMVECTOR R3)
{ r[0] = R0, r[1] = R1, r[2] = R2, r[3] = R3 }
// 성분 16개를 지정해서 행렬을 초기화
XMMATRIX(float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33);
// 부동소수점 수 16개 배열을 지정해서 행렬을 초기화
explicit XMMATRIX(_In_reads_(16) const float *pArray);
XMMATRIX operator+ () const { return *this; }
XMMATRIX operator- () const;
XMMATRIX& XM_CALLCONV operator+= (FXMMATRIX M);
XMMATRIX& XM_CALLCONV operator-= (FXMMATRIX M);
XMMATRIX& XM_CALLCONV operator*= (FXMMATRIX M);
XMMATRIX& operator*= (float S);
XMMATRIX& operator/= (float S);
XMMATRIX XM_CALLCONV operator+ (FXMMATRIX M) const;
XMMATRIX XM_CALLCONV operator- (FXMMATRIX M) const;
XMMATRIX XM_CALLCONV operator* (FXMMATRIX M) const;
XMMATRIX operator* (float S) const;
XMMATRIX operator/ (float S) const;
friend XMMATRIX XM_CALLCONV operator* (float S, FXMMATRIX M);
};
- 코드와 같이 XMMATRIX는 SIMD 활용을 위해 XMVECTOR 인스턴스 4개를 사용한다.
- XMMATRIX의 여러 생성자 외에 XMMatrixSet이라는 함수로도 인스턴스 생성이 가능하다.
XMMATRIX XM_CALLCONV XMMatrixSet(float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33);
- XMVECTOR를 클래스에 저장할 때 자료 멤버의 형식으로 XMFLOATn들을 사용하는것과 같이 XMMATRIX또한 XMFLOAT4X4 형식이 존재한다.
// 4x4 Matrix: 32 bit floating point components
struct XMFLOAT4X4
{
union
{
struct
{
float _11, _12, _13, _14;
float _21, _22, _23, _24;
float _31, _32, _33, _34;
float _41, _42, _43, _44;
};
float m[4][4];
};
XMFLOAT4X4() = default;
XMFLOAT4X4(const XMFLOAT4X4&) = default;
XMFLOAT4X4& operator=(const XMFLOAT4X4&) = default;
XMFLOAT4X4(XMFLOAT4X4&&) = default;
XMFLOAT4X4& operator=(XMFLOAT4X4&&) = default;
XM_CONSTEXPR XMFLOAT4X4(float m00, float m01, float m02, float m03,
float m10, float m11, float m12, float m13,
float m20, float m21, float m22, float m23,
float m30, float m31, float m32, float m33)
: _11(m00), _12(m01), _13(m02), _14(m03),
_21(m10), _22(m11), _23(m12), _24(m13),
_31(m20), _32(m21), _33(m22), _34(m23),
_41(m30), _42(m31), _43(m32), _44(m33) {}
explicit XMFLOAT4X4(_In_reads_(16) const float *pArray);
float operator() (size_t Row, size_t Column) const { return m[Row][Column]; }
float& operator() (size_t Row, size_t Column) { return m[Row][Column]; }
};
- 마찬가지로 XMFLOAT4X4과 같은 자료형식을 계산에 사용하면 SIMD의 장점을 취할 수 없다.
- 이를 해결하기 위해 계산 전에 XMMATRIX로 변환하고 계산 후에는 다시 XMFLOAT4X4으로 변환해야한다.
- 적재 함수 = XMMATRIX로 변환
- 저장 함수 = XMFLOAT4X4으로 변환
// 로드 함수
XMMATRIX XM_CALLCONV XMLoadFloat3x3(_In_ const XMFLOAT3X3* pSource);
XMMATRIX XM_CALLCONV XMLoadFloat4x3(_In_ const XMFLOAT4X3* pSource);
XMMATRIX XM_CALLCONV XMLoadFloat4x3A(_In_ const XMFLOAT4X3A* pSource);
XMMATRIX XM_CALLCONV XMLoadFloat3x4(_In_ const XMFLOAT3X4* pSource);
XMMATRIX XM_CALLCONV XMLoadFloat3x4A(_In_ const XMFLOAT3X4A* pSource);
XMMATRIX XM_CALLCONV XMLoadFloat4x4(_In_ const XMFLOAT4X4* pSource);
XMMATRIX XM_CALLCONV XMLoadFloat4x4A(_In_ const XMFLOAT4X4A* pSource);
// 적재 함수
void XM_CALLCONV XMStoreFloat3x3(_Out_ XMFLOAT3X3* pDestination, _In_ FXMMATRIX M);
void XM_CALLCONV XMStoreFloat4x3(_Out_ XMFLOAT4X3* pDestination, _In_ FXMMATRIX M);
void XM_CALLCONV XMStoreFloat4x3A(_Out_ XMFLOAT4X3A* pDestination, _In_ FXMMATRIX M);
void XM_CALLCONV XMStoreFloat3x4(_Out_ XMFLOAT3X4* pDestination, _In_ FXMMATRIX M);
void XM_CALLCONV XMStoreFloat3x4A(_Out_ XMFLOAT3X4A* pDestination, _In_ FXMMATRIX M);
void XM_CALLCONV XMStoreFloat4x4(_Out_ XMFLOAT4X4* pDestination, _In_ FXMMATRIX M);
void XM_CALLCONV XMStoreFloat4x4A(_Out_ XMFLOAT4X4A* pDestination, _In_ FXMMATRIX M);
2.3 행렬 함수
- DirectXMath 라이브러리에는 아래와 같은 행렬 관련 함수들이 존재한다.
// 단위행렬 I를 반환
XMMATRIX XM_CALLCONV XMMatrixIdentity();
// 단위행렬인지 판별여부 반환
bool XM_CALLCONV XMMatrixIsIdentity(FXMMATRIX M);
// 행렬 곱 AxB를 반환
XMMATRIX XM_CALLCONV XMMatrixMultiply(FXMMATRIX M1, CXMMATRIX M2);
// 입력된 행렬의 전치행렬 반환
XMMATRIX XM_CALLCONV XMMatrixTranspose(FXMMATRIX M);
// 행렬식 반환 ( 반환 자료형 = XMVECTOR )
// (det M, det M, det M, det M)
XMVECTOR XM_CALLCONV XMMatrixDeterminant(FXMMATRIX M);
// 역행렬 반환
// 입력 ( 행렬식, 행렬 )
XMMATRIX XM_CALLCONV XMMatrixInverse(_Out_opt_ XMVECTOR* pDeterminant, _In_ FXMMATRIX M);
- XMMATRIX 매개변수를 선언 할때에는 XMVECTOR의 규칙과 같은 규칙이 적용된다. 단 XMMATRIX 하나가 XMVECTOR 4개로 해당되는것이 다르다.
- FXMMATRIX : 첫 XMMATRIX 변수
- CXMMATRXI : 이후 XMMATRIX 변수
3. 예시 코드
#include <windows.h> // for XMVerifyCPUSupport
#include <DirectXMath.h>
#include <DirectXPackedVector.h>
#include <iostream>
using namespace std;
using namespace DirectX;
using namespace DirectX::PackedVector;
// Overload the "<<" operators so that we can use cout to
// output XMVECTOR and XMMATRIX objects.
ostream& XM_CALLCONV operator << (ostream& os, FXMVECTOR v)
{
XMFLOAT4 dest;
XMStoreFloat4(&dest, v);
os << "(" << dest.x << ", " << dest.y << ", " << dest.z << ", " << dest.w << ")";
return os;
}
ostream& XM_CALLCONV operator << (ostream& os, FXMMATRIX m)
{
for (int i = 0; i < 4; ++i)
{
os << XMVectorGetX(m.r[i]) << "\t";
os << XMVectorGetY(m.r[i]) << "\t";
os << XMVectorGetZ(m.r[i]) << "\t";
os << XMVectorGetW(m.r[i]);
os << endl;
}
return os;
}
int main()
{
// Check support for SSE2 (Pentium4, AMD K8, and above).
if (!XMVerifyCPUSupport())
{
cout << "directx math not supported" << endl;
return 0;
}
XMMATRIX A(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 2.0f, 0.0f, 0.0f,
0.0f, 0.0f, 4.0f, 0.0f,
1.0f, 2.0f, 3.0f, 1.0f);
XMMATRIX B = XMMatrixIdentity();
XMMATRIX C = A * B;
XMMATRIX D = XMMatrixTranspose(A);
XMVECTOR det = XMMatrixDeterminant(A);
XMMATRIX E = XMMatrixInverse(&det, A);
XMMATRIX F = A * E;
cout << "A = " << endl << A << endl;
cout << "B = " << endl << B << endl;
cout << "C = A*B = " << endl << C << endl;
cout << "D = transpose(A) = " << endl << D << endl;
cout << "det = determinant(A) = " << det << endl << endl;
cout << "E = inverse(A) = " << endl << E << endl;
cout << "F = A*E = " << endl << F << endl;
return 0;
}
참고 : DirectX 12 를 이용한 3D 게임 프로그래밍 입문 / 한빛미디어
'독학 > DirectX' 카테고리의 다른 글
[ DirectX ] Direct3D 기초 4. Direct3D의 초기화 (1) (0) | 2022.11.11 |
---|---|
[ DirectX ] 기초 수학 3. 변환 (0) | 2022.11.09 |
[ DirectX ] 기초 수학 1. 벡터 대수 (0) | 2022.11.09 |