一、点和矢量
(一)坐标系分类
- 笛卡尔坐标系;
- 圆柱坐标系;
- 球坐标系;
通常来说笛卡尔坐标系是我们最常用的坐标系,但我们同样要根据不同的情况来选择合适的坐标系,例如我们在做一些环绕动画的时候,采用圆柱坐标系可以更简单。
在三维笛卡尔坐标系中又分为左右手坐标系,用左右手来方便做记忆,大拇指指向X轴,食指指向Y轴,中指指向Z轴,3指垂直即可建立模型。左右坐标系的转换只需要把一个轴转换,保留另外两个轴的方向不变即可。对于三维图形程序员来说,一般以左手坐标系工作,并且Y轴向上,X轴向右,Z轴远离观察者(摄像机朝向),因此在三维图形渲染至二维屏幕时,Z坐标的增加就会增加景深。
(二)矢量运算
- 矢量与标量的乘法:
通常矢量与标量相乘都是保留矢量的方向,对矢量的模进行缩放。当然每个轴上的缩放因子也可以不相同,即非统一缩放,可表示为矢量与缩放矢量的分量积(反射光量可以使用RGB色值的分量积来计算)。
S x A = (SxAx, SyAy, SzAz)
- 加减法:
矢量加减法多用于合成运算,点与方向的运算。
- 方向 + 方向 = 方向
- 方向 - 方向 = 方向
- 点 + 方向 = 点
- 点 - 点 = 方向
- 点 + 点 = 无意义
(三)模
矢量的模是个标量,表示矢量在三维空间中的长度。
(四)应用
- 矢量加减法可以用来刷新运动物体每帧的位置;
- 球体相交测试的时候用矢量减法,模以及浮点比较来进行判断(在进行模运算的时候,计算平方根通常是费时的操作,所以在不影响准确性的情况下应该尽量改用模的平);
(五)矢量乘法
矢量的乘法有很多种,游戏编程中常见的有2种:
- 点积:
两个矢量的点积结果是一个标量,为两个矢量中每对分量乘积之和。
A · B = AxBx + AyBy + AzBz
点积也可以写成两个矢量的模相乘再乘以两矢量夹角的余弦。
A · B = |A||B|cosθ
点积符合交换律,加法上的分配律,标量乘法的结合律。
点击判定:点击非常适合用来判断两矢量是否共线或垂直,或测试两矢量是否大致在相同或相反方向。
- 共线:(A · B) = |A||B| = AB
- 共线但是相反方向:(A · B) = -AB
- 垂直:(A · B) = 0
- 相同方向:(A · B) > 0
- 相反方向:(A · B) < 0
- 向量投影:给定两个向量v和n,可以把向量v分解为平行和垂直n的两个分量v1,v2。v1 = n(v·n)/|n|2,v2 = v - v1。
- 叉积:
两个矢量的叉积会产生一个垂直于原来两个矢量的矢量,叉积运算只定义在三维空间。
A x B = [(AyBz - AzBy), (AzBx - AxBz), (AxBy - AyBx)]
|A x B| = |A||B|sinθ
若A和B为平行四边形的两条边,其面积为两矢量叉积的模|A x B|。
叉积可以用来求法向量,力矩等。
点和矢量的线性插值,用来计算两个已知点的中间点。
L = LERP(A, B, θ) = (1-θ)A + θB
= [(1-θ)Ax + θBx, (1-θ)Ay + θBy, (1-θ)Az + θBz]
LERP函数是两矢量的加权平均。
关于向量相关的类我们可以在很多游戏引擎里面有看过,封装的方法也都是大同小异,这里介绍下封装过程中需要注意的细节:
- 数据类型:float还是double,根据实际的需求而定;
- 使用const成员函数;
- 使用const引用参数传地址避免以值传递调用一次构造提高效率,而且如果函数不是内联的,传值的方式会需要更多的堆栈空间和更长的参数压栈时间。
- 无缺省初始化:缺省构造函数不执行任何的初始化操作,因为向量类需要在严格要求速度的场合使用,建议不分配资源;
- 不使用虚函数:1、使用虚函数,优化器不能产生成员函数的内联代码;2、虚函数需要指向虚函数表的指针,向量定义时指针必须初始化,会使对象的大小增加25%,而存储包含向量的大数组是一种很普遍的现象。
- 全局常量:零
矩阵
4x4矩阵可表示任意三维变换,包括平移、旋转和缩放。仿射矩阵是一种4x4矩阵,它能维持直线在变换前后的平行性以及相对的距离比,但是不一定维持直线在变换前后的绝对长度及角度。
(一)矩阵乘法
P=AB,若A为缩放矩阵,B为旋转矩阵,则P等同于对点或矢量进行缩放和旋转变换。AB≠BA(AB不等于BA),矩阵乘法不符合交换律。
- 逆矩阵
矩阵A的逆矩阵能还原矩阵A的变换。若一个矩阵乘以它的逆矩阵,结果必然是单位矩阵。并非所有的矩阵都有逆矩阵。然而所有的仿射矩阵都有逆矩阵,可用高斯消去法或LU分解求之。
A(Aˉ1) = I
(ABC)ˉ1 = Cˉ1Bˉ1Aˉ1
- 转置矩阵
转置矩阵就是把原来的矩阵以主对角线为对称轴做反射,和逆矩阵相同,矩阵串接的转置为反向串接各个矩阵的转置。
齐次坐标
2x2矩阵来表示二维中的旋转:
3x3矩阵来表示三维中的旋转:
3x3矩阵是无法表示平移的:R + T = [(Rx + Tx), (Ry + Ty), (Rz + Tz)],虽然矩阵的乘法可以对元素进行相乘和相加,但是没有办法把T的分量放到3x3的矩阵中,使得与R相乘后产生(R+T)的值。
如果采用4x4矩阵就可以获得类似的和:
- 变换方向矢量
当用矩阵变换一个点时,平移、旋转、缩放都会施于该点上。但是,当用矩阵变换一个方向矢量时,就要忽略矩阵的平移效果。因为方向矢量本身并没有平移,加上平移会改变其模。
严格地说四维的齐次坐标转换为三维的非齐次坐标的方法是把x,y,z分量除以w分量:
[x y z w] = [x/w y/w z/w]
此公式表明,可设点的w分量为1,方向矢量的w为0。矢量除以w=1,并不影响点的坐标,矢量除以w=0则会产生无穷大。所以事实上三维空间的纯方向在四维齐次空间是位于无穷远的点。
基础变换矩阵
4x4矩阵可以切割为4个组成部分:
- 左上的3x3矩阵U,代表旋转/缩放
- 1x3平移矢量t
- 平移
平移矩阵的逆矩阵就是把t求反(即翻转tx,ty,tz的正负号)
- 旋转
纯旋转矩阵的逆矩阵即是该旋转矩阵的转置矩阵。
- 缩放
缩放矩阵的逆矩阵就是把Sx,Sy,Sz用倒数代替即可。
- 4x3矩阵
4x4的仿射矩阵中最右侧一定是一列[0 0 0 1]的矢量,所以可以略去第4列以节省内存。(在使用GPU做蒙皮的时候,要向顶点着色器传递大量的变换,所以为了节省空间、时间,通常会使用3x4矩阵)
版权声明:本文为博主原创文章,未经博主允许不得转载。