XNA Math 라이브러리와 XMVECTOR
Direct3D 11의 D3DX 라이브러리에는 Direct3D 9와 10의 D3DX와는 다르게 개별적으로 개발된
XNA Math 라는 벡터 수학 라이브러리가 제공된다.
SIMD의 명령들은 128비트 너비의 SIMD(Single instruction multiple data) 레지스터들을 이용해서 한 명령에서 32비트 float나 int 네 개를 한 번에 처리할 수 있다. 이는 벡터 계산에 아주 유용하다.
SIMD가 아닌 경우에는 32-비트의 실수를 4번 더해야 하지만 벡터의 덧셈 시 SIMD를 이용하면 두 개의 4요소 벡터(Vector4) 를 더할 경우 한 번의 덧셈 명령으로 처리가 가능하다는 것이다.
SIMD?
병렬 프로세서의 한 종류로, 하나의 명령어로 여러 개의 값을 동시에 계산하는 방식, 컴퓨터를 일컫는다.
SSE (Streaming SIMD Extensions)는 이런 SIMD 구조의 명령을 프로세서에 도입한 것으로 128bit짜리 SIMD 전용 레지스터가 추가된 것이다.
◎ 사용
코드에서 이 라이브러리를 사용하려면 헤더파일 xnamath.h를 추가하기만 하면 된다.
#include <xnamath.h>
모든 코드가 헤더 파일 안에 inline으로 구현되어 있으므로 라이브러리 파일을 따로 링크할 필요가 없다.
물론 <d3dx10.h>를 포함시키고 <d3dx10.lib>를 링크해서 XNA Math 라이브러리 대신에 D3DX10 Math 함수들을 사용하는 것도 여전히 가능하다.
◎ 벡터 형식들
XNA Math에서 핵심 벡터 형식은 SIMD 하드웨어 레지스터들에 대응되는 XMVECTOR이다.
XMVECTOR는 하드웨어 레지스터에 대응하는 32-비트의 실수 벡터로 32-비트 실수 또는 정수 요소들의 벡터를 표현하기 위한 '자료형'이다. (구조체가 아니다.)
추가로 덧붙이자면 뒤에 나오는 XMMATRIX는 구조체이다.
XMVECTOR는 128비트짜리 형식으로 하나의 SIMD 명령으로 처리되는 네 개의 32비트 부동소수점 값들로 이루어져있다.
SSE2를 사용할 수 있는 경우에서 XMVECTOR는
typedef __m128 XMVECTOR;
위와 같이 정의되어 있다.
__m128?
특별한 SIMD 형식으로 계산을 수행할 때 이 형식의 벡터들은 반드시 SIMD의 장점을 갖고 연산을 할 수 있다.
이 XMVECTOR는 사용할 때 16바이트 경계에 정렬되어야 한다.
왜냐하면 정렬이 되어있어야 SIMD 명령어를 이용해 데이터를 벡터에 패킹하여 한 번의 명령으로 동시에 처리할 수 있기 때문이다.
이 정렬은 지역 변수와 전역 변수에는 정렬이 자동으로 이루어지게 된다.
그러나 class의 멤버나 구조체의 멤버변수의 경우에는 이것 보다는 XMFLOAT를 사용하는 것이 더 바람직하다.
왜?
(Microsoft Docs의 DirectXMath 中)
SIMD 처리는 데이터를 SIMD 레지스터에 load하고 결과를 추출하기 전에 완전히 처리할 때 가장 효율적이다.
SIMD processing is most efficient when data is loaded into the SIMD registers and fully processed before extracting the results.
스칼라와 벡터 형식 간의 변환은 비효율적이므로 필요할 때만 수행하는 것이 좋다.
Conversion between scalar and vector forms is inefficient, so we recommend that you do it only when required.
이러한 이유로 스칼라 값을 생성하는 DirectXMath 라이브러리의 함수는 스칼라 결과가 결과 벡터에 복제되는 벡터 형태로 리턴된다.
For this reason, functions in the DirectXMath library that produce a scalar value are returned in a vector form where the scalar result is replicated across the resulting vector
그래서 스칼라 값이 필요한 경우에 이와 같은 내용을 수행하는 방법에 대한 몇 가지 선택사항으로 XMFLOAT를 이용해 벡터를 메모리 구조에 저장하고 다시 읽어오는 방식을 사용.
typedef struct _XMFLOAT3
{
FLOAT x;
FLOAT y;
FLOAT z;
} XMFLOAT3;
예를 들면 XMFLOAT3(3차원)은 위와 같이 정의한 후 사용한다.
XMVECTOR나 XMMATRIX는 operator(연산자)들이 오버로드 되어있지만 XMFLOAT를 이용해 사용하는 경우 추가로 생성자들이나 연산자 관련 함수를 추가해 준다.
이 XMFLOAT를 이용한 형식은 계산할 때 SIMD의 장점을 갖고 연산할 수가 없으므로 SIMD를 이용하고 싶으면 이 형식의 인스턴스를 XMVECTOR 형식으로 변환해줘야 한다.
이를 위해 XNA Math는 여러 함수를 제공한다.
또한 XNA Math는 XMVECTOR 인스턴스에 담긴 자료를 XMFLOAT* 형식들로 변환하는 저장 함수들도 제공한다.
간략정리
간략정리
1. 지역 변수와 전역 변수에서는 XMVECTOR를 이용
2. 클래스 자료 멤버에는 XMFLOAT2나 XMFLOAT3, XMFLOAT4를 사용
3. 계산 수행 전 함수들을 이용해 XMFLOAT*를 XMVECTOR로 변환
4. '계산'은 XMVECTOR 인스턴스들을 이용해서 수행
5. XMVECTOR를 XMFLOAT*로 변환하려면 저장 함수들을 이용
◎ 적재 및 저장 함수
- XMFLOAT*의 자료를 XMVECTOR로 적재(Load)하는 함수
XMVECTOR XMLoadFloat2 (Const XMFLOAT2 *pSource);
XMVECTOR XMLoadFloat3 (Const XMFLOAT3 *pSource);
XMVECTOR XMLoadFloat4 (Const XMFLOAT4 *pSource);
이외에도 Color나 UINT 배열을 XMVECTOR에 load하는 함수들도 존재한다.
- XMVECTOR의 자료를 XMFLOAT*로 저장(Store)하는 함수
FLOAT XMVectorGetX (FXMVECTOR V);
FLOAT XMVectorGetY (FXMVECTOR V);
FLOAT XMVectorGetZ (FXMVECTOR V);
FLOAT XMVectorGetW (FXMVECTOR V);
XMVECTOR XMVectorSetX (FXMVECTOR V, FLOAT x);
XMVECTOR XMVectorSetY (FXMVECTOR V, FLOAT y);
XMVECTOR XMVectorSetZ (FXMVECTOR V, FLOAT z);
XMVECTOR XMVectorSetW (FXMVECTOR V, FLOAT w);
◎ 매개변수 전달과 상수 벡터
SIMD의 장점을 이용하려면 함수에 XMVECTOR 형식의 매개변수를 전달할 때 지켜야 할 규칙이 있다.
이 규칙들은 플랫폼바다 다른데 플랫폼 독립적 코드를 위해 XMVECOTR 형식의 매개변수에 대해 CXMVECTOR, FXMVECTOR 형식을 사용한다.
Windows의 경우
// 32비트 Windows
typedef const XMVECTOR FXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
//64비트 Windows
typedef const XMVECTOR& FXMVECTOR;
typedef const XMVECTOR& CXMVECTOR;
이 둘의 차이는 XMVECTOR의 복사본을 직접 전달할 수 있는지, 참조를 전달해야 하는지이다.
구체적인 또 하나의 규칙은 한 함수의 처음 세 개의 XMVECTOR 매개변수는 반드시 FXMVECTOR형식이어야 한다. 그 외의 XMVECTOR 매개변수는 반드시 CXMVECOTR 형식이여야 한다.
예를 들어 7개의 매개변수를 받는 함수가 있으면 위의 규칙에 따라 처음 세 개는 FXMVECTOR, 나머지 네 개는 CXMVECOTR 형식이어야 하며 XMVECTOR 매개변수들 사이에 다른 매개변수가 끼어있을 경우에도 처음 세 개의 XMVECTOR 매개변수는 반드시 FXMVECTOR 형식이고 나머지 XMVECTOR 매개변수는 CXMVECOTR 형식이어야 한다.
또한 상수(const) XMVECTOR 인스턴스에는 반드시 XMVECTORF32 형식을 사용해야 한다.
초기화 구문을 사용하고자 할 때에는 항상 XMVECTORF32를 사용해야 한다.
XMVECTORF32는 16바이트 경계로 정렬된 구조체로, XMVECTOR로의 변환 연산자를 지원한다.
◎ 기타 제공 함수
XNA Math 라이브러리는 XMVECTOR를 이용한 벡터 덧셈, 뺄셈, 스칼라 곱셈을 위해 중복적재된 연산자들을 제공한다.
또한 XNA Math 라이브러리는 벡터의 길이, 벡터 길이의 제곱, 두 벡터의 내적, 두 벡터의 외적, 벡터 정규화를 위한 편의용 함수들도 제공한다.
XMVECTOR XMVector3Length(FXMVECTOR V);
XMVECTOR XMVector3LengthSq(FXMVECTOR V);
XMVECTOR XMVector3Dot (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR XMVector3Cross (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR XMVector3Normalize (FXMVECTOR V);
참고 출처;
- https://ko.wikipedia.org/wiki/SIMD
- Direct11을 이용한 3D게임프로그래밍 (저; 프랭크 D. 루나, 역; 류광, 출판사; 한빛미디어)
'GameProgramming > Direct3D 11' 카테고리의 다른 글
[DirectX] DirectX Texture Tool 이용한 CubeMap 제작 (1) | 2020.07.07 |
---|---|
[Direct3D11] 렌더링 파이프라인? (Rendering Pipeline) (0) | 2020.01.09 |