首页 > 代码库 > 《游戏人工智能编程案例精粹》读书笔记—数学和物理学初探
《游戏人工智能编程案例精粹》读书笔记—数学和物理学初探
1.1.1 笛卡尔坐标系
在二维空间中,笛卡尔坐标系被定义成两个坐标轴成直角相交并且用单位长度标出。水平轴称为x 轴,而垂直轴称为y 轴,两个轴的交点称为原点,如图1.1 所示。
如图1.1所示,每个坐标轴端点的箭头表示它们在每个方向上无限延伸。假想有一张无限大的纸,上面有x 轴和y 轴,纸就表示 xy 平面,所有二维的笛卡尔坐标系中的点都可以给制在这个平面上。在2D 空间中的一个点可以用一对坐标(x,y) 表示。x 和y 的值代表沿着各自的轴上的距离。
为了表达三维空间,需要另外一个坐标轴z铀。z 轴从你的屏幕的后面延伸到屏幕的前面,在途中穿过原点。如图1.2 所示。
1.1.2 函数和方程
函数的概念是数学的基础。函数表达了两个(或更多个) 称为变量的项之间的关系,并且典型的写法是方程的形式(一个代数表达式等于另一个代数表达式)。
图1.3的左边显示了函数y=2x 在 xy 平面上绘制出来是怎样的图形,使用的x 值的范围是-5.0-5.0。
为了把函数y=mx+c 给制成一个图形,你必须首先有常数m 和c 的一些值。我们设m=2和c=3,给出函数y=2x+3。图1.3 右边显示了结果图形。
y=mx+c 是定义在三维空间的所有直线的函数。常数m定义了直线的斜率,或者说是直线倾斜的陡峭程度,常数c 规定了直线与y 轴相交的位置。
1.1.2.1 指数和幂
一个指数函数定义如下:
α 称为底而x 称为幂。如果口头描述此方程,就是f(x)等于a 的x 次幂。这意味着a 与自身相乘x 次。
图1.5 显示了方程在a=2 时绘制的图形。曲线明显地显示了y 的值是如何随着x 的值快速增加的。这种曲线的类型常常被称为指数增长。
1.1.2.3 化简方程
通常,要解一个方程必须先化简。实现化简的一个黄金定律是在方程的两边通过同时加、减、乘或除一些项来得到方程的解。(这个规则有一个例外:当进行乘或除时,该项不能为零。〉只要方程两边做的运算相同,那么两边将保持相等。
1.1.3 三角学
角和弧度
一个角定义为有公共原点的两条射线的分散度,见图1.7。
弧度是以原点为中心的单位半径(半径为1) 圆为基准的一种度量单位。圆的半径是从圆的中心到圆周上的点的距离。在画有两条射线的同一图(见图1.7)中作单位圆,我们得到图1.8。在两条射线之间的曲线段的长度(在图中显示成点线的)是它们的夹角在弧度制下角的度量。
角度转弧度:弧度=角度×(π/180)
弧度转角度:角度=弧度×(180/π)
勾股定理
一个直角三角形直角所对内的斜边的平方等于其他两个边的平方和。三角形的斜边是它的最长的边,如图1.10 所示。
如果斜边用h 表示,勾股定理可以写成:
两边取平方根得:
这意味着如果我们知道一个直角三角形的任意两个边的长度,就可以轻松地找到第三边。
直角三角函数
α的正弦sinα=b/c;(对边÷斜边)
α的余弦cosα=a/c;(邻边÷斜边)
α的正切tanα=b/a;(对边÷邻边)
当已知角度时,就用正弦、余弦或正切函数得到对应的三角函数值; 反之,如果要想得到角度,就应该利用反三角函数计算。
1.1.4 向量
一个向表达了两个性质:方向和大小。1.16 右边显示了份子原点处的向量(9, 6)。
向量运算
(以下内容来自3D数学基础:图形与游戏开发)
1 零向量
零向量是唯一大小为零的向量,它的每一维都是零,零向量也是惟一一个没有方向的向量。其实零向量表示的就是“没有位移”,就像标量零表示“没有数量”一样。
1.2 负向量
要得到任意维向量的负向量,只需要简单地把每个分量都变负即可。数学表达式为:
几何解释:向量变负,将得到一个和原来向量大小相等,方向相反的向量。(向量在图中的位置是无关紧要的,只有大小和方向才是最重要的)。
1.3 向量大小
其实向量的大小和方向都没有在向量的数学表示中明确的表示出来。所有向量的大小是需要计算的,向量的大小也常被称作向量的长度或模。
n维向量大小的计算公式如下图:
线性代数中,向量的大小用向量两边双竖线表示,这和标量的绝对值在标量两边加单竖线表示类似。
1.4 标量与向量的乘法
虽然标量与向量不能相加,但它们能相乘。结果得到一个向量,与源向量平行,但长度不同或方向相反。
标量和向量的乘法非常直接,将向量的每一个分量都与标量相乘即可。
1.5 标准化向量
对许多向量,我们只关心它的方向而不关心其大小,这样的情况下,使用单位向量将非常方便。
单位向量就是大小为1的向量,单位向量经常也被称作标准化向量。
对于任意非零向量v,都能计算出一个和v方向相同的单位向量 v‘ 这个过程被称作向量的标准化,要标准化向量,将向量除以它的大小即可。
零向量不能被标准化。数学上这是不允许的,因为将导致除零。几何上也没有意义,因为零向量没用方向。
1.6 向量的加法与减法
如果两个向量的维数相同,那么它们能相加,或相减。结果向量的维数与原向量相同。向量加减法的记法和标量加减的记法相同。
两个向量相加或相减,将对应分量相加即可。
(1)向量不能与标量或维数不同的向量相加减。
(2)和标量加法一样,向量加法满足交换律,但向量减法不满足交换律。
1.7 向量点乘
向量点乘也常称作向量内积。
向量点乘就是对应分量乘积的和,结果是一个标量。
点乘结果描述了两个向量的“相似”程度,点乘结果越大,两个向量越相近。
1、判断是否垂直,如果A·B=0,那么A⊥B。
2、点乘结果的正负,如果A·B<0,那么Θ>90°,如果A·B>0,那么Θ<90°,其中Θ为向量A和向量B之间的夹角。
3、两向量之间的夹角,A·B=||A|| ||B|| cosΘ,其中Θ为向量A和向量B之间的夹角。
1.8 向量差乘
向量叉乘又叫叉积,仅可应用于3D向量。
叉乘得到的向量垂直于原来的两个向量。
C++向量封装类:
#ifndef __VECTOR3_H__#define __VECTOR3_H__ #include <math.h> ///////////////////////////////////////////////////////////////// Vector3类 简单的3D向量类/////////////////////////////////////////////////////////////// class Vector3{public: float x, y, z; // 构造函数 // 默认构造函数,不执行任何操作 Vector3() {} // 拷贝构造函数 Vector3(const Vector3 &a) : x(a.x), y(a.y), z(a.z) {} // 带参数的构造函数,用三个值完成初始化 Vector3(float nx, float ny, float nz) : x(nx), y(ny), z(nz) {} // 标准对象操作 // 重载“=”操作符 Vector3& operator =(const Vector3 &a) { x = a.x; y = a.y; z = a.z; return *this; } // 重载“==”操作符 bool operator ==(const Vector3 &a) const { return x==a.x && y==a.y && z==a.z; } // 重载“==”操作符 bool operator !=(const Vector3 &a) const { return x!=a.x || y!=a.y || z!=a.z; } // 向量运算 // 向量归零 void zero() { x = y = z = 0.0f; } // 重载一元“-”运算符 Vector3 operator -() const { return Vector3(-x, -y, -y); } // 重载二元“+”和“-”运算符 Vector3 operator +(const Vector3 &a) const { return Vector3(x+a.x, y+a.y, z+a.z); } Vector3 operator -(const Vector3 &a) const { return Vector3(x-a.x, y-a.y, z-a.z); } // 与标量的乘、除法 Vector3 operator *(float a) const { return Vector3(x*a, y*a, z*a); } Vector3 operator /(float a) const { float oneOverA = 1.0f/a; return Vector3(x*oneOverA, y*oneOverA, z*oneOverA); } // 重载自反运算符 Vector3& operator +=(const Vector3 &a) { x+= a.x; y+= a.y; z+= a.z; return *this; } Vector3& operator -=(const Vector3 &a) { x-= a.x; y-= a.y; z-= a.z; return *this; } Vector3& operator *=(const Vector3 &a) { x*= a.x; y*= a.y; z*= a.z; return *this; } Vector3& operator /=(float a) { float oneOverA = 1.0f/a; x*= oneOverA; y*=oneOverA; z*= oneOverA; return *this; } // 向量标准化 void normailze() { float magSq = x*x +y*y +z*z; if ( magSq > 0.0f ) { float oneOverMag = 1.0f / sqrtf(magSq); x*= oneOverMag; y*= oneOverMag; z*= oneOverMag; } } // 向量点乘,重载标准的乘法运算符 float operator *(const Vector3 &a) const { return x*a.x + y*a.y + z*a.z; }}; ///////////////////////////////////////////////////////////////// 非成员函数/////////////////////////////////////////////////////////////// // 求向量模inline float vectorMag(const Vector3 &a){ return sqrtf(a.x*a.x + a.y*a.y + a.z*a.z);} // 计算向量叉乘inline Vector3 crossProduct(const Vector3 &a, const Vector3 &b){ return Vector3( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x );} // 实现标量左乘inline Vector3 operator *(float k, const Vector3 &v){ return Vector3(k*v.x, k*v.y, k*v.z);} // 计算两点间距离inline float distance(const Vector3 &a, const Vector3 &b){ float dx = a.x-b.x; float dy = a.y-b.y; float dz = a.z-b.z; return sqrtf(dx*dx + dy*dy + dz*dz);} ///////////////////////////////////////////////////////////////// 全局变量/////////////////////////////////////////////////////////////// // 提供一个全局零向量extern const Vector3 kZeroVector; #endif // __VECTOR3_H__
1.2 物理学
本书中定义物理学如下:质量和能量以及它们之间互相作用的科学。游戏人工智能程序员常常会运用物理定律进行工作,特别是与运动有关的物理定律,即在这部分会介绍的内容。
1.2.1 时间
时间是一个标量(用它的大小就可以完全确定,没有方向),用秒来度量,简写成s。
1.2.2 距离
距离(一个标量)的标准单位是m (米)。
1.2.3 质量
质量是一个标量,用千克度量,简写成kg。质量是一个事物的总量的度量(不包括外力)。
1.2.4 位置
位置是相对于质心来度量的属性,质量的中心是物体的平衡点。假想在这一点上系一根绳子悬挂物体,物体可以在任何一个位置都保持平衡。另一
个想象质心的好方法是把它看作物体内所有质量的平衡位置。
1.2.5 速度
速度是一个矢量(一个具有大小和方向的量),表达了距离相对于时间的变化率。度量速度的标准单位是mls (米每秒)。它用数学公式表达为:
Δx表示距离上的变化,结束时候的距离减去开始移动时候的距离。Δt代表速度上的变化,结束时的时间减去开始移动时候的时间。
1.2.6 加速度
加速度是一个矢量,表达的是在时间段上速度的变化率,用米每二次方秒来度量,写作m/s²。加速度可以用数学式表达为:
1.2.7 力
力( Force) 是可以改变物体的速度或者运动线路的量。
我们知道如果施加在一个物体上的合力是非零的,就在该力的方向上产生了一个加速度;但是加速度是多少?答案是加速度的大小a 与物体的质量m 成反比,与所施加的合力F 成正比。这个关系可以用下式给出:
更多情况下,你将会看到写成这样的公式:
使用这个公式,如果我们知道一个物体的加速度有多大,并且知道它的质量,就可以计算施加在它上面的合力。
例如,如果一个物体的质量为2000kg ,井且它的加速度为1.5m/s²,施加在它上面的合力是: