본문으로 바로가기

[DX12]1장 벡터 대수(DirectXMath)

category Computer Science/DirectX 2024. 2. 1. 23:47

1장 벡터 대수

(벡터의 수학적 내용보다는 DirectXMath 라이브러리의 위주로 작성.)

DirectXMath 라이브러리

  • Windows8 이상에서 Direct3D 응용 프로그램을 위한 표준적인 3차원 수학 라이브러리이며 Window SDK의 일부로 포함됨
  • SSE2(Streaming SIMD Extensions 2) 명령 집합을 활용.
    • SIMD 명령들은 128비트 너비의 SIMD(single instruction multiple data) 레지스터들을 이용해서 32비트 float 또는 int 4개를 하나의 명령으로 처리
    • X86에서 SSE2 명령을 사용하기 위해서는 별도 옵션 지정 필요.
  • 사용하는 벡터의 형식은 XMVECTOR와 XMFLOAT2,3,4 가 있다.

DirectXMath에서 벡터 자료형

DirectXMath 에서 벡터를 다루는 자료형은 XMVECTOR와 XMFLOAT2, XMFLOAT3, XMFLOAT4 존재.

XMVECTOR

  • SIMD 하드웨어 레지스터에 대응되는 벡터 타입으로 XMVECTOR 간의 연산은 하드웨어에서 단일 연산으로 처리됨.
typedef __m128 XMVECTOR;
  • 2차원 3차원 벡터의 경우도 128비트 XMVECTOR를 사용하면 SIMD의 장점 사용 가능
    • 2차원 3차원 벡터에서 사용하지 않는 성분은 0으로 설정
  • XMVECTOR 간의 연산은 하드웨어에서 단일 연산으로 처리됨
  • 16바이트 단위로 Alignment 되기 때문에 클래스나 구조체의 멤버변수의 타입으로 사용되는 것은 권장되지 않는다.
    • 멤버 변수에 저장할 때는 아래의 XMFLOATn 타입을 사용
    • Alignment 에대한 설명은 해당 게시글을 참고.

XMFLOAT2, XMFLOAT3, XMFLOAT4

  • 각각 2,3,4개의 float으로 구성되어 있는 구조체로 XMVECTOR를 클래스나 구조체의 멤버로 저장할 때 변환하여 사용
  • 연산을 할때는 XMVECTOR로 변환해야 SIMD 하드웨어 지원을 받음.

XMVECTOR와 XMFLOAT- 타입 간의 변환 함수

  • XMVECTOR와 XMFLOATn 타입 간에는 변환이 가능하며 Window SDK의 DirectXMathConvert.inl에 관련 함수들 존재

XMVECTOR의 값 Set / Get 함수

  • XMVECTOR의 전체값 혹은 특정 값만 설정하거나 읽을 수 있으며 Window SDK의 DirectXMathVector.inl에 관련 함수들 존재

상수 벡터

  • 상수 XMVECTOR 인스턴스에는 반드시 XMVECTORF32 형식 또는 XMVECTORU32을 사용해야 한다.
    • XMVECTORF32: 실수 형식
    • XMVECTORU32: 정수 형식
  • 예시
XMGLOBALCONST XMVECTORF32 g_XMOne = { { { 1.0f, 1.0f, 1.0f, 1.0f } } }; XMGLOBALCONST XMVECTORU32 g_XMMaskY = { { { 0x00000000, 0xFFFFFFFF, 0x00000000, 0x00000000 } } };

함수 호출 규칙

XMVECTOR 인스턴스를 인수로 해서 함수를 호출할 때, 효율성을 위해서는 XMVECTOR 값이 스택이 아니라 SSE/SSE2 레지스터를 통해서 함수에 전달되게 해야 한다. 그런 식으로 전달할 수 있는 인수의 개수는 플랫폼과 컴파일러에 따라 다르다. 플랫폼/컴파일러 의존성을 없애기 위해서 몇 가지 규칙이 존재.

XM_CALLCONV

  • SSE/SSE2 레지스터 활용을 위한 호출 규약 역시 컴파일러에 따라 다를 수 있다.
  • 컴파일러 의존성을 없애려면 함수 이름 앞에 반드시 XM_CALLCONV 라는 호출 규약 지시자(매크로)를 붙여야 한다.

XMVECTOR 매개변수의 전달에 관한 규칙

  1. 처음 세 XMVECTOR 매개변수에는 반드시 FXMVECTOR 형식을 지정해야한다.
  2. 넷째 XMVECTOR 매개변수에는 반드시 GXMVECTOR 형식을 지정해야 한다.
  3. 다섯째와 여섯째 XMVECTOR 매개변수에는 반드시 HXMVECTOR 형식을 지정해야 한다.
  4. 그 이상의 XMVECTOR 매개변수들에는 반드시 CXMVECTOR 형식을 지정해야 한다.
  5. XMVECTOR 매개변수들 사이에 XMVECTOR가 아닌 매개변수가 끼어 있을 경우 XMVECTOR 매개 변수들만 세어서 규칙을 적용한다.

예시

  • XM_CALLCONV와 XMVECTOR 규칙을 적용한 예시. (DirectXMath 라이브러리의 코드 중 일부)
XMMATRIX XM_CALLCONV XMMatrixTransformation(
    FXMVECTOR ScalingOrigin, 
    FXMVECTOR ScalingOrientationQuaternion, 
    FXMVECTOR Scaling, 
    GXMVECTOR RotationOrigin, 
    HXMVECTOR RotationQuaternion, 
    HXMVECTOR Translation) noexcept

생성자의 호출 규칙

생성자는 일반 함수들과 다른 규칙이 적용됨

  1. 처음 세 XMVECTOR 매개변수에는 FXMVECTOR를 사용
  2. 나머지에는 CXMVECTOR를 사용
  3. XM_CALLCONV 호출 규약 지시자를 사용하지 않음
(참고) 위 규칙으로 플랫폼/컴파일 의존성이 제거되는 이유

FXMVECTOR, GXMVECTOR, HXMVECTOR, CXMVECTOR는 각 플랫폼과 컴파일러의 상황에 맞게 타입이 정의되어서 사용된다. 예를 들어 32비트 Windows에서 __fastcall 호출 규약을 지원하는 컴파일러와 __vectorcall 호출 규약을 지원하는 컴파일러는 이 형식들을 다음과 같이 정의.

//__fastcall은 처음 세 XMVECTOR 인수를 레지스터들을 통해서 전달. 나머지는 스택을 사용
typedef const XMVECTOR FXMVECTOR;    // 1, 2, 3
typedef const XMVECTOR& GXMVECTOR;  // 4
typedef const XMVECTOR& HXMVECTOR;  // 5, 6
typedef const XMVECTOR& CXMVECTOR;  // 그 이상

// __vectorcall은 처음 여섯 XMVECTOR 인수를 레지스터들을 통해서 전달하고, 나머지는 스택을 사용
typedef const XMVECTOR FXMVECTOR;  // 1, 2, 3
typedef const XMVECTOR GXMVECTOR;  // 4
typedef const XMVECTOR HXMVECTOR;  // 5, 6
typedef const XMVECTOR& CXMVECTOR; // 그 이상

 


출처:

한빛미디어 출판 <DirectX 12를 이용한 3D 게임 프로그래밍 입문>