一、向量
1. 向量的定义
- 向量: 具有大小和方向的量
- 标量:只有大小,例如:1, 2, 3等
- 向量的模(大小): 也就是向量的大小, 向量a的模记作|a|
- 单位向量: 长度为一个单位(即模为1)的向量
- 标准化:如果一个向量不是单位向量,而我们把它缩放到1,这个过程就叫标准化
- 单位向量化:将一个向量进行标准化就是把它的长度缩放为1
在 3D 笛卡尔坐标系, 基本上一个顶 就是XYZ 坐标空间上的一个位置。 而在空间中给定的一个位置恰恰是由一个单独的XYZ 定义的。 而这样的XYZ 就是向量。在数学思维中,⼀个顶点也就是一个向量。
2. OpenGL如何定义向量
GLTools
库中有一个组件叫Math3d
,其中包含了⼤量好用的OpenGL已知的3D数学和数据类型。
Math3d
库,有2个数据类型,能够表示一个三维或者四维向量。
-
M3DVector3f
可以表示⼀个三维向量(x,y,z) -
M3DVector4f
则可以表示一个四维向量(x,y,z,w).
在典型情况下,w坐标设为1.0。x,y,z值通过除以w,来进行缩放。而除以1.0则本质上不改变x,y,z值。
参考代码
// 三维向量/四维向量的声明
typedef float M3DVector3f[3];
typedef float M3DVector4f[4];
//声明一个三维向量 M3DVector3f:类型 vVector:变量名
M3DVector3f vVector;
//声明⼀个四维向量并初始化⼀个四维向量
M3DVector4f vVertex = {0,0,1,1};
//声明一个三分量顶点数组,例如为了生成⼀个三⻆形 //
M3DVector3f vVerts[] = {
-0.5f,0.0f,0.0f,
0.5f,0.0f,0.0f,
0.0f,0.5f,0.0f
};
4.向量点乘
-
向量可以进行加法、减法运算,也可以简单地通过加法、减法进行缩放,或者对XYZ分量单独进行缩放。然而还有一种有趣又有用的操作称为点乘(
dot product
),这种操作只能在两个向量之间进行。 -
两个(三分量)单位向量之间的点乘运算将得到一个标量(不是三维向量,只有一个标量),它表示两个向量之间的夹角。
1. 前提条件:两个向量必须是单位向量 2. 动作:两个三维向量之间进行点乘 3. 结果:返回⼀个[-1,1]范围的值. 这个值其实就是夹⻆的cos值(余弦值)
math3d
库中也包含一些有用的函数使用点乘操作。
// 获取两个向量的点乘结果
float m3dDotProduct3(const M3DVector3f u, const M3DVector3f v);
//获取两个向量夹角的弧度制
float m3dGetAngleBetweenVectors3(const M3DVector3f u, const M3DVector3f v);
5.向量叉乘
2个向量之间叉乘就可以得到另外⼀个向量,新的向量会与原来2个向量定义的平⾯垂直. 要进行叉乘,这两个向量都不必为单位向量”。
1. 前提条件:两个普通向量
2. 动作:向量与向量叉乘
3. 结果:向量(垂直于原来2个向量定义的平面的向量)
叉乘运算的结果返回一个新的向量,这个新向量与原来两个向量垂直.
math3d
库中提供了了关于叉乘的API
// m3dCrossProduct3 函数获得2个向量之间的叉乘结果得到一个新的向量
void m3dCrossProduct3(M3DVector3f result,const M3DVector3f u ,const
M3DVector3f v);
二、基础变换
OpenGL中涉及的基础变化主要有以下5种:
变换 | 解释 |
---|---|
视图变换 | 指定观察者位置 |
模型变换 | 在场景中移动物体 |
模型视图变换 | 描述视图/模型变换的⼆元性(2种看到模型转换的⽅式 ) |
投影变换 | 改变视景体⼤⼩和设置它的投影⽅式 |
视⼝变换 | 伪变化,对窗⼝上最终输出进⾏缩放 |
1. 视觉坐标
下图显示了两个不同视点的视觉坐标系。
- a图中,视觉坐标系是以场景的观察者的角度(也就是垂直于显示器的方向)。
- b图中,视觉坐标系稍稍进行了旋转,这样就可以更好地观察z 轴的位置关系了。
-
从观察者的角度来看,x 轴和y 轴的正方向分别指向右方和上方。z 轴的正方向从原点指向使用者,而z 轴的负方向则从观察者指向屏幕内部。
2. 视图变换
- 视图变换是应用到场景中的第一种变换。
- 在默认情况下,透视投影中的观察点位于原点(0,0,0),并沿着z 轴的负方向进行观察(向显示器内部“看进去”),一般通过moveForward方法来调整观察者位置,moveForward默认的朝向是-z轴,所以向屏幕里面移动传正数值,向屏幕外即+z轴,需要传负数值
-
从大局上考虑,在应用任何其他模型变换之前,必须先应用视图变换。这样做是因为,对于视觉坐标系而言,视图变换移动了当前的工作坐标系。所有后续变换随后都会基于新调整的坐标系进行。
3. 模型变换
-
模型变换其实就是物体通过平移、旋转、缩放的操作,将物体移动到你想要的位置的一个过程.
平移
-
模型变换中,两个变换的顺序是不能交换的,交换后的矩阵相乘结果是不一致的,如下图,交换平移和旋转的顺序,得到的结果完全不一致
- 造成这种情况的根本原因,主要还是因为矩阵相乘采用的是矩阵的叉乘,而矩阵叉乘是不满足交换律的。
4. 模型视图变换
- 视图和模型变换按照它们内部效果和对场景的最终外观来说是一样的。将这两者区分开纯粹是为了程序员的方便。将对象向后移动和将参考坐标系向前移动在视觉上没有区别。
- “视图变换和模型变换一样,都应用在整个场景中,在场景中的对象常常在进行视图变换后单独进行模型变换。术语“模型视图”是指这两种变换在变换管线中进行组合,成为一个单独的矩阵,即模型视图矩阵。
5. 投影变换
- 在正投影(或者说平行投影)中,所有多边形都是精确地按照指定的相对大小来在屏幕上绘制的。线和多边形使用平行线来直接映射到2D屏幕上,这就意味着,无论某个物体的位置有多远,它都会按照同样的大小来进行绘制,仅仅是平贴到屏幕上而已。典型情况下,这种投影用于渲染二维图像,例如蓝图或者是文本或屏幕菜单等二维图形。
- 透视投影所显示的场景与现实生活中更加接近,而不是一张蓝图。透视投影的特点就是透视缩短(foreshortening),这种特性使得远处的物体看起来比近处同样大小的物体更小一些。3D空间中应该是平行的线可能在观察者看来不总是平行的。例如,对于铁轨来说,两根铁轨是平行的,但是在使用透视投影的情况下,它们看起来将在远处的某一点汇聚在一起。
6. 视口变换
-将得到的一个场景的二维投影,它将被映射到屏幕上某处的窗口上。这种到物理窗口标的映射是我们最后要做的变换,称为视口变换
三、矩阵
1. 单位矩阵
- 主对角线上数据都是1,其余元素都是0,即为单元矩阵
- 向量 X 单元矩阵 = 向量 X 1,不会发生任何变化
- 向量与单元矩阵相乘的前提是:向量的列数 = 单元矩阵的行数
2. 矩阵分类
- 行优先矩阵:一行一行读取
- 列优先矩阵:一列一列读取
- 行优先矩阵经过转置即可的到列优先矩阵
3. 矩阵相乘
矩阵乘法基本上意味着遵照规定好的法则进行相乘。
- 只有当左侧矩阵的列数与右侧矩阵的行数相等,两个矩阵才能相乘。
-
矩阵相乘不遵守交换律(Commutative),也就是说A⋅B≠B⋅A。
4. 矩阵堆栈
矩阵堆栈是由GLMatrixStack类创建的,其特性是先进后出,根据矩阵类的源码可知,矩阵堆栈中最大只能放64个状态.
矩阵堆栈中关于入栈、相乘、出栈的流程
- 原始矩阵堆栈中,拷贝一份栈顶矩阵,压入栈顶
- 当有变换操作时,将变换操作的矩阵与矩阵堆栈栈顶相乘,将其结果覆盖栈顶矩阵
- 如果还有其他矩阵入栈,则继续相乘
- 当没有矩阵需要push,即图形绘制完成后,需要pop栈顶矩阵
网友评论