Direct3D에는 XNA Math라는 벡터 수학 라이브러리를 제공한다.
코드에서 XNA Math 라이브러리를 사용하려 할 때 헤더 파일 xnamath.h를 포함시키만 하면 된다.
학원에서 했던 프레임워크는 xnmath.h대신 d3dx10.h를 사용했다.
1.벡터 형식들
XNA Math에서 핵심 벡터 형식은 SIMD 하드웨어 레지스터들에 대응되는 XMVECTOR이다. 이 128bit짜리 형식은 하나의 SIMD 명령으로 처리되는 네 개의 32bit 부동소수점 값들로 이뤄져있다. XMVECTOR는 16byte 경계에 정렬되어야 하는데, 지역 변수와 전역 변수에는 정렬이 자동으로 이뤄진다. 클래스 자료 멤버의 경우 XMFLOAT2, XMFLOAT3, XMFLOAT4를 사용하는 것이 바람직하다.
typedef struct _XMFLOAT2
{
FLOAT x;
FLOAT y;
} XMFLOAT2;
typedef struct _XMFLOAT3
{
FLOAT x;
FLOAT y;
FLOAT z;
} XMFLOAT3;
typedef struct _XMFLOAT4
{
FLOAT x;
FLOAT y;
FLOAT z;
FLOAT w;
} XMFLOAT4;
그러나 이 형식들을 계산에 직접 사용하려면 SIMD의 장점을 취하지 못하므로, 이 형식의 인스턴스를 XMVECTOR 형식으로 변환할 필요가 있다. 이를 위해 XNA Math는 여러 적재 함수들을 제공한다.
내용을 정리해보자
1.지역 변수와 전역 변수에 대해서는 XMVECTOR를 사용한다.
2.클래스 자료 멤버에는 XMFLOAT2나 XMFLOAT3, XMFLOAT4를 사용한다.
3.계산을 수행하기 전에 적재 함수들을 이용해서 XMFLOAT*를 XMVECTOR로 변환한다.
4.계산은 XMVECTOR 인스턴스들을 이용해서 수행한다.
5.XMVECTOR를 XMFLOAT*로 변환하려면 저장 함수들을 사용한다.
2.적재 및 저장 함수들
XMFLOAT*의 자료를 XMVECTOR로 적재하는 함수와 XMVECTOR의 자료를 XMFLOAT*로 저장하는 함수들
XMVECTOR XMLoadFloat2(CONST XMFLOAT2* pSource); //XMFLOAT2를 XMVECTOR에 적재
XMVECTOR XMLoadFloat3(CONST XMFLOAT3* pSource); //XMFLOAT3를 XMVECTOR에 적재
XMVECTOR XMLoadFloat4(CONST XMFLOAT4* pSource); //XMFLOAT4를 XMVECTOR에 적재
VOID XMStoreFloat2(XMFLOAT2* pDestination, FXMVECTOR V); //XMVECTOR를 XMFLOAT2로 저장
VOID XMStoreFloat3(XMFLOAT3* pDestination, FXMVECTOR V); //XMVECTOR를 XMFLOAT3로 저장
VOID XMStoreFloat4(XMFLOAT4* pDestination, FXMVECTOR V); //XMVECTOR를 XMFLOAT4로 저장
XMVECTOR 인스턴스의 성분 하나만 읽거나 변경하고 싶을 때 사용하는 함수들
FLOAT XMVectorGetX(FXMVECTOR V); //XMVECTOR로 부터 x성분 하나만 반환
FLOAT XMVectorGetY(FXMVECTOR V); //XMVECTOR로 부터 Y성분 하나만 반환
FLOAT XMVectorGetZ(FXMVECTOR V); //XMVECTOR로 부터 Z성분 하나만 반환
FLOAT XMVectorGetW(FXMVECTOR V); //XMVECTOR로 부터 W성분 하나만 반환
XMVECTOR XMVectorSetX(FXMVECTOR V, FLOAT x); //XMVECTOR의 x성분 변경
XMVECTOR XMVectorSetY(FXMVECTOR V, FLOAT y); //XMVECTOR의 Y성분 변경
XMVECTOR XMVectorSetZ(FXMVECTOR V, FLOAT z); //XMVECTOR의 Z성분 변경
XMVECTOR XMVectorSetW(FXMVECTOR V, FLOAT w); //XMVECTOR의 W성분 변경
3.매개변수 전달
SIMD의 장점을 취하려면 함수에 XMVECTOR 형식의 매개변수를 전달할 때 지켜야 할 규칙이 있다.
플랫폼 독립적인 코드를 위해 XMVECTOR 형식의 매개변수에 대해 CXMVECTOR 형식과 FXMVECTOR 형식을 사용한다.
//32bit Windows 환경
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
//64bit Windows 환경
typedef const XMVECTOR& FXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
눈에 보이는 차이는 값으로 전달과 참조로 전달이 보인다.
1.한 함수의 처음 세 개의 XMVECTOR 매개변수는 반드시 FXMVECTOR 형식이여야 한다. 그 외의 XMVECTOR 매개변수는 반드시 CXMVECTOR 형식이어야 한다.
XMINLINE XMMATRIX XMMatrixTransformation(
FXMVECTOR ScalingOrigin, FXMVECTOR ScalingOrientationQuaternion, FXMVECTOR Scaling,
CXMVECTOR RotationOrigin, CXMVECTOR RotationQuaternion, CXMVECTOR Translation);
이 함수는 규칙에 따라 처음 세 개는 FXMVECTOR를 사용하고 나머지는 CXMVECTOR를 사용한다.
XMVECTOR 매개변수 사이에 XMVECTOR이 아닌 매개변수가 끼어 있을 수 있다. 그런 경우에도 처음 세 개는의XMVECTOR 매개변수는 반드시 FXMVECTOR 형식이여야 하고, 나머지 XMVECTOR 매개변수는 CXMVECTOR 형식이어야 한다.
XMINLINE XMMATRIX XMMatrixTransformation2D(
FXMVECTOR ScalingOrigin,
FLOAT ScalingOrientationQuaternion,
FXMVECTOR Scaling,
FXMVECTOR RotationOrigin,
FLOAT Rotation,
CXMVECTOR Translation);
4.상수 벡터
상수 XMVECTOR 인스턴스에는 반드시 XMVECTOR32 형식을 사용해야 한다.
static const XMVECTOR32 g_vHalfVector = {0.5f, 0.5f, 0.5f, 0.5f};
static const XMVECTOR32 g_vZero = {0.0f, 0.0f, 0.0f, 0.0f};
XMVECTOR32 vRightTop = {vViewFrust.RightSlop, vViewFrust.TopSlope, 1.0f, 1.0f};
XMVECTOR32 vLeftBottom = {vViewFrust.LeftSlop, vViewFrust.BottomSlope, 1.0f, 1.0f};
간단히 말하면, 초기화 구문을 사용하고자 할 때에는 항상 XMVECTOR32을 사용해야 한다. XMVECTOR32는 16byte 경계로 정렬된 구조로, XMVECTOR로의 변환 연산자를 지원한다.
5.중복적재된 연산자들
XMVECTOR에는 벡터 덧셈, 뺄셈, 스칼라 곱셈을 위해 중복적재된(overloaded) 연산자들이 있다. 중복적재를 비활성화하면 복잡한 표현식을 형성할 때 함수 버ㅈ전이 더 빠를 수 있기 때문이다. 중복적재를 비활성화하고 싶다면 매크로 상수 XM_NO_OPERATOR_OVERLOADS를 정의해 주면 된다.

