6 minute read

1.6.DirectXMath 라이브러리

Window 8 이상에선 DirectXMath 라이브러리를 활용해 DiretX 응용 프로그램을 다룬다.

DirectXMath 라이브러리는 SSE2 명령 집합을 활용한다.

  • 128비트 너비의 SIMD 레지스터를 이용해 32비트 floatint 네 개를 하나의 명령에서 처리 가능함!


DirectXMath 라이브러리를 사용하기 위해 DirectXMath.h를 포함시켜야 한다. 추가 자료가 필요하다면 DirectXPackedVector.h 헤더 파일도 포함시켜보자.

  • DirectXMath.h의 코드는 DirectX의 이름 공간 안에 속함
  • DirectXPackedVector.h의 코드는 DirectX::PackedVector 이름 공간에 속함


1.6.1. 벡터 형식

  • XMVECTOR: DirectXMath의 핵심 벡터 형식
    • 32비트 부동소수점 값 네 개로 구성 => SIMD 명령으로 한 번에 처리
    • typedef __m1238 XMVECTOR로 정의됨
      • SIMD를 올바르게 활용되려면 벡터가 반드시 __m128 형식이어야 함!
  • 클래스 자료 멤버는 XMFLOAT2, XMFLOAT3, XMFLOAT4 변수 사용 권장
    • 지역/전역 변수는 자동으로 alignment가 이루어지므로 고려x
    • 단, 해당 구조체를 사용하면 SIMD를 제대로 활용하지 못하므로 형변환 필요
      • 계산 수행 전 적재(load) 함수를 활용해 XMVECTOR로 변환
      • 계산 수행 후 저장(store) 함수를 활용해 XMFLOATn으로 변환


1.6.2. 적재 및 저장 함수

XFLOATn → XMVECTOR 적재 ```c++ // XMFLOAT2 XMVECTOR XM_CALLCONV XMLoadFloat2(const XMFLOAT2 *pSource); // XMFLOAT3 XMVECTOR XM_CALLCONV XMLoadFloat3(const XMFLOAT3 *pSource); // XMFLOAT4 XMVECTOR XM_CALLCONV XMLoadFloat4(const XMFLOAT4 *pSource); ```


XMVECTOR → XFLOATn 저장 ```c++ // XMFLOAT2 void XM_CALLCONV XMStoreFloat2(XMFLOAT2 *pDestination, FXMVECTOR V); // XMFLOAT3 void XM_CALLCONV XMStoreFloat3(XMFLOAT3 *pDestination, FXMVECTOR V); // XMFLOAT4 void XM_CALLCONV XMStoreFloat4(XMFLOAT4 *pDestination, FXMVECTOR V); ```


XMVECTOR → XFLOATn 저장 ```c++ // XMFLOAT2 void XM_CALLCONV XMStoreFloat2(XMFLOAT2 *pDestination, FXMVECTOR V); // XMFLOAT3 void XM_CALLCONV XMStoreFloat3(XMFLOAT3 *pDestination, FXMVECTOR V); // XMFLOAT4 void XM_CALLCONV XMStoreFloat4(XMFLOAT4 *pDestination, FXMVECTOR V); ```


XMVECTOR의 특정 성분 조회/변경 ```c++ // 조회 float XM_CALLCONV XMVectorGetX(FXMVECTOR V); float XM_CALLCONV XMVectorGetY(FXMVECTOR V); float XM_CALLCONV XMVectorGetZ(FXMVECTOR V); float XM_CALLCONV XMVectorGetW(FXMVECTOR V); // 변경 float XM_CALLCONV XMVectorSetX(FXMVECTOR V); float XM_CALLCONV XMVectorSetY(FXMVECTOR V); float XM_CALLCONV XMVectorSetZ(FXMVECTOR V); float XM_CALLCONV XMVectorSetW(FXMVECTOR V); ```


1.6.3. 매개변수 전달

  • SSE/SSE2 레지스터를 활용해기 위해 플랫폼/컴파일러 의존성 제거
    • 함수 호출 시 XMVECTOR의 매개변수로 FMVECTOR, GXMVECTOR, HXMVECTOR, CXMVECTOR 형식 사용
    • 호출 규약 의존성을 없애기 위해 함수 이름 앞에 XM_CALLCONV 지시자 추가
  • XMVECTOR 매개변수 전달 규칙
    • 매개변수 ~세 번째 FXMVECTOR, 네 번째 GXMVECTOR, 다섯째, 여섯째 HXMVECTOR, 그 이상 CXMVECTOR 형식 지정
    • XMVECTOR 형식의 인수들을 받는 생성자를 작성할 때는 ~세 번째 FXMVECTOR, 나머지 CXMVECTOR 사용
      • 생성자에는 XM_CALLCONV 호출 규약 지시자를 사용하지 않음
  • 출력 XMVECTOR 매개변수는 SSE/SSE2 레지스터를 사용하지 않으므로 다른 매개변수들과 동일하게 취급
    • XMVECTOR&, XMVECTOR*


