DirectX12 #1 [DirectXMath 라이브러리 벡터]

황재진·2022년 8월 11일
0
post-thumbnail

DirectX12에서 사용하는, 엄밀히는 Windows SDK의 일부인 DirectXMath의 벡터에 대해 알아보겠습니다.


DirectXMath 라이브러리

먼저, 이 라이브러리는 SSE2(Streaming SIMD Extensions 2) 명령집합을 사용합니다.
SIMD 명령들은 128비트 너비의 SIMD(Single Instruction Multiple Data) 레지스터들을 이용해 32비트 float 또는 int 네 개를 하나의 명령에서 처리할 수 있습니다.
즉, 벡터 연산에 아주 유용합니다.

SMID : 병렬컴퓨팅의 한 종류로 하나의 명령으로 여러 값을 동시에 계산하는 방식

u+v=(ux+vx,uy+vy,uz+vz)u+v=(u_x+v_x,u_y+v_y,u_z+v_z)

다음과 같은 벡터 연산을 스칼라 명령 4개가 아니라 SIMD 명령 하나로 처리할 수 있습니다.

x86 플랫폼에서는 SSE2를 활성화해야 하지만 x64 CPU는 모두 SSE2를 지원해 따로 활성화할 필요 없습니다.


벡터 형식들

SIMD 하드웨어 레지스터에 대응되는 XMVECTOR가 핵심 벡터 형식입니다.

XMVECTOR는 32비트의 부동소수점 값 4개로 구성되어있고
x64, SSE 활성화 x86 플랫폼에서 아래와 같이 정의됩니다

typedef __m128 XMVECTOR;

__m128 SIMD 형식을 사용해야만 벡터 연산 시 SIMD의 장점이 발휘됩니다.

2차원 3차원 벡터에서는 사용하지 않는 성분을 0으로 설정해서 무시하면 됩니다.

  • XMVECTOR는 16바이트 경계에 정렬(alignment)되어야 하는 제약이 있습니다.
    • 로컬 변수는 스택에, 전역 변수는 데이터 섹션에 자동으로 정렬하고 배치하지만, 힙에서 할당하는 것은 주의해야 한다. x64에서는 모든 힙이 16바이트로 할당되지만, x86은 8바이트입니다.

    • 지역변수와 전역변수는 정렬이 자동으로 일어나 상관없지만, 클래스 멤버변수에는 이 형식 대신 XMFLOAT2, XMFLOAT3, XMFLOAT4를 사용하는 것이 권장됩니다.

      그러나 이 형식들(XMFLOAT2, 3, 4)을 사용하면 SIMD의 장점을 가져갈 수 없으므로 이 형식들을 XMVECTOR로 변환해야 합니다,

      이러한 FLOATn 형식을 XMVECTOR로 바꿔주는 적재함수XMVECTOR 형식을 FLOATn으로 바꿔주는 저장함수를 DirectXMath에서 제공합니다.

매개변수 전달

XMVECTOR 인스턴스를 인수로 함수를 호출할 때 효율성을 위해 값이 스택이 아니라 SSE/SSE2 레지스터를 통해 함수에 전달되게 해야 합니다.

전달할 수 있는 인수의 개수가 플랫폼과 컴파일러에 따라 달라 의존성을 없애기 위해 FXMVECTOR, GXMVECTOR, HXMVECTOR, CXMVECTOR 형식을 사용해야 합니다.

컴파일러에 대한 제약을 없애기 위해 XM_CALLCONV라는 호출규약 지시자를 함수 이름 앞에 붙여야 합니다.

  • XMVECTOR 매개변수 전달 규칙
    • 처음 세 매개변수 : FXMVECTOR
    • 넷째 매개변수 : GXMVECTOR
    • 다섯, 여선째 매개변수 : HXMVECTOR
    • 그 이상 매개변수 : CXMVECTOR

입력 매개변수들에게 적용되는 규칙이며, 출력에는 SSE/SSE2 레지스터를 사용하지 않습니다.

상수 벡터

상수 XMVECTOR 인스턴스에는 반드시 XMVECTORF32 형식을 사용해야 합니다.

static const XMVECTORF32 s_vecEye = { 100.0f, 5.0f, 5.0f, 0.f };

정수 자료를 담은 상수 XMVECTOR를 생성하려면 XMVECTORU32를 사용하면 됩니다.

설정 함수

XMVECTOR 객체의 내용을 설정하는 용도로 사용합니다.

  • 함수 예시
    • XMVectorZero() → 0벡터 반환

    • XMVectorSplatOne() → 벡터 (1,1,1,1)를 돌려준다

    • XMVectorSet(float x, float y, float z, float w) → 벡터 (x,y,z,w)를 돌려준다

      등등..

추정 함수

계산이 덜 정확하지만 속도가 더 빠른 함수들을 지원합니다.

  • 함수 예시
    • XMVector3LengthEst(FXMVECTOR v) → 추정된 v||v||를 반환한다

      Est가 붙은 함수들은 보통 추정 함수입니다.

부동소수점 오차

부동소수점 수들을 비교할 때 부동소수점의 부정확함을 고려해야 합니다.

예를 들어, 정규화된 벡터의 길이는 수학적으로 1이여야 하지만, 부동소수점 연산에서 오차가 발생합니다.

이러한 이유 때문에 부동소수점 수의 상등을 판정할 때에는 두 수가 근사적으로 동일한지 봐야 하비다.

const float Epsilon = 0.001f;
bool Equals(float lhs, float rhs)
{
	// lhs와 rhs간의 차지아 Epsilon보다 작은가?
	return fabs(lhs - rhs) < Epsilon ? true : false;
}
  • Unity C#의 Mathf.Approximately도 비슷한 기능을 합니다.

참고자료

XMVectorZero function (directxmath.h) - Win32 apps

DirectXMath.h 함수 레퍼런스

profile
프로그래밍, 쉐이더 등 이것저것 다해보는 게임 개발자입니다

0개의 댓글