6.기타 상수 및 함수
XNA Math 라이브러리는 다양한 공식에 유용한 여러 근삿값들을 매크로 상수로 정의해 뒀다.
#define XM_PI 3.141592654f
#define XM_2PI 6.283185307f
#define XM_1DIVPI 0.318309886f
#define XM_1DIV2PI 0.159154943f
#define XM_PIDIV2 1.570796327f
#define XM_PIDIV4 0.785398163f
또한 라디안(radian) 단위 각도와 도(degree) 단위 각도의 변환도 인라인 함수들로 제공한다.
//Degree에서 Radian로 변환
XMFINLINE FLOAT XMConvertToRadians(FLOAT fDegrees)
{ return fDegrees * (XM_PI / 180.0f); }
//Radian에서 Degree로 변환
XMFINLINE FLOAT XMConvertToDegrees(FLOAT fRadians)
{ return fRadians * (180.0f / XM_PI); }
//최솟값 최대값 매크로 함수
#define XMMin(a, b) (((a) < (b)) ? (a) : (b))
#define XMMax(a, b) (((a) > (b)) ? (a) : (b))
7.설정 함수
XNA Math 라이브러리는 XMVECTOR 객체의 내용을 설정하는 용도로 사용할 수 있는 함수들을 제공한다.
XMVECTOR XMVectorZero(); //영벡터 0을 반환
XMVECTOR XMVectorSplatOne(); //벡터(1,1,1,1)를 반환
XMVECTOR XMVectorSet(FLOAT x, FLOAT y, FLOAT z, FLOAT w); //벡터(x,y,z,w)를 반환
XMVECTOR XMVectorReplicate(FLOAT s); //벡터(s,s,s,s)를 반환
XMVECTOR XMVectorSplatX(FXMVECTOR V); //벡터(vx,vx,vx,vx)를 반환
XMVECTOR XMVectorSplatY(FXMVECTOR V); //벡터(vy,vy,vy,vy)를 반환
XMVECTOR XMVectorSplatZ(FXMVECTOR V); //벡터(vz,vz,vz,vz)를 반환
8.벡터 함수들
XNA Math 라이브러리는 다양한 벡터 연산을 위한 함수들을 제공한다.
XMVECTOR XMVector3Length(FXMVECTOR V); //||V|| 반환
XMVECTOR XMVector3LengthSq(FXMVECTOR V); //||V||의 제곱 반환
XMVECTOR XMVector3Dot(FXMVECTOR V1, FXMVECTOR V2); //V1과 V2의 내적 반환
XMVECTOR XMVector3Cross(FXMVECTOR V1, FXMVECTOR V2); //V1과 V2의 외적 반환
XMVECTOR XMVector3Normalize(FXMVECTOR V); //V/||V|| 반환
XMVECTOR XMVector3Orthogonal(FXMVECTOR V); //V에 직교인 벡터 반환
XMVECTOR XMVector3AngleBetweenVectors(FXMVECTOR V1, FXMVECTOR V2); //V1과 V2 사이의 각도 반환
//projn(v), prepn(v) 변경
VOID XMVector3ComponentsFromNormal(
XMVECTOR* pParallel, XMVECTOR* pPerperndicular,
FXMVECTOR V, FXMVECTOR Normal);
BOOL XMVector3Equal(FXMVECTOR V1, FXMVECTOR V2); //v1 == v2의 참/거짓 결과 반환
BOOL XMVector3NotEqual(FXMVECTOR V1, FXMVECTOR V2); //v1 != v2의 참/거짓 결과 반환
위 코드는 3차원 벡터를 위한 함수인데 2차원, 4차원 벡터는 Vector3대신 Vector2, Vector4로 준비되어 있다.
9.부동소수점 오차
부동소수점 수들을 비교할 떄에는 부동소수점의 오차를 인지해야 한다(Epsilon). 그렇기에 부동소수점 수의 상등을 판정할 때에는 두 수가 근사적으로 같은지를 봐야한다.
const float Epsilon = 0.001f;
bool Equals(float lhs, float rhs)
{ return fabs(lhs - rhs) < Epsilon ? true : false; }
XNA Math 라이브러리에는 두 벡터의 상등을 판정한느 XMVector3NearEqual이라는 함수가 있다.
//abs(U.x - V.x) <= Epsilon.x &&
//abs(U.y - V.y) <= Epsilon.y &&
//abs(U.z - V.z) <= Epsilon.z
XMFINLINE BOOL XMVector3NearEqual(FXMVECTOR U, FXMVECTOR V, FXMVECTOR Epsilon);
'서적 정리 > DirectX11을 이용한 3D 게임 프로그래밍 입문' 카테고리의 다른 글
10.행렬의 전치 (0) | 2022.01.20 |
---|---|
9.행렬 곱셈 (0) | 2022.01.20 |
8.행렬 정의 (0) | 2022.01.20 |
7.벡터 대수 요약 (0) | 2022.01.20 |
5.점 (0) | 2022.01.04 |
4.외적 (0) | 2022.01.04 |
3.내적 (0) | 2022.01.04 |
2.길이와 단위벡터 (0) | 2022.01.04 |
댓글