1.6.4. 상수 벡터

  • const XMVECTOR 인스턴스에는 반드시 XMVECTORF32 형식 사용
    • 중괄호 초기화 구문 등
  • XMVECTORF32: 16바이트 경계에 align되는 구조체
    • XMVECTOR0로의 변환 연산자 제공


1.6.7. 설정 함수

  • XMVECTOR 객체의 내용을 설정하는 용도


설정 함수 ```c++ // 0벡터 반환 XMVECTOR XM_CALLCONV XMVectorZero(); // 벡터 (1, 1, 1, 1) 반환 XMVECTOR XM_CALLCONV XMVectorSplateOne(); // 벡터 (x, y, z, w) 반환 XMVECTOR XM_CALLCONV XMVectorSet(float x, float y, float z, float w); // 벡터 (s, s, s, s) 반환 XMVECTOR XM_CALLCONV XMVectorReplicate(float value); // 벡터 (vx, vx, vx, vx) 반환 XMVECTOR XM_CALLCONV XMVectorSplatX(FXMVECTOR V); XMVECTOR XM_CALLCONV XMVectorSplatY(FXMVECTOR V); XMVECTOR XM_CALLCONV XMVectorSplatZ(FXMVECTOR V); ```


1.6.8. 벡터 함수들

  • 벡터 연산을 위한 함수 제공
    • 함수 이름 숫자에 따라 2,3,4 차원 벡터 구분
벡터 함수 ```c++ // ||v|| 반환 XMVECTOR XM_CALLCONV XMVector3Length(FMVECTOR V); // ||v||^2 반환 XMVECTOR XM_CALLCONV XMVector3LengthSq(FMVECTOR V); // v1 * v2 반환 XMVECTOR XM_CALLCONV XMVector3Dot(FMVECTOR V1, FMVECTOR V2); // v1 X v2 반환 XMVECTOR XM_CALLCONV XMVector3Cross(FMVECTOR V, FMVECTOR V2); // v / ||v|| 반환 XMVECTOR XM_CALLCONV XMVector3Normalize(FMVECTOR V); // v1과 v2 사이의 각도 반환 XMVECTOR XM_CALLCONV XMVector3AngleBetweenVectors(FXMVVECTOR V1, FXMVECTOR V2); void XM_CALLCONV XMVector3ComponentsFromNormal( XMVECTOR* pPrarllel, // proj_n(v) 반환 XMVECOTR* pPerpendicular, // perp_n(v) 반환 FXMVECTOR V, // 입력 v FXMVECTOR Normal); // 입력 n // v1 = v2 반환 bool XM_CALLCONV XMVector3Equal(FXMVECTOR V1, FXMVECTOR V2); // v1 != v2 반환 bool XM_CALLCONV XMVector3NotEqual(FXMVECTOR V1, FXMVECTOR V2); ```


예제 코드 ```c++ #include // XMVerifyCPUSupport에 필요 #include #include #include using namespace std; using namespace DirectX; using namespace DirectX::PackedVector; // XMVECTOR 객체를 cout으로 출력하기 위해 "<<" 연산자 중복 적재 ostream& XM_CALLCONV operator << (ostream& os, FXMVECTOR v) { XMFLOAT3 dest; XMStoreFloat3(&dest, v); os << "(" << dest.x << ", " << dest.y << ", " << dest.z << ")"; return os; } int main() { cout.setf(ios_base::boolalpha); // SSE2를 지원하는지 확인 if (!XMVerifyCPUSupport()) { cout << "directx math not supported" << endl; return 0; } XMVECTOR n = XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f); XMVECTOR u = XMVectorSet(1.0f, 2.0f, 3.0f, 0.0f); XMVECTOR v = XMVectorSet(-2.0f, 1.0f, -3.0f, 0.0f); XMVECTOR w = XMVectorSet(0.707f, 0.707f, 0.0f, 0.0f); // 벡터 덧셈: XMVECTOR operator + XMVECTOR a = u + v; // 벡터 뺄셈: XMVECTOR operator - XMVECTOR b = u - v; // 스칼라곱: XMVECTOR operator * XMVECTOR c = 10.0f * u; // ||u|| XMVECTOR L = XMVector3Length(u); // d = u / ||u|| XMVECTOR d = XMVector3Normalize(u); // 내적: s = u dot v XMVECTOR s = XMVector3Dot(u, v); // 외적: e = u x v XMVECTOR e = XMVector3Cross(u, v); // proj_n(w), perp_n(w) 구함 XMVECTOR projW; XMVECTOR perpW; XMVector3ComponentsFromNormal(&projW, &perpW, w, n); // projW + perpW == w? bool equal = XMVector3Equal(projW + perpW, w) != 0; bool notEqual = XMVector3NotEqual(projW + perpW, w) != 0; // prohW와 perpW 사이의 각도는 반드시 90도여야 함 XMVECTOR angleVec = XMVector3AngleBetweenVectors(projW, perpW); float angleRadians = XMVectorGetX(angleVec); float angleDegrees = XMConvertToDegrees(angleRadians); cout << "u = " << u << endl; cout << "v = " << v << endl; cout << "w = " << w << endl; cout << "n = " << n << endl; cout << "a = u + v = " << a << endl; cout << "b = u - v = " << b << endl; cout << "c = 10 * u = " << c << endl; cout << "d = u / ||u|| = " << d << endl; cout << "e = u x v = " << e << endl; cout << "L = ||u|| = " << L << endl; cout << "s = u.v = " << s << endl; cout << "projW = " << projW << endl; cout << "perpW = " << perpW << endl; cout << "projW + perpW == w = " << equal << endl; cout << "projW + perpW != w = " << notEqual << endl; cout << "angle = " << angleDegrees << endl; return 0; } ```

