XNA Math Vectors
In Direct3D 9 and 10, the calculations for the D3DX library support vectors and other core types are included in the math library. In Direct11, the D3DX library is not included in the math library, but instead is the XNA Math Library. The XNA utilizes a special hardware register. In the Windows environment, XNA
The math library uses the SSE2 (streaming SIMD Extension 2) instruction set. It uses a 128-bits-size SIMD (single instruction multiple data) register that can manipulate 4 32-bits floating-point data or integral types with one instruction.
For example: U + V = (UX + VX, Uy + vy, uz + vz)
We add each component together with 3 addition instructions. But by using SIMD, we can do 4D vector addition with just one SIMD instruction instead of using 4 scalar instructions. If you manipulate 3D vectors, we can still use SIMD,
We simply set the fourth component of the vector to 0 and ignore it. Similar in 2D.
In order to use the XNA Math Library, we simply add the header file #include<xnamath.h>. Of course, you can also #include<d3dx10.h> by including the header file, and link the static library d3dx10.lib using the d3dx10 math library.
In the XNA Math Library, the key vector type is xmvector. It is a 128-bits type and can be handled by a single SIMD instruction.
It is defined this way:
1 typedef __m128 Xmvector;
Here, __m128 is a special type of SIMD. For class data members, it is best to use XMFLOAT2,XMFLOAT3,XMFLAOT4. They are defined as follows:
1 struct _XMFLOAT4 2 {3 FLOAT x; 4 FLOAT y; 5 FLOAT z; 6 FLOAT W; 7 }xmfloat4;
However, if we use these types directly for calculations, we will not be able to leverage the SIMD hardware. We need to convert these types of instances into xmfloat types. These are the work of the XNA load function (loading functions). Conversely, XNA also provides a storage function (storage functions) that will
Xmvector converted to xmfloat* type.
Loading and Storage functions
Loading function:
1 // Convert XMFLOAT2 to Xmvector type 2 // Convert XMFLOAT3 to Xmvector type 3 // Convert XMFLOAT4 to Xmvector type
There are many other ways to convert other types to xmvector types, here are some examples:
1 xmvector XMLoadInt3 (CONST uint* psource); // Loads 3-element UINT array into Xmvector 2 xmvector xmloadcolor (CONST xmcolor *psource); // Loads Xmcolor into Xmvector 3 xmvector XMLoadByte4 (CONST XMBYTE4 *psource); // Loads XMBYTE4 into Xmvector
Storage function:
1 // Convert xmvector to XMFLOAT2 type
There are many ways to convert xmvector to other types, here are some examples:
1 VOID XMStoreInt3 (uint* pdestination, Fxmvector V); 2 VOID xmstorecolor (xmcolor* pdestination, Fxmvector V); 3 VOID XMStoreByte4 (XMBYTE4 *pdestination, Fxmvector V);
Sometimes we just want to get or set a component of the xmvector, which can be done using the following function:
1 FLOAT xmvectorgetx (fxmvector V); 2 xmvector xmvectorsetx (fxmvector v,float x);
Rules for passing parameters
In order to take advantage of SIMD, passing parameters to a function of the Xmvector type has some rules that need to be followed, which vary depending on the platform. Especially 32-bit windows, 64-bit windows, and Xbox 360. To be independent of the platform,
We use the types Cxmvector and fxmvector to pass the parameters of the Xmvector. For Windows, they are defined as follows:
1 // 32-bit Windows 2 Const xmvector Fxmvector; 3 Const xmvector& Cxmvector; 4 // 64-bit Windows 5 Const xmvector& Fxmvector; 6 Const xmvector& Cxmvector;
The difference is that we can pass a copy of Xmvector directly or we have to pass a reference. Now, the rules for passing the Xmvector parameter are as follows:
The first three xmvector parameters should be the Fxmvector type, followed by the Cxmvector type.
1 xminline Xmmatrix xmmatrixtransformation (2 fxmvector scalingorigin,3 Fxmvector scalingorientationquaternion, 4 fxmvector Scaling,5 cxmvector rotationorigin,6 Cxmvector rotationquaternion,7 cxmvector translation);
Note that you can have non-xmvector types of parameters, and the preceding rules are still valid:
1 xminline Xmmatrix xmmatrixtransformation2d (2fxmvector scalingorigin,3// Float type 4fxmvector Scaling,5fxmvector rotationorigin,6 // float type 7 cxmvector translation);
For a constant xmvector instance, we should use the XMVECTORF32 type to store the floating-point vector. Here are some examples:
1 Static Const 0.0f 0.0f 0.0f 0.0f }; 2 3 XMVECTORF32 vrighttop = {4vviewfrust.rightslope,5 Vviewfrust.topslope,61.0f,1.0f7 };
Use XMVECTORU32 to store integer vectors:
1 Static Const XMVECTORU32 Vgraby = {20x00000000,0xFFFFFFFF,0x00000000, 0x000000003 };
The XNA Math Library defines some of the constants associated with PI:
1 #defineXM_PI 3.141592654f 2 #defineXM_2PI 6.283185307f 3 # DEFINEXM_1DIVPI 0.318309886f 1/pi 4 #defineXM_1DIV2PI 0.159154943f // 1/2pi 5 #defineXM_PIDIV2 1.570796327f // PI/2 6 #defineXM_PIDIV4 0.785398163f // Pi/4
It also defines the following inline function to convert between angles and radians:
1 xmfinline float Xmconverttoradians (float fdegrees) 2 {3 return fdegrees* (xm_pi/180.0f); 4 }56xmfinline float xmconverttodegrees (float fradians)7 {8 return fradians* (180.0f/xm_pi); 9 }
It also defines the maximum minimum macro:
1 #define Xmmin (a) ((a) < (b))? (a): (b)2#define Xmmax (A, B) ((a) > (b)) (a): (b))
The XNA Math Library provides the following functions to set the contents of the Xmvector:
1Xmvector Xmvectorzero ();//returns 0 vector (0,0,0,0)2Xmvector Xmvectorsplatone ();//return Vectors (1, 1, 1, 1)3Xmvector Xmvectorset (float x, float y, float z,float W);//return vector (x, Y, Z, W)4Xmvector xmvectorreplicate (FLOAT s);//return vector (s, s, S, s)5Xmvector xmvectorsplatx (Fxmvector V);//return vectors (VX, VX, VX,VX)6Xmvector Xmvectorsplaty (Fxmvector V);//return vectors (vy, VY, Vy,vy)7Xmvector Xmvectorsplatz (Fxmvector V);//return vectors (vz, vz, Vz,vz)
Some of the functions of vector Computing: (The 3D example below, 2d,4d the same, just replace 3 of the function name with 2, 4)
1Xmvector xmvector3length (Fxmvector V);//Returns | | v | |2Xmvector xmvector3lengthsq (Fxmvector V);//Returns | | v | | The two-time party3Xmvector Xmvector3dot (Fxmvector V1, Fxmvector V2);//Returns v1 v24Xmvector Xmvector3cross (Fxmvector V1, Fxmvector V2);//Returns V1xv25Xmvector xmvector3normalize (Fxmvector V);//Returns v/| | v | |6Xmvector xmvector3orthogonal (Fxmvector V);//Returns a vector orthogonal to v7Xmvector3anglebetweenvectors (Fxmvector V1, Fxmvector V2);//Returns the angle between V1 and v28VOID xmvector3componentsfromnormal (xmvector* pparallel,xmvector* pperpendicular, Fxmvector V, FXMVECTORNormal);//Returns projn (v)//Returns PREPN (v)9BOOL xmvector3equal (Fxmvector V1, Fxmvector V2);//Returns v1 = v2TenBOOL xmvector3notequal (Fxmvector V1, Fxmvector V2);//Returns v1≠v2
There are some estimation methods, if you don't care about the accuracy, but you care about the speed, you can use the following function:
Mfinline xmvector xmvector3lengthest (Xmvector V); Returns Estimated | | V | |
Mfinline xmvector xmvector3normalizeest (xmvector V);//Returns Estimated v/| | V | |
It is well known that the operation result of floating-point numbers is imprecise.
You can define a threshold to resolve:
1 Const float 0.001f ; 2 BOOL Equals (floatfloat rhs)3{4returnTrue false; 5 }
There are similar functions in the XNA Math Library: xmvector3nearequal ()
1 // Returns 2 // ABS (u.x–v.x) <= epsilon.x && 3 // ABS (U.Y–V.Y) <= epsilon.y && 4 // ABS (U.Z–V.Z) <= epsilon.z 5 xmfinline BOOL xmvector3nearequal (6fxmvector U,7fxmvector V, 8 fxmvector Epsilon);
XNA Math Library