无论游戏是什么形式(无论是角色扮演游戏、即时策略游戏、冒险解谜游戏还是动作射击游戏),即使是只有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;
}
//判断是否为 2
N
inline 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 库的高级语言版本更容易理解。
常规加法指令一次只能完成1次加法运算,而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];
}
基本数学单位
3D矢量
VSVector3 表示三维向量。 此类可以表示 3D 矢量或点。
所以这个类提供了3D向量应该具有的功能和空间点应该具有的功能。
class VSMATH_API VSVector3
{
public:
union
{
VSREAL m[3];
struct
{
VSREAL x, y, z;
};
};
}
矩阵类和向量类一样游戏引擎原理及应用,定义了联合类型,并且可以通过数组方法或下标方法访问此向量的类属性。
VSVector3类中的相关函数如下。
//长度
inline VSREAL GetLength(void)const;
//长度的平方
inline VSREAL GetSqrLength(void) const;
//乘以-1
inline 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中添加了aw组件,主要是为了方便4×4矩阵的运算。 当 w 分量非 1 时,这在空间变换中起着重要作用。 另一个应用场景是作为颜色。
class VSMATH_API VSVector3W
typedef class VSVector3W VSColorRGBA;
下面是颜色操作的相关函数,都是用来实现32位DWORD类型和四种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);以下几个函数也要了解一下。
有时需要获取引擎中矩阵的行向量和列向量,尤其是从物体的旋转矩阵中获取向前、向上和向右方向(三个基向量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.0ft) +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就是相机在世界中的三个基向量(或者说轴向)空间,Point 是相机在世界空间中的位置。
void CreateInWorldObject(const VSVector3 &U,const VSVector3 &V,const VSVector3 &
N,const VSVector3 &Point);
公告牌是一种特殊的面,这里不做介绍。 一般来说,公告板有两种类型:一种是完全面向摄像头,通常由颗粒组成;另一种是完全面向摄像头,通常由颗粒组成。 另一种是只能沿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,VSREAL
fMaxz);
以下功能也是常用的。 因为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,求 t
bool GetParameter(const VSVector3 &Point,VSREAL &fLineParameter )const;
//构建直线
inline void Set(const VSVector3 & Orig,const VSVector3 &Dir);
//得到 P0 和 dir
inline const VSVector3 & GetOrig()const;
inline const VSVector3 & GetDir()const;
//给定 t,求 P
inline VSVector3 GetParameterPoint(VSREAL fLineParameter)const;
下面的函数用于确定直线与其他图元之间的位置关系。
//判断直线与三角形的位置关系。bCull 为是否为背面剪裁,是否考虑朝向,t 返回相交长度
//VSNOINTERSECT VSNTERSECT
int RelationWith(const VSTriangle3 & Triangle, bool bCull,VSREAL &fLineParameter,
VSREAL fTriangleParameter[3])const;
//判断直线与平面的位置关系
//VSNOINTERSECT VSNTERSECT VSON VSBACK VSFRONT
int RelationWith(const VSPlane3 &Plane, bool bCull,VSREAL &fLineParameter)const;
//判断直线与矩形的位置关系
//VSNOINTERSECT VSNTERSECT
int RelationWith(const VSRectangle3 &Rectangle,bool bCull,VSREAL &fLineParameter,
VSREAL fRectangleParameter[2])const;
//判断直线与球的位置关系
//VSNOINTERSECT VSNTERSECT
int RelationWith(const VSSphere3 &sphere, unsigned int &Quantity,VSREAL &tNear,
VSREAL &tFar)const;
//判断直线与 OBB 的位置关系
//VSNOINTERSECT VSNTERSECT
int RelationWith(const VSOBB3 &OBB, unsigned int &Quantity,VSREAL &tNear,VSREAL
&tFar)const;
//判断直线与 AABB 的位置关系
//VSNOINTERSECT VSNTERSECT
int RelationWith(const VSAABB3 &AABB, unsigned int &Quantity,VSREAL &tNear,VSREAL &
tFar)const;
//判断直线与多边形的位置关系
//VSNOINTERSECT VSNTERSECT
int 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 VSPLANAR
int RelationWith(const VSVector3 &Point)const;
//判断直线和平面的位置关系
/VSNOINTERSECT VSNTERSECT VSON VSBACK VSFRONT
int RelationWith(const VSLine3 &Line, bool bCull,VSREAL &fLineParameter)const;
//判断射线和平面的位置关系
//VSNOINTERSECT VSNTERSECT VSON VSBACK VSFRONT
int RelationWith(const VSRay3 &Ray, bool bCull,VSREAL &fRayParameter)const;
//判断线段和平面的位置关系
//VSNOINTERSECT VSNTERSECT VSON VSBACK VSFRONT
int RelationWith(const VSSegment3 &Segment, bool bCull,VSREAL &fSegmentParameter)
const;
//判断平面和 OBB 的位置关系
//VSFRONT VSBACK VSINTERSECT
int RelationWith(const VSOBB3 &OBB)const;
//判断平面和 AABB 的位置关系
//VSFRONT VSBACK VSINTERSECT
int RelationWith(const VSAABB3 &AABB)const;
//判断平面和球的位置关系
//VSFRONT VSBACK VSINTERSECT
int RelationWith(const VSSphere3 &Sphere)const;
//判断平面和三角形的位置关系
//VSON VSFRONT VSBACK VSINTERSECT
int RelationWith(const VSTriangle3 &Triangle)const;
int RelationWith(const VSTriangle3 &Triangle ,VSSegment3 & Segment)const;
//判断参数平面和平面的位置关系
//VSNOINTERSECT VSINTERSECT
int RelationWith(const VSPlane3 &Plane)const;
int RelationWith(const VSPlane3 &Plane,VSLine3 &Line)const;
//判断平面和矩形的位置关系
//VSON VSFRONT VSBACK VSINTERSEC
Tint 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 UV) 是三角形的参数方程。
给定点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 表示立方体。 因为没有实现物理引擎,所以圆柱体、胶囊、椭球体等没有单独实现。 球体和立方体在引擎中最常用,并且用于场景管理。 除此之外,还有一些合并算法,将球体与球体合并,将立方体与立方体合并。
不同游戏引擎的内部架构差异很大3D素材,游戏引擎涉及的知识点也很多。 很少有人能够完全掌握每一个知识细节。
同时,游戏引擎是一个实用的项目,必须有足够令人信服的演示示例和代码支持。 另外,商业引擎的授权以及作者个人时间有限等多种因素,导致市面上的游戏引擎书籍要么笼统,要么通用。 谈论它与实际开发游戏相去甚远。
如果你还想了解游戏引擎的基本原理和功能,了解大公司引擎开发的基本流程,打好游戏引擎的知识基础,这本书《游戏引擎原理与实践第一卷基本框架》是推荐给大家。 书中专门配备了引擎和示例3D场景,让您可以了解开发游戏引擎的具体细节。
本书是腾讯游戏引擎设计师程东哲基于多年经验和积累的力作。 通过详细的实例讲解了游戏引擎的制作和开发技术。 受到Milo等游戏行业资深专家的大力推荐。