對很多愛玩遊戲的男生來說,遊戲行業一定會有值得熱愛的工作。但入行之後才知道玩遊戲和開發遊戲是兩回事!
給無數人帶去快樂的遊戲,開發難度大嗎?入行門檻高嗎?
無數對遊戲行業憧憬的人都有這樣的疑問。
我們先從和遊戲開發密切相關的引擎說起吧。
遊戲引擎技術在國外發展十分迅速,但國內遊戲行業起步相對較晚,再加上從業者有時急於求成,引擎的人才積累遠遠不如國外。
遊戲引擎到底是什麼呢?
在遊戲玩家看來,遊戲畫面的表現力越好,遊戲場面的震撼程度越大,遊戲體驗的真實感越強,底層的遊戲引擎就可能越強大。
從專業角度來說,遊戲引擎是指一些已編寫好的可編輯計算機遊戲系統或者一些互動式實時影象應用程式的核心元件。這些系統為遊戲設計者提供編寫遊戲所需的各種工具,其目的在於讓遊戲設計者能容易和快速地寫出遊戲程式而不用從零開始。
不管遊戲是怎樣的形式(是角色扮演遊戲、即時策略遊戲、冒險解謎遊戲或是動作射擊遊戲),哪怕是一個只有1兆的小遊戲,也需要遊戲引擎技術。
引擎相當於遊戲的框架,框架打好後,關卡設計師、建模師、動畫師可往裡填充內容,對於開發遊戲來說乃重中之重。
當然,勇於迎難而上的人並不少,在興趣的驅動下,學習遊戲引擎技術開發並非遙不可及的事。那今天先給大家講一下游戲引擎開發路上的第一個攔路華——數學演算法。
基本數學從 VSMath 這個檔案說起
該檔案裡封裝了 C 語言常用的數學函式,以及大量的巨集定義。
以下幾個巨集定義是用來判斷精度的,尤其是判斷兩個浮點數是否相等,因為絕對的相等是沒有的,誤差必須考慮進去。
#define VSFRONT 0#define VSBACK 1#define VSON 2#define VSCLIPPED 3#define VSCULLED 4#define VSVISIBLE 5#define VSINTERSECT 3#define VSOUT 4#define VSIN 5#define VSNOINTERSECT 6//弧度和角度轉換函式inline VSREAL RadianToAngle(VSREAL Radian){ return ( Radian * 180.0f ) / VSPI ;}inline VSREAL AngleToRadian(VSREAL Angle){ return ( Angle * VSPI ) / 180.0f;}//判斷是否為 2Ninline bool IsTwoPower(unsigned int uiN){ return !(uiN & (uiN - 1));}inline unsigned short FloatToHalf(VSREAL Value)inline VSREAL HalfToFloat(unsigned short Value)inline unsigned int CompressUnitFloat(VSREAL f, unsigned int Bit = 16)inline unsigned int CompressFloat(VSREAL f, VSREAL Max , VSREAL Min , unsigned int Bit = 16)inline VSREAL DecompressUnitFloat(unsigned int quantized,unsigned int Bit = 16)inline VSREAL DecompressFloat(unsigned int quantized,VSREAL Max , VSREAL Min ,unsigned int Bit = 16)//計算正弦和餘弦查詢表,加快正弦和餘弦計算速度for (unsigned int i = 0 ; i <= 360 ; i++){ VSREAL iRadian = AngleToRadian(VSREAL(i)); FastSin[i] = SIN(iRadian); FastCos[i] = COS(iRadian);}inline VSREAL VSMATH_API GetFastSin(unsigned int i);inline VSREAL VSMATH_API GetFastCos(unsigned int i);VSREAL GetFastSin(unsigned int i){ return FastSin[i];}VSREAL GetFastCos(unsigned int i){ return FastCos[i];}
下面兩個函式通過給定長度的資料來計算出一個雜湊索引,返回值為 32 位的雜湊。
如果提供的資料量很大,可能會存在衝突,即兩個不同的資料返回同一個值。
對於引擎而言,相關的資料都不多,所以衝突為 0。
void VSInitCRCTable()unsigned int CRC32Compute( const void *pData, unsigned int uiDataSize )
最後介紹 SSE(Streaming SIMD Extensions,其中 SIMD 是 Single Instruction Multiple Data 縮寫,表示單指令多資料)指令加速數學庫。
本書用到該庫的兩個版本,一個是彙編版,另一個是“高階語言”版,高階語言版比彙編版用起來方便。
VSFastFunction 檔案裡面用到的是彙編 SSE 庫,在 VSVector3、VSMatrix3X3、VSMatrix4X4 檔案中用到的高階語言版 SSE 庫,較容易理解。
常規的加法指令一次只能完成一次加法運算,而 SSE 庫中的加法指令一次最多可以完成 4 次加法運算。下面分別給出 SSE 庫的彙編版和高階語言版。
//彙編版 SSE 庫void VSFastAdd(const VSMatrix3X3W & InM1,const VSMatrix3X3W & InM2, VSMatrix3X3W & OutM){ //VS 支援內嵌彙編 __asm { mov eax, [InM2]; mov ecx, [InM1]; movups xmm4, [eax]; movups xmm5, [eax+16]; movups xmm6, [eax+32]; movups xmm7, [eax+48]; mov eax, [OutM]; movups xmm0, [ecx]; movups xmm1, [ecx+16]; movups xmm2, [ecx+32]; movups xmm3, [ecx+48]; addps xmm0, xmm4; movups [eax], xmm0; addps xmm1, xmm5; movups [eax+16], xmm1; addps xmm2, xmm6; movups [eax+32], xmm2; addps xmm3, xmm7; movups [eax+48], xmm3; }}//高階語言版 SSE 庫void VSMatrix3X3W::operator -=(VSREAL f){ __m128 _v1 = _mm_set_ps(m[0],m[1],m[2],m[3]); __m128 _v2 = _mm_set_ps(m[4],m[5],m[6],m[7]); __m128 _v3 = _mm_set_ps(m[8],m[9],m[10],m[11]); __m128 _v4 = _mm_set_ps(m[12],m[13],m[14],m[15]); __m128 _f = _mm_set_ps(f,f,f,f); __m128 _r1 = _mm_sub_ps(_v1,_f); __m128 _r2 = _mm_sub_ps(_v2,_f); __m128 _r3 = _mm_sub_ps(_v3,_f); __m128 _r4 = _mm_sub_ps(_v4,_f); M[0][0] = _r1.m128_f32[3]; M[0][1] = _r1.m128_f32[2]; M[0][2] = _r1.m128_f32[1]; M[0][3] = _r1.m128_f32[0]; M[1][0] = _r2.m128_f32[3]; M[1][1] = _r2.m128_f32[2]; M[1][2] = _r2.m128_f32[1]; M[1][3] = _r2.m128_f32[0]; M[2][0] = _r3.m128_f32[3]; M[2][1] = _r3.m128_f32[2]; M[2][2] = _r3.m128_f32[1]; M[2][3] = _r3.m128_f32[0]; M[3][0] = _r4.m128_f32[3]; M[3][1] = _r4.m128_f32[2]; M[3][2] = _r4.m128_f32[1]; M[3][3] = _r4.m128_f32[0];}
基本數學單元三維向量
VSVector3 表示三維向量,這個類既可表示一個 3D 向量,也可以表示一個點。
所以這個類提供了 3D 向量應該具有的函式和作為一個空間點應該具有的函式。
class VSMATH_API VSVector3{public: union { VSREAL m[3]; struct { VSREAL x, y, z; }; };}
矩陣類與向量類一樣,都定義了 union 型別,通過陣列方式或下標方式均可以訪問這個向量的類屬性。
VSVector3 類中的相關函式如下。
//長度inline VSREAL GetLength(void)const;//長度的平方inline VSREAL GetSqrLength(void) const;//乘以-1inline void Negate(void);//單位化inline void Normalize(void);//叉積inline void Cross(const VSVector3 &v1,const VSVector3 &v2);//點積VSREAL operator * (const VSVector3 &v)const;//兩個向量的夾角(弧度)VSREAL AngleWith( VSVector3 &v);//用四元數旋轉向量VSQuat operator * (const VSQuat &q)const;//3×3 矩陣變換向量VSVector3 operator * (const VSMatrix3X3 &m)const;//4×4 矩陣變換向量VSVector3 operator * (const VSMatrix3X3W &m)const;//向量加減void operator += (const VSVector3 &v);void operator -= (const VSVector3 &v);VSVector3 operator + (const VSVector3 &v)const;VSVector3 operator - (const VSVector3 &v)const;//向量和常量加減void operator *= (VSREAL f);void operator /= (VSREAL f);void operator += (VSREAL f);void operator -= (VSREAL f);bool operator ==(const VSVector3 &v)const;VSVector3 operator * (VSREAL f)const;VSVector3 operator / (VSREAL f)const;VSVector3 operator + (VSREAL f)const;VSVector3 operator - (VSREAL f)const;
讀者應充分理解上述函式的實現和意義,尤其點積和叉積以及與矩陣的變換。
四維向量
VSVector3W 表示四維向量,該類是在 VSVector3 上加了 w 分量,主要是為了方便與 4×4 矩陣進行運算。這對於 w 分量非 1 情況下的空間變換起了很大作用。另一個應用場景是用作顏色。
class VSMATH_API VSVector3Wtypedef class VSVector3W VSColorRGBA;
以下是顏色操作的相關函式,都用於實現 32 位 DWORD 型別與 4 個 float 型別的相互轉換。
DWORD GetDWARGB()const;DWORD GetDWRGBA()const;DWORD GetDWBGRA()const;DWORD GetDWABGR()const;void GetUCColor(unsigned char &R,unsigned char &G,unsigned char &B, unsigned char &A)const;void CreateFromARGB(DWORD ARGB);void CreateFromBGRA(DWORD BGRA);void CreateFromRGBA(DWORD RGBA);void CreateFormABGR(DWORD ABGR);
下面幾個關於顏色的組合函式都用於實現 VSColorRGBA 型別和 DWORD 型別的相互轉換。
inline DWORD VSDWCOLORARGB(unsigned char a, unsigned char r, unsigned char g,unsigned char b){ return (DWORD) ((((a)&0xff)<<24)|(((r)&0xff)<<16)|(((g)&0xff)<<8)|((b)&0xff)));}inline DWORD VSDWCOLORBGRA(unsigned char a, unsigned char r, unsigned char g,unsigned char b){ return (DWORD) ((((b)&0xff)<<24)|(((g)&0xff)<<16)|(((r)&0xff)<<8)|((a)&0xff)));}inline DWORD VSDWCOLORRGBA(unsigned char a, unsigned char r, unsigned char g,unsigned char b){ return (DWORD) ((((r)&0xff)<<24)|(((g)&0xff)<<16)|(((b)&0xff)<<8)|((a)&0xff)));}inline DWORD VSDWCOLORABGR(unsigned char a, unsigned char r, unsigned char g,unsigned char b){ return (DWORD) ((((a)&0xff)<<24)|(((b)&0xff)<<16)|(((g)&0xff)<<8)|((r)&0xff)));}inline void VSDWCOLORGetARGB(DWORD ARGB,unsigned char &a, unsigned char &r, unsigned char &g,unsigned char &b){ a = (ARGB>>24) & 0xff; r = (ARGB>>16) & 0xff; g = (ARGB>>8) & 0xff; b = (ARGB) & 0xff;}inline void VSDWCOLORGetBGRA(DWORD BGRA,unsigned char &a, unsigned char &r, unsigned char &g,unsigned char &b){ b = (BGRA>>24) & 0xff; g = (BGRA>>16) & 0xff; r = (BGRA>>8) & 0xff; a = (BGRA) & 0xff;}inline void VSDWCOLORGetRGBA(DWORD RGBA,unsigned char &a, unsigned char &r, unsigned char &g,unsigned char &b){ r = (RGBA>>24) & 0xff; g = (RGBA>>16) & 0xff; b = (RGBA>>8) & 0xff; a = (RGBA) & 0xff;}inline void VSDWCOLORGetABGR(DWORD ABGR,unsigned char &a, unsigned char &r, unsigned char &g,unsigned char &b){ a = (ABGR>>24) & 0xff; b = (ABGR>>16) & 0xff; g = (ABGR>>8) & 0xff; r = (ABGR) & 0xff;}
在圖形渲染時,顏色需要在 unsigned char、DWORD 和 float 之間轉換,不同格式表示的顏色範圍不同。
3×3 矩陣
VSMatrix3X3 表示 3×3 矩陣,3×3 矩陣在變換中主要用於實現矩陣的旋轉、縮放或者兩者的組合。
需要提醒的是:一定要分清是左手還是右手座標系,矩陣和向量是左乘還是右乘,矩陣是以行矩陣為主還是以列矩陣為主,並明白旋轉的正方向是如何定義的。
下面是幾個建立旋轉矩陣的函式。
//通過一個朝向建立旋轉矩陣void CreateFromDirection(VSVector3 & Direction ,const VSVector3 &Up = VSVector3(0,1,0));void CreateRotX(VSREAL a); // 繞 x 軸旋轉void CreateRotY(VSREAL a); // 繞 y 軸旋轉void CreateRotZ(VSREAL a); // 繞 z 軸旋轉//繞 z 軸、x 軸和 y 軸構建尤拉角void CreateEluer(VSREAL Roll,VSREAL Pitch, VSREAL Yaw)void CreateAxisAngle(const VSVector3 &vAxis, VSREAL a);//繞 vAxis 旋轉 a 弧度 //通過 3 個基向量建立旋轉矩陣void CreateRot(const VSVector3 &U,const VSVector3 &V,const VSVector3 & N);以下幾個函式也要了解一下。
有時在引擎裡也要獲取矩陣的行向量和列向量,尤其是從一個物體的旋轉矩陣中得到它的前方向、上方向和右方向(3 個基向量 U、V、N)。
//按行獲得向量void GetRowVector(VSVector3 Row[3])const;//按行、按列獲得向量void GetColumnVector(VSVector3 Column[3])const;void GetRowVector(VSVector3 &Row0,VSVector3 &Row1,VSVector3 &Row2)const;void GetColumnVector(VSVector3 &Column0,VSVector3 &Column1, VSVector3 &Column2)const;//獲得基向量void GetUVN(VSVector3 UVN[3])const;void GetUVN(VSVector3 & U,VSVector3 &V,VSVector3 &N)const;
有時也需要建立縮放矩陣,大部分引擎的縮放根據原點進行。
//建立縮放矩陣,根據原點縮放void CreateScale(VSREAL fX,VSREAL fY,VSREAL fZ);//根據軸縮放void CreateScale(const VSVector3 & Axis,VSREAL fScale);
從一個矩陣中獲取旋轉量和縮放量也較常用到。
void GetScale(VSVector3 & Scale)const;void GetScaleAndRotater(VSVector3 & Scale);
下面的兩個函式很少使用,本引擎用這兩個函式來求點集的 OBB 包圍盒。
//構造一個行向量、一個列向量inline void CreateFromTwoVector(const VSVector3 & v1,const VSVector3 & v2);//求特徵值、特徵向量void GetEigenSystem(VSREAL EigenValue[3],VSVector3 Eigen[3])const;
矩陣的乘法以及矩陣和向量的乘法採用以下函式實現。
inline VSMatrix3X3 operator * (const VSMatrix3X3 &Matrix)const; // 矩陣相乘inline VSVector3 operator * (const VSVector3 &vc)const; // 矩陣和向量相乘
矩陣只有相乘才有實際意義,矩陣相乘可以視為矩陣的“加法”。
聽到這裡很多讀者可能很迷惑,相乘怎麼是加法?
學過“離散數學”的人都學過群論,其中經常提到的加法只是特定範圍的加法,不同的群有各自的加法。
舉個例子:整數 1 的加法就是傳統的加法 1 + 1 = 2 ,減法 1 1 = 0 ,也就是 1 +(−1)。
而矩陣的加法就是 M1和 M2相乘等於 M,矩陣的減法就是 M1和 M2的逆矩陣相乘,只不過這個加法不滿足交換律。
矩陣中的“0”就是單位矩陣,也稱為 E。
在理解了這個的基礎上,引出矩陣的插值概念。
檢視以下程式碼。
void VSMatrix3X3::LineInterpolation(VSREAL t,const VSMatrix3X3 & M1, const VSMatrix3X3 &M2){ *this = M1 * (1.0f - t) + M2 * t;}void VSMatrix3X3::Slerp(VSREAL t,const VSMatrix3X3 & M1, const VSMatrix3X3 &M2){ VSMatrix3X3 M1Transpose,Temp; M1Transpose.TransposeOf(M1); Temp = M1Transpose * M2; VSREAL fAnagle; VSVector3 Axis; Temp.GetAxisAngle(Axis,fAngle); Temp.CreateAxisAngle(Axis,fAngle * t); *this = M1 * Temp;}
從本質上講,對於旋轉矩陣的插值,第一個函式的插值演算法是不正確的,雖然插值公式是 M1(1.0f t) +M2t,但“+”表示矩陣相乘,所以第二個函式的插值演算法才是正確的。
在第二個函式中,插值公式是 M1(M1t)1M2t,這裡的 t 也不是與矩陣簡單的相乘,必須把矩陣變成軸向和角度,然後把 t 和角度相乘。
4×4 矩陣
VSMatrix3X3W 表示 4×4 矩陣,該函式用得最多的還是在空間變換上。
下面是建立 4×4 矩陣,縮放和旋轉都是通過 VSMatrix3X3 實現的。
//用 3*3 矩陣建立void CreateFrom3X3(const VSMatrix3X3 & Mat);//平移矩陣void CreateTranslate(VSREAL dx, VSREAL dy, VSREAL dz);void CreateTranslate(const VSVector3 & V);
下面的函式為物體建立區域性變換矩陣。
如果兩個物體 A、B 都在同一個空間 M 下,B 若要變換到 A 的空間下,則為 A 物體建立變換矩陣。
其中,U、V、N 為物體 A 在空間 M 下的基向量,Point 為 A 在 M 空間下的位置。
舉個簡單的例子:若 M 為世界空間,所有世界空間下的物體都要變換到相機空間,那麼U、V、N 就是相機在世界空間下的 3 個基向量(或者軸向),Point 為相機在世界空間下的位置。
void CreateInWorldObject(const VSVector3 &U,const VSVector3 &V,const VSVector3 & N,const VSVector3 &Point);
公告板(billboard)是一種特殊的面片,此處不過多介紹。一般公告板有兩種:一種是完全面向相機的,一般多為粒子;另一種是隻能沿 y 軸旋轉的,儘量面向相機方向。
//建立公告牌變換矩陣void CreateFormBillboard(const VSVector3 &vcPos, //公告牌位置 const VSMatrix3X3 &CameraRotMatrix, //相機或其他矩陣 bool bAxisY); //是否只選擇沿 y 軸旋轉
以下幾個是建立相機矩陣、透視投影矩陣、正交投影矩陣、視口矩陣的函式。
//構建相機矩陣(根據觀察方向)bool CreateFromLookDir(const VSVector3 &vcPos, //相機位置 const VSVector3 &vcDir, //觀察方向 const VSVector3 &vcWorldUp = VSVector3(0,1,0));//構建相機矩陣(根據目標位置)bool CreateFromLookAt(const VSVector3 &vcPos, //相機位置 const VSVector3 &vcLookAt, //觀察位置 const VSVector3 &vcWorldUp = VSVector3(0,1,0)); //上方向//建立透視投影矩陣bool CreatePerspective(VSREAL fFov , //x 方向的張角 VSREAL fAspect, //寬高比 VSREAL fZN , //近剪裁面 VSREAL fZF); //遠剪裁面//建立正交投影矩陣bool CreateOrthogonal(VSREAL fW , //寬 VSREAL fH, //高 VSREAL fZN , //近剪裁面 VSREAL fZF); //遠剪裁面//建立視口矩陣bool CreateViewPort(VSREAL fX,VSREAL fY,VSREAL fWidth,VSREAL fHeight,VSREAL fMinz,VSREALfMaxz);
下面幾個也是常用的函式,因為在 3×3 矩陣裡都有得到旋轉和縮放分量的函式,所以未在 4×4 矩陣裡直接提供。
inline void Identity(void); //單位矩陣inline void TransposeOf(const VSMatrix3X3W &Matrix); //轉置inline void InverseOf(const VSMatrix3X3W & Mat); //求逆inline VSMatrix3X3W GetTranspose()const; //轉置inline VSMatrix3X3W GetInverse()const; //求逆inline VSVector3 GetTranslation(void)const; //得到平移量inline void Get3X3(VSMatrix3X3 & Mat)const; //得到 3*3 部分
下面幾個也是比較常用的,但 VSVector3 和 4×4 矩陣相乘是點與 4×4 矩陣相乘,表示對點的空間變換。
如果要對向量進行空間變換,應使用 Apply3X3。
inline VSMatrix3X3W operator * (const VSMatrix3X3W &Matirx)const; // 矩陣相乘inline VSVector3 operator * (const VSVector3 &vc)const; // 矩陣和向量乘inline VSVector3W operator * (const VSVector3W &vc)const; // 矩陣和向量乘//應用 3*3 的部分inline VSVector3 Apply3X3(const VSVector3 &v)const;//應用平移inline VSVector3 ApplyTranlate(const VSVector3 &Point)const;
四元數
VSQuat 表示四元數類。下面的函式建立四元數。
//通過旋轉軸和旋轉角構造四元數void CreateAxisAngle(const VSVector3& Axis,VSREAL fAngle);//由尤拉角構造四元數void CreateEule(VSREAL fRoll, VSREAL fPitch, VSREAL fYaw);
通過旋轉矩陣得到四元數的函式寫在了 VSMatrix3X3 裡面。
//得到尤拉角void GetEulers(VSREAL &fRoll, VSREAL &fPitch, VSREAL &fYaw)const;//從四元數得到變換矩陣void GetMatrix(VSMatrix3X3 &Matrix)const;//取得旋轉軸和旋轉角void GetAxisAngle(VSVector3 & Axis , VSREAL & fAngle)const;
四元數的一些常用函式如下。
//單位化void Normalize();//求共軛VSQuat GetConjugate()const;//得到長度VSREAL GetLength(void)const;//求逆VSQuat GetInverse()const;//求點積VSREAL Dot(const VSQuat& q)const;//求共軛VSQuat operator ~(void) const;//求冪VSQuat Pow(VSREAL exp)const;//求以 e 為底的對數VSQuat Ln()const;//求以 e 為底的指數VSQuat Exp()const;void operator /= (VSREAL f);VSQuat operator / (VSREAL f)const;void operator *= (VSREAL f);VSQuat operator * (VSREAL f)const;VSQuat operator * (const VSVector3 &v) const;VSQuat operator * (const VSQuat &q) const;void operator *= (const VSQuat &q);void operator += (const VSQuat &q);VSQuat operator + (const VSQuat &q) const;void operator -= (const VSQuat &q);VSQuat operator - (const VSQuat &q) const;bool operator ==(const VSQuat &q)const;
四元數旋轉的示例程式碼如下。
//求 q2 繞 q1 旋轉後的四元數void Rotate(const VSQuat &q1, const VSQuat &q2);//旋轉一個向量VSVector3 Rotate(const VSVector3 &v)const;
四元數插值的相關實現可參考《3D 數學基礎:圖形與遊戲開發》一書。
//插值void Slerp(VSREAL t,const VSQuat & q1,const VSQuat & q2);//三角形二維球型插值void TriangleSlerp(VSREAL t1,VSREAL t2, const VSQuat & q1,const VSQuat & q2, const VSQuat & q3);//四元數樣條插值void Slerp(VSREAL t,const VSQuat & q1,const VSQuat & q2,const VSQuat & s1, const VSQuat & s2);void SlerpSValueOf(const VSQuat & q1,const VSQuat & q2,const VSQuat & q3);
基本圖形單元這一節主要介紹引擎中常用的基本圖元,相機裁剪、射線檢測、物體碰撞等都與它們密切相關,每一個圖元是一個類,類的屬性是根據空間幾何定義來封裝的,類的方法也很容易分類,主要是與其他圖元的位置關係,或者與其他圖元的距離判定(《計算機圖形學幾何工具演算法詳解》一書中有詳細的演算法描述)。
下圖展示了圖元類的繼承關係。
點
點用 VSVector3 類表示。
直線、射線、線段
VSLine3 表示直線,直線定義為一個點和一個方向,與射線的區別為直線的方向可以為負方向,這個方向一定是單位化的。
P = P0 + tDir
上面的等式是直線的引數化方程,t 為引數。
給定 t,就可以算出 P;給定 P,則可以算出 t。
//給定點 P,求 tbool GetParameter(const VSVector3 &Point,VSREAL &fLineParameter )const;//構建直線inline void Set(const VSVector3 & Orig,const VSVector3 &Dir);//得到 P0 和 dirinline const VSVector3 & GetOrig()const;inline const VSVector3 & GetDir()const;//給定 t,求 Pinline VSVector3 GetParameterPoint(VSREAL fLineParameter)const;
下面的函式用於判斷直線與其他圖元的位置關係。
//判斷直線與三角形的位置關係。bCull 為是否為背面剪裁,是否考慮朝向,t 返回相交長度//VSNOINTERSECT VSNTERSECTint RelationWith(const VSTriangle3 & Triangle, bool bCull,VSREAL &fLineParameter, VSREAL fTriangleParameter[3])const;//判斷直線與平面的位置關係//VSNOINTERSECT VSNTERSECT VSON VSBACK VSFRONTint RelationWith(const VSPlane3 &Plane, bool bCull,VSREAL &fLineParameter)const;//判斷直線與矩形的位置關係//VSNOINTERSECT VSNTERSECTint RelationWith(const VSRectangle3 &Rectangle,bool bCull,VSREAL &fLineParameter, VSREAL fRectangleParameter[2])const;//判斷直線與球的位置關係//VSNOINTERSECT VSNTERSECTint RelationWith(const VSSphere3 &sphere, unsigned int &Quantity,VSREAL &tNear, VSREAL &tFar)const;//判斷直線與 OBB 的位置關係//VSNOINTERSECT VSNTERSECTint RelationWith(const VSOBB3 &OBB, unsigned int &Quantity,VSREAL &tNear,VSREAL &tFar)const;//判斷直線與 AABB 的位置關係//VSNOINTERSECT VSNTERSECTint RelationWith(const VSAABB3 &AABB, unsigned int &Quantity,VSREAL &tNear,VSREAL & tFar)const;//判斷直線與多邊形的位置關係//VSNOINTERSECT VSNTERSECTint RelationWith(const VSPolygon3 &Polygon,VSREAL &fLineParameter, bool bCull,int & iIndexTriangle,VSREAL fTriangleParameter[3])const;
下面的函式用於計算直線與其他圖元的距離。
//計算點到直線的距離VSREAL SquaredDistance(const VSVector3 &Point,VSREAL &fLineParameter)const;//計算直線和直線的距離VSREAL SquaredDistance(const VSLine3 &Line,VSREAL &fLine1Parameter,VSREAL &fLine2 Parameter)const;//計算直線和射線的距離VSREAL SquaredDistance(const VSRay3 &Ray,VSREAL &fLineParameter,VSREAL & fRayParameter)const;//計算直線和線段的距離VSREAL SquaredDistance(const VSSegment3 & Segment,VSREAL &fLineParameter,VSREAL & fSegmentParameter)const;//計算直線和三角形的距離VSREAL SquaredDistance(const VSTriangle3& Triangle,VSREAL &fLineParameter,VSREAL fTriangleParameter[3])const;//計算直線和矩形的距離VSREAL SquaredDistance(const VSRectangle3& Rectangle,VSREAL &fLineParameter,VSREAL fRectangleParameter[2])const;//計算直線和 OBB 的距離VSREAL SquaredDistance(const VSOBB3 & OBB,VSREAL &fLineParameter,VSREAL fOBBParameter[3])const;//計算直線和球的距離VSREAL Distance(const VSSphere3 &Sphere,VSREAL &fLineParameter,VSVector3 & SpherePoint)const;//計算直線和平面的距離VSREAL Distance(const VSPlane3 &Plane,VSVector3 &LinePoint,VSVector3 &PlanePoint) const;//計算直線和 AABB 的距離VSREAL SquaredDistance(const VSAABB3 &AABB,VSREAL &fLineParameter, VSREAL fAABBParameter[3])const;//計算直線和多邊形的距離VSREAL SquaredDistance(const VSPolygon3 & Polygon,VSREAL &fLineParameter,int& IndexTriangle,VSREAL fTriangleParameter[3])const;
VSRay3 表示射線,射線和直線的唯一區別在於 t 可以為負。
VSSegment3 表示線段,線段不同於直線,它有端點屬性。
對於 P = P0 + tDir 來說,t 是有範圍的,所以它的定義方式有兩種:第一種基於兩個點,第二種基於方向和長度。
inline void Set(const VSVector3 &Orig,const VSVector3 &End);inline void Set(const VSVector3 &Orig,const VSVector3 &Dir,VSREAL fLen);
平面、三角形、矩形、多邊形
VSPlane 表示平面,平面的引數化方程為 N (P0 – P1) = 0。
平面的法線垂直於平面上所有的線,簡化為NP0 + D = 0,D = NP1為常數;所有平面上的點 P 都滿足 NP + D = 0。
下面幾個函式都可以建立一個平面。
//通過平面法向量和平面上一點確定一個平面inline void Set(const VSVector3 &N, const VSVector3 &P);//通過平面法向量和 D 確定一個平面inline void Set(const VSVector3 &N , VSREAL fD);//通過 3 個點確定一個平面inline void Set(const VSVector3 &P0, const VSVector3 &P1, const VSVector3 &P2);inline void Set(const VSVector3 Point[3]);
下面的函式用於計算平面與其他圖元的距離。
//計算點到平面的距離VSREAL Distance(const VSVector3 &Point,VSVector3 &PlanePoint)const;//計算平面和球的距離VSREAL Distance(const VSSphere3 &Sphere,VSVector3 & SpherePoint)const;//計算直線和平面的距離VSREAL Distance(const VSLine3 &Line,VSVector3 &PlanePoint, VSVector3 &LinePoint)const;//計算射線和平面的距離VSREAL Distance(const VSRay3 & Ray,VSVector3 &PlanePoint,VSVector3 &RayPoint)const;//計算線段和平面的距離VSREAL Distance(const VSSegment3 & Segment,VSVector3 &PlanePoint, VSVector3 &Segment Point)const;//計算平面和平面的距離VSREAL Distance(const VSPlane3 &Plane,VSVector3 &Plane1Point,VSVector3 & Plane2Point)const;//計算平面和三角形的距離VSREAL Distance(const VSTriangle3 &Triangle,VSVector3 &PlanePoint, VSVector3 &Triangle Point)const;//計算矩形和平面的距離VSREAL Distance(const VSRectangle3 &Rectangle,VSVector3 &PlanePoint,VSVector3 &Rectangle Point)const;//計算 OBB 和平面的距離VSREAL Distance(const VSOBB3& OBB,VSVector3 &PlanePoint,VSVector3 & OBBPoint)const;//計算 AABB 和平面的距離VSREAL Distance(const VSAABB3 &AABB,VSVector3 &PlanePoint,VSVector3 & AABBPoint)const;//計算平面和多邊形的距離VSREAL Distance(const VSPolygon3 &Polygon,VSVector3 &PlanePoint,int& IndexTriangle,VSVector3 &TrianglePoint)const;
下面的函式用於判斷平面與其他圖元的位置關係。
//判斷點和平面的位置關係//VSFRONT VSBACK VSPLANARint RelationWith(const VSVector3 &Point)const;//判斷直線和平面的位置關係/VSNOINTERSECT VSNTERSECT VSON VSBACK VSFRONTint RelationWith(const VSLine3 &Line, bool bCull,VSREAL &fLineParameter)const;//判斷射線和平面的位置關係//VSNOINTERSECT VSNTERSECT VSON VSBACK VSFRONTint RelationWith(const VSRay3 &Ray, bool bCull,VSREAL &fRayParameter)const;//判斷線段和平面的位置關係//VSNOINTERSECT VSNTERSECT VSON VSBACK VSFRONTint RelationWith(const VSSegment3 &Segment, bool bCull,VSREAL &fSegmentParameter)const;//判斷平面和 OBB 的位置關係//VSFRONT VSBACK VSINTERSECTint RelationWith(const VSOBB3 &OBB)const;//判斷平面和 AABB 的位置關係//VSFRONT VSBACK VSINTERSECTint RelationWith(const VSAABB3 &AABB)const;//判斷平面和球的位置關係//VSFRONT VSBACK VSINTERSECTint RelationWith(const VSSphere3 &Sphere)const;//判斷平面和三角形的位置關係//VSON VSFRONT VSBACK VSINTERSECTint RelationWith(const VSTriangle3 &Triangle)const;int RelationWith(const VSTriangle3 &Triangle ,VSSegment3 & Segment)const;//判斷引數平面和平面的位置關係//VSNOINTERSECT VSINTERSECTint RelationWith(const VSPlane3 &Plane)const;int RelationWith(const VSPlane3 &Plane,VSLine3 &Line)const;//判斷平面和矩形的位置關係//VSON VSFRONT VSBACK VSINTERSECTint RelationWith(const VSRectangle3 & Rectangle)const;int RelationWith(const VSRectangle3 &Rectangle,VSSegment3 &Segment)const;//判斷平面和多邊形的位置關係//VSON VSFRONT VSBACK VSINTERSECTint RelationWith(const VSPolygon3 &Polygon)const;int RelationWith(const VSPolygon3 &Polygon,VSSegment3 & Segment)const;//判斷平面和圓柱的位置關係int RelationWith(const VSCylinder3 &Cylinder3)const;
VSTriangle3 表示三角形類,三角形類從平面類派生而來,它的構造方式很簡單,就是 3 個點。
P=P1U+P2V+P3(1 U V)是三角形的引數化方程。
給定一個點 P,引數 U、V 可以通過公式推匯出來;給定引數 U、V,P 也可以推匯出來。
bool GetParameter(const VSVector3 &Point,VSREAL fTriangleParameter[3])const;inline VSVector3 GetParameterPoint(VSREAL fTriangleParameter[3])const;
VSRectangle3 表示矩形類,矩形也是從平面類派生而來的,它由兩個垂直向量和一個點定義。
球體、有向包圍盒、立方體
VSSphere3 表示球體,VSOBB3 表示有向包圍盒,VSAABB3 表示立方體。因為沒有實現物理引擎,所以圓柱體、膠囊體和橢球體等都沒單獨實現。在引擎裡面球體和立方體用得最多,都用在場景管理裡。除了這些之外,還有一些合併演算法,球體與球體合併,立方體與立方體合併。
不同遊戲引擎的內部架構千差萬別,而且遊戲引擎涉及的知識點甚多,很少有人能全面把握每一個知識細節。
同時,遊戲引擎屬於實踐性的工程,必須有足夠令人信服的演示示例以及程式碼支援,加上商用引擎的授權、作者個人時間有限等各方面的因素,導致市面上的遊戲引擎圖書要麼泛泛而談,要麼距離真正開發遊戲相去甚遠。
如果你還想了解遊戲引擎的基本原理和作用、了解大公司開發引擎的基本流程、 獲得良好的遊戲引擎方面的知識儲備,這本《 遊戲引擎原理與實踐 卷1 基礎框架》推薦給大家, 本書專門配套的引擎和示例,可以了解開發遊戲引擎的具體細節。
本書是騰訊遊戲引擎設計師程東哲基於多年經驗和積累的力作,詳盡示例,詮釋遊戲引擎製作與開發技術,Milo等遊戲業內資-深專家鼎力推薦。
-END-