本文參考dx11龍書 Chapter1 vector algebra(向量代數)
要想學好游戲編程,扎實的數學知識是尤為重要的,下面將對dx11龍書中有關向量的數學知識做一下總結。
在數學中,幾何向量(也稱為歐幾里得向量,通常簡稱向量、矢量),指具有大小(magnitude)和方向(direction)的幾何對象,可以形象化地表示為帶箭頭的線段,箭頭所指:代表向量的方向、線段長度:代表向量的大小。
向量的表示方式一般有3種:
1.代數表示:一般印刷用黑體小寫字母α、β、γ…或a、b、c… 等來表示,手寫用在a、b、c…等字母上加一箭頭表示
2.幾何表示:用有向線段表示
3.坐標表示
(注:directx使用的是左手系,下面不作說明均以左手系為准)
向量的一些基本操作(部分摘自百度百科):
1.向量的模,即向量的長度。
向量a的模記作|a|。向量的模是非負實數,是可以比較大小的。因為方向不能比較大小,所以向量也就不能比較大小。對於向量來說“大於”和“小於”的概念是沒有意義的。例如,“向量AB>向量CD”是沒有意義的。
(外積、叉積)是一個向量,記作a×b(這里“×”並不是乘號,只是一種表示方法,與“·”不同,也可記做“∧”)。若a、b不共線,則a×b的模是:∣a×b∣=|a|·|b|·sin〈a,b〉;a×b的方向是:垂直於a和b,且a、b和a×b按這個次序構成右手系。若a、b垂直,則∣a×b∣=|a|*|b|(此處與數量積不同,請注意),若a×b=0,則a、b平行。向量積即兩個不共線非零向量所在平面的一組法向量。
給定一個向量u和v,求u在v上的投影向量,如下圖。
假設u在v上的投影向量是u’,且向量u和v的夾角為theta。一個向量有兩個屬性,大小和方向,我們先確定u’的大小(即長度,或者模),從u的末端做v的垂線,那么d就是u’的長度。而u’和v的方向是相同的,v的方向v/|v|也就是u’的方向。所以有
(1)
再求d的長度。
(2)
最后求cos(theta)
(3)
聯合求解方程(1)(2)(3)得到
這就是最終的投影向量。
而這個向量的長度d是
============================
以下是舊的推導,也保留。
XNA MathVectors
下面介紹一些xna math庫中常用的向量結構及方法
1.向量類型
有XMVECTOR,XMFLOAT2,XMFLOAT3,XMFLOAT4等幾種類型,具體可以看dx11龍書1.6.1節
在這一章中作者給出使用向量類型應注意的5點:
(1)、 對局部變量和全局變量,使用XMVECTOR類型;
(2)、 對類的數據成員,使用XMFLOAT2, XMFLOAT3和XMFLOAT4數據成員;
(3)、 在進行計算之前,使用載入函數(loading functions)來將XMFLOAT*類型轉換成XMVECTOR類型;
(4)、 用XMVECTOR的實例進行計算;
(5)、 使用存儲函數(storage functions)來將XMVECTOR轉換成XMFLOAT*類型
2.Loading and Storage Methods(載入和存儲函數)
我們用下面的方法來加載數據,從XMFLOAT*到XMVECTOR
XMVECTOR XMLoadFloat3(CONST XMFLOAT3 *pSource);
XMVECTOR XMLoadInt3(CONST UINT* pSource);
XMVECTOR XMLoadColor(CONST XMCOLOR *pSource);
用下面的方法存儲數據,從XMVECTOR到XMFLOAT*
VOID XMStoreFloat3(XMFLOAT3 *pDestination,FXMVECTOR V);
......
3.Parameter Passing參數傳遞
龍書中主要介紹了CXMVECTOR 和FXMVECTOR 這兩種參數類型,並告訴了我們在定義函數時,參數類型的注意事項:
函數的前三個XMVECTOR類型必須是FXMVECTOR,而后面的都是CXMVECTOR。
4.Constant Vectors常向量
需要初始化的XMVECTOR常量應該定義為XMVECTORF32類型(用於存儲浮點向量)或XMVECTORU32類型(用於存儲整數向量).
5.Vector Functions一些向量運算有關的函數
XMVECTOR XMVectorZero();//返回零向量
XMVECTOR XMVectorSplatOne();//返回(1,1,1,1)
XMVECTOR XMVectorSet(FLOAT x,FLOAT y,FLOAT z,FLOAT w);//返回(x,y,z,w)
XMVECTOR XMVectorReplicate(FLOAT s);//返回(s,s,s,s)
XMVECTOR XMVectorSplatX(FXMVECTOR V);//返回(vx,vx,vx,vx)
XMVECTOR XMVector3Length(FXMVECTOR V);//返回向量v的模所構成的新的向量,例如向量v模為2,則返回(2,2,2)
XMVECTOR XMVector3LengthSq(FXMVECTOR V);//模的平方
XMVECTOR XMVector3Dot(FXMVECTOR V1,FXMVECTOR V2);//點積
XMVECTOR XMVector3Cross(FXMVECTOR V1,FXMVECTOR V2);//叉積
XMVECTOR XMVector3Normalize(FXMVECTOR V);//單位化
XMVECTOR XMVector3Orthogonal(FXMVECTOR V);//得到一個與其垂直的向量
XMVECTOR XMVector3AngleBetweenVectors(FXMVECTOR V1,FXMVECTOR V2);//兩個向量的夾角
VOID XMVector3ComponentsFromNormal(XMVECTOR* pParallel,XMVECTOR* pPerpendicular,FXMVECTOR V,FXMVECTOR Normal);//向量的投影
BOOL XMVector3Equal(FXMVECTOR V1,FXMVECTOR V2);//判斷兩個向量是否相等
6.Floating-Point Error浮點數計算誤差
用浮點數進行計算(甚至單純地表示)時,會出現誤差,所以等判斷相等時,需要定義一個容許誤差。
附:dx11龍書測試的源碼及測試結果
1.
1 #include <windows.h> 2 #include <xnamath.h> 3 #include <iostream> 4 using namespace std; 5 6 //重載<<操作符 7 ostream& operator<<(ostream &os, FXMVECTOR v) 8 { 9 XMFLOAT3 dest; 10 XMStoreFloat3(&dest, v); 11 os << "(" << dest.x << "," << dest.y << "," << dest.z << ")"; 12 return os; 13 } 14 15 int main() 16 { 17 cout.setf(ios_base::boolalpha);//cout格式化 輸入輸出bool值可以為true和false 18 19 //檢查是否支持SSE2 20 if (!XMVerifyCPUSupport()) 21 { 22 cout << "xna math not supported" << endl; 23 return 0; 24 } 25 XMVECTOR p = XMVectorZero(); 26 XMVECTOR q = XMVectorSplatOne(); 27 XMVECTOR u = XMVectorSet(1.0f, 2.0f, 3.0f, 0.0f); 28 XMVECTOR v = XMVectorSplatX(u); 29 XMVECTOR w = XMVectorReplicate(-3.5f); 30 31 cout << "p = " << p << endl; 32 cout << "q = " << q << endl; 33 cout << "u = " << u << endl; 34 cout << "v = " << v << endl; 35 cout << "w = " << w << endl; 36 37 return 0; 38 }
2.
1 #include <windows.h> 2 #include <xnamath.h> 3 #include <iostream> 4 using namespace std; 5 6 ostream& operator<<(ostream &os, FXMVECTOR v) 7 { 8 XMFLOAT3 dest; 9 XMStoreFloat3(&dest, v); 10 os << "(" << dest.x << "," << dest.y << "," << dest.z << ")"; 11 return os; 12 } 13 14 int main() 15 { 16 cout.setf(ios_base::boolalpha); 17 if (!XMVerifyCPUSupport()) 18 { 19 cout << "xna math not supported" << endl; 20 return 0; 21 } 22 XMVECTOR n = XMVectorSet(1.0f, 0.0f, 0.0f, 0.0f); 23 XMVECTOR u = XMVectorSet(1.0f, 2.0f, 3.0f, 0.0f); 24 XMVECTOR v = XMVectorSet(-2.0f, 1.0f, -3.0f, 0.0f); 25 XMVECTOR w = XMVectorSet(0.707f, 0.707f, 0.0f, 0.0f); 26 27 XMVECTOR a = u + v; 28 XMVECTOR b = u - v; 29 XMVECTOR c = 10.0f * u; 30 XMVECTOR L = XMVector3Length(u); 31 XMVECTOR d = XMVector3Normalize(u); 32 XMVECTOR s = XMVector3Dot(u, v); 33 XMVECTOR e = XMVector3Cross(u, v); 34 35 XMVECTOR projW; 36 XMVECTOR perpW; 37 XMVector3ComponentsFromNormal(&projW, &perpW, w, n); 38 39 bool equal = XMVector3Equal(projW + perpW, w) != 0; 40 bool notEqual = XMVector3NotEqual(projW + perpW, w) != 0; 41 XMVECTOR angelVec = XMVector3AngleBetweenVectors(projW, perpW); 42 float angleRadians = XMVectorGetX(angelVec); 43 float angleDegrees = XMConvertToDegrees(angleRadians); 44 45 cout << "u = " << u << endl; 46 cout << "v = " << v << endl; 47 cout << "w = " << w << endl; 48 cout << "n = " << n << endl; 49 cout << "a = u + v = " << a << endl; 50 cout << "b = u - v = " << b << endl; 51 cout << "c = 10 * u = " << c << endl; 52 cout << "d = u / ||u|| = " << d << endl; 53 cout << "e = u x v = " << e << endl; 54 cout << "L = ||u|| = " << L << endl; 55 cout << "s = u.v = " << s << endl; 56 cout << "projW = " << projW << endl; 57 cout << "perpW = " << perpW << endl; 58 cout << "projW + perpW == w = " << equal << endl; 59 cout << "projW + perpW != w = " << notEqual << endl; 60 cout << "angle = " << angleDegrees << endl; 61 62 return 0; 63 }
3.
1 #include <windows.h> // for FLOAT definition 2 #include <xnamath.h> 3 #include <iostream> 4 using namespace std; 5 6 int main() 7 { 8 cout.precision(8); 9 10 // Check support for SSE2 (Pentium4, AMD K8, and above). 11 if( !XMVerifyCPUSupport() ) 12 { 13 cout << "xna math not supported" << endl; 14 return 0; 15 } 16 17 XMVECTOR u = XMVectorSet(1.0f, 1.0f, 1.0f, 0.0f); 18 XMVECTOR n = XMVector3Normalize(u); 19 20 float LU = XMVectorGetX(XMVector3Length(n)); 21 22 // Mathematically, the length should be 1. Is it numerically? 23 cout << LU << endl; 24 if( LU == 1.0f ) 25 cout << "Length 1" << endl; 26 else 27 cout << "Length not 1" << endl; 28 29 // Raising 1 to any power should still be 1. Is it? 30 float powLU = powf(LU, 1.0e6f); 31 cout << "LU^(10^6) = " << powLU << endl; 32 }