출력 결과 image </details>

> **<요약>** > > > > 1. 벡터는 크기와 방향을 모두 가진 물리적 수량을 나타내는 데 쓰임 > * 기하학적으로는 벡터를 지향 선분으로 표현 > * "표준 위치": 꼬리가 원점과 일치하도록 이동된 벡터 > * 표준 위치에 있는 벡터는 좌표계에 상대적인 그 머리의 좌표 성분을 이용해 수치적으로 서술 가능 > > > > 2. 벡터 $\mathbf{u} = (u_{x}, u_{y}, u_{z})$와 $\mathbf{v} = (v_{x}, v_{y}, v_{z})$에 대한 벡터 연산 > > * 덧셈: $\mathbf{u} + \mathbf{v} = (u_{x}+v_{x},\space u_{y}+v_{y}, \space u_{z}+v_{z})$ > > * 뺄셈: $\mathbf{u} - \mathbf{v} = (u_{x}-v_{x},\space u_{y}-v_{y}, \space u_{z}-v_{z})$ > > * 스칼라 곱셈: $k\mathbf{u} = (ku_{x}, \space ku_{y}, \space ku_{z})$ > > * 길이: $\lVert \mathbf{u} \rVert=\sqrt{x^{2} + y^{2} + z^{2} }$ > > * 정규화: $\hat{\mathbf{u}} = {\mathbf{u} \over \lVert \mathbf{u} \rVert} = ({x \over \lVert \mathbf{u} \rVert}, \space {y \over \lVert \mathbf{u} \rVert}, \space {z \over \lVert \mathbf{u} \rVert})$ > > * 내적: $\mathbf{u} \cdot \mathbf{v} = \lVert \mathbf{u} \rVert \space \lVert \mathbf{u} \rVert \cos\theta = u_{x}+v_{x},\space u_{y}+v_{y}, \space u_{z}+v_{z}$ > > * 외적: $\mathbf{u} \times \mathbf{v} = (u_{y}v_{z}-v_{z}u_{y}, \space u_{z}v_{x}-v_{x}u_{z}, \space u_{x}v_{y}-v_{y}u_{x}, \space)$ > > > > 3. 코드에서 벡터를 효율적으로 다루기 위해 DirectXMath의 `XMVECTOR` 형식 사용 > > * SIMD 연산들을 이용해 벡터를 효율적으로 처리함 > > * 클래스 자료 멤버: `XMFLOAT2`, `XMFLOAT3`, `XMFLOAT4` 클래스 사용 > > * 필요에 따라 적재 함수를 이용해 `XMVECTOR`로 변환 후 저장 함수를 이용해 다시 `XMFLOAT`n 으로 변환 > > * 초기화 구문을 이용해 상수 벡터를 정의할 때는 `XMVECTORF32` 형식을 사용해야 함 > > > > 4. `XMVECTOR` 인스턴스를 인수로 함수를 호출할 경우 > > * 효율성을 위해 SSE/SSE2 레지스터를 통해 함수에 전달(스택 사용X) > > * 플랫폼 독립적인 방식으로 처리하려면 `XMVECTOR` 매개변수에 `FMVECTOR`, `GXMVECTOR`, `HXMVECTOR` 형식 지정 > * 함수의 매개변수 ~세 번째 `FXMVECTOR`, 네 번째 `GXMVECTOR`, 다섯째, 여섯째 `HXMVECTOR`, 그 이상 `CXMVECTOR` > > > > 5. DirectXMath 라이브러리에서 중복적재된 연산자 제공 > > *벡터의 길이 및 길이 제곱 계산, 두 벡터의 내적과 외적 계산, 벡터 정규화를 위한 편의용 함수도 제공한다!* > ```c++ > XMVECTOR XM_CALLCONV XMVector3Length(FMVECTOR V); > XMVECTOR XM_CALLCONV XMVector3LengthSq(FMVECTOR V); > XMVECTOR XM_CALLCONV XMVector3Dot(FMVECTOR V1, FMVECTOR V2); > XMVECTOR XM_CALLCONV XMVector3Cross(FMVECTOR V, FMVECTOR V2); > XMVECTOR XM_CALLCONV XMVector3Normalize(FMVECTOR V); > ```

Updated:

Leave a comment