前三章主要是一些数学概念和定理,主要记录了一下名词与基本概念。
向量
向量 (Vector)兼具大小(或称 模,magnitude)和方向。
向量与坐标系
当一个向量的尾部位于原点时,成该向量位于 标准位置(standard position)。
书中术语“框架”(frame)、“参考系”(frame of reference)、“空间”(space)和“坐标系”(coordinate system)表示相同的意义。
左手坐标系与右手坐标系
Direct3D 采用的是左手坐标系。
长度和单位向量
把一个向量的长度变为单位长度成为向量的 规范化(normalizing)处理。规范化的实现方法:
u=∥u∥u=(∥u∥x,∥u∥y,∥u∥z)
点积
点积 (dot product,又称数量积或内积),有时也称为 标量积(scalar product)。点积的定义:
u⋅v=uxvx+uyvy+uzvz
余弦定理(law of cosines):
u⋅v=∥u∥∥v∥cosθ
如果 u⋅v=0,称两个向量 正交(orthogonal)或垂直(perpendicular)。
向量 v 落在向量 n 上的 正交投影 (orthogonal projection)p 通常表示为:
p=projn(v)
通过把向量 n 替换为单位向量 ∥n∥n 可得到一般性的投影公式:
p=projn(v)=(v⋅∥n∥n)∥n∥n=∥n∥2(v⋅n)n
正交化
如果向量集 {v0,…,vn−1} 中任意向量两两正交且皆具单位长度,成此集合是 规范正交(orthonormal)的。
规范正交集有时由于处理过程中数值精度的问题,会逐步变成非规范正交集。这是需要正交化。
设有向量集{v0,v1,v2},希望将它正交化为正交集{w0,w1,w2},则令:
w0w1w2=v0=v1−projw0(v1)=v2−projw0(v2)−projw1(v2)
对于 n 个向量的一般集合 {v0,…,vn−1},为将其正交化为规范正交集{w0,…,wn−1},则使用 格拉姆 - 施密特正交化 方法:
基本步骤:设w0=v0
对于1≤i≤n−1,令wi=vi−∑j=0i−1projwj(vi)
规范化步骤:令wi=∥wi∥wi
叉积
乘法的第二种形式是 叉积(cross product,亦称向量积、外积)。如果u=(ux,uy,uz),v=(vx,vy,vz),那么叉积的计算方法为:
w=u×v=(uyvZ−uzvy,uzvx−uxvz,uxvy−uyvx)
如果伸出左手,大拇指伸出,向量 u 按四指旋转方向旋转到向量 v 时,且小于等于 180°,则向量 w 沿着大拇指方向,反之则与大拇指反方向。这就是 左手拇指法则(left-hand-thumb rule),也称左手定则。
叉积具有反交换律:
u×v=−v×u
使用叉积处理将近乎规范正交的向量集 {v0,v1,v2} 完全正交化:
- 令w0=∥v0∥v0。
- 令w2=∥w0×v1∥w0×v1。
- 令w1=w2×w0。
此时向量积 {w0,w1,w2} 是规范正交的。
DirectXMath 库
该数学库采用 SSE2 指令集,借助 128 位宽的 SIMD 寄存器,利用一条指令即可同时对 4 个 32 位浮点数或整数进行运算。
向量类型
DirectXMath 中核心的向量类型是XMVECTOR。开启 SSE2 后,该类型在 x86 和 x64 的定义是:
1
| typedef __m128 XMVECTOR;
|
类中的成员变量,建议分别使用 XMFLOAT2(2D 向量)、XMFLOAT3(3D 向量)和XMFLOAT4(4D 向量)来加以代替。转化过程可通过库的加载函数(loading function)实现。相反地,库提供了将XMVECTOR 类型转换为 XMFLOATn 类型地存储函数(storage function)。
总结:
- 局部变量或全局变量使用
XMVECTOR 类型。
- 对于类中的数据成员,使用
XMFLOAT2、XMFLOAT3)和XMFLOAT4 类型。
- 运算前通过加载函数将
XMFLOATn 转换为XMVECTOR。
- 用
XMVECTOR 实例进行运算。
- 通过存储函数将
XMVECTOR 转换为XMFLOATn。
加载方法和存储方法
1 2 3 4
| XMVECTOR XM_CALLCONV XMLoadFloat3 (const XMFLOAT3 *pSource);
void XM_CALLCONV XMStoreFloat3 (XMFLOAT3 *pDestination, FXMVECTOR V);
|
参数的传递
可将 XMVECTOR 的值作为函数的参数,直接传送至 SSE/SSE2 寄存器,而不是栈内。
一定要把约定注解 XM_CALLCONV 加在函数名前,它会根据编译器版本确定对应的调用约定属性。构造函数除外。
传递 XMVECTOR 参数的规定如下:
- 前 3 个参数用类型
FXMVECTOR;
- 第 4 个参数用类型
GXMVECTOR;
- 第 5、6 个参数用类型
HXMVECTOR;
- 其余参数用
CXMVECTOR;
32 位 Windows 上的调用约定:
1 2 3 4 5 6 7 8 9 10 11
| typedef const XMVECTOR FXMVECTOR; typedef const XMVECTOR& GXMVECTOR; typedef const XMVECTOR& HXMVECTOR; typedef const XMVECTOR& CXMVECTOR;
typedef const XMVECTOR FXMVECTOR; typedef const XMVECTOR GXMVECTOR; typedef const XMVECTOR HXMVECTOR; typedef const XMVECTOR& CXMVECTOR;
|
常向量
XMVECTOR类型的常量实例应当用 XMVECTORF32 类型表示。例:
1
| static const XMVECTORF32 g_vHalfVector = {0.5f, 0.5f, 0.5f, 0.5f};
|
重载运算符
XMVECTOR类型针对加法、剑法、标量乘法提供了对应的重载运算符。
杂项
库中定义了一组与 π 有关的常量XM_PI、XM_2PI、XM_1DIVPI、XM_1DIV2PI、XM_PIDIV2、XM_PIDIV4。
内联函数 XMConvertTORadians、XMConvertTODegrees 实现了弧度与角度的相互转化。
Setter
1 2 3 4 5 6 7 8
| XMVECTOR XM_CALLCONV XMVectorZero ();
XMVECTOR XM_CALLCONV XMVectorSplatOne ();
XMVECTOR XM_CALLCONV XMVectorSet (float x, float y, float z, float w);
XMVECTOR XM_CALLCONV XMVectorReplicate (float Value);
|
向量函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| XMVECTOR XM_CALLCONV XMVector3Length (FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVector3LengthSq (FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVector3Dot (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR XM_CALLCONV XMVector3Cross (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR XM_CALLCONV XMVector3Normalize (FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVector3Orthogonal (FXMVECTOR V);
XMVECTOR XM_CALLCONV XMVector3AngleBetweenVectors (FXMVECTOR V1, FXMVECTOR V2);
XMVECTOR XM_CALLCONV XMVector3ComponentsFromNormal (XMVECTOR* pParallel, XMVECTOR* Perpendicular, FXMVECTOR V1, FXMVECTOR V2);
bool XM_CALLCONV XMVector3Equal (FXMVECTOR V1, FXMVECTOR V2);
bool XM_CALLCONV XMVector3NotEqual (FXMVECTOR V1, FXMVECTOR V2);
|
浮点数误差
比较浮点数时,需要定义一个 Epsilon 常量,作为针对浮点数的误差问题的容差(tolerance)。
对此,库提供了 XMVector3NearEqual 函数:
1
| XMFINLINE bool XM_CALLCONV XMVector3NearEqual (FXMVECTOR U, FXMVECTOR V, FXMVECTOR Epsilon);
|