OpenGL 向量/矩阵
向量
什么是向量
在3D笛卡坐标系中,基本上,一个顶点就是XYZ坐标空间上的一个位置。而在空间中给定的一个位置,恰恰是由一个单独的XYZ定义的。而这样的XYZ就是向量。长度为1的的向量为单位向量。向量长度计算公式为,
如果一个向量不是单位向量,而我们把它缩放到1,这个过程叫做标准化,将一个向量进行标准化就是将它缩为1;也叫做单位化向量。使用一个非零向量除以它的模(向量的长度),就可以得到方向相同的单位向量。
如下图所示,点A的坐标为 ,这个向量A在X轴上为+1,其它两个方向为0,向量长度为1,则点A为单位向量。
坐标系.jpg向量的定义
在math3d
库中,有两个数据类型,能够表示一个三维或四维向量。M3DVector3f
表示一个三维向量,M3DVector4f
表示一个四维向量。
OpenGL 中这两个数据类型本质上是一个一维浮点型数组,代码示例如下:
typedef float M3DVector3f[3];
typedef float M3DVector4f[4];
//声明一个三维变量
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
}
点乘
点乘只能发生在两个向量之间。两个三维单位向量之间进行点乘将得到一个标量(数值),它表示两个向量之间的夹角(余弦值)。math3d库中关于点乘的函数:
//获得两个向量之间点乘的结果
float m3dDotProduct3(const M3DVector3f u,const M3DVector3f v);
//获得两个向量之间夹角的弧度值
float m3dGetAngleBetweenVector3(const M3DVector3f u,const M3DVector3f v);
叉乘
两个向量(不必为单位向量)之间叉乘所得的结果是另外一个向量,这个新向量与原来两个向量定义的平面垂直。math3d库中关于叉乘的函数:
void m3dCrossProduct3(M3DVector3f result,const);
矩阵
在数学上,矩阵只不过是一组排列在统一的行和列中的数字。用程序设计语言的语言来说就是一个二维数组。如果在空间中有一个点,由x,y和z坐标定义,将它围绕任意点沿任意方向旋转一定角度后,我们需要这个点现在的位置,就要用到矩阵。
矩阵之间可以进行乘法和加法,也能与向量或者标量相乘。用一个向量乘以一个矩阵(一次变化)结果得到一个新的变化点(向量)。math3d库中关于矩阵的定义:
//3维矩阵
typedef float M3DMatrix33f[9];
//4维矩阵
typedef float M3DMatrix44f[16];
矩阵的构造
在其他编程标准中,许多矩阵库定义一个矩阵时,使用二维数组;在OpenGL里,更多倾向于使用一维数组;这样做的原因是OpenGL使用的是Column-Major(以列为主)矩阵排序的约定。
在4*4矩阵中,这16个值表示了空间中的一个特点位置,以及相对于视觉坐标系的3个轴的方向。这4列中每一列都代表一个由4个元素组成的向量。前3列的前3个元素只是方向向量,他们表示空间中x轴、y轴和z轴上的方向,第4列包含变换后的坐标系原点的x、y和z值。
特别地,矩阵的最后一行都为0,只有最后一个元素为1。
4*4矩阵.png如果将一个对象所有的顶点向量乘以这个矩阵,就能让整个对象变换到空间中给定的位置和方向。
单元矩阵
将一个向量乘以一个单位矩阵,就等与用这个向量乘以1,不会发生任何改变。
-
初始化方式①
GLFloat m[] = { 1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1 }
-
初始化方式②
M3DMatrix44f m = { 1,0,0,0 0,1,0,0, 0,0,1,0, 0,0,0,1 }
-
初始化方式③
void m3dLoadIdentity44f(M3DMatrix44f)
理解变换
变化 | 解释 |
---|---|
视图变换 | 指定观察者位置 |
模型变换 | 在场景中移动物体 |
模型视图 | 描述视图/模型变化的二元性 |
投影 | 改变视景体大小和它的投影方式 |
视口 | 伪变化,对窗口上最终输出进行缩放 |
-
视图变换
视图变换将观察者放在希望的任何位置,并允许在任何方向上观察场景,确定视图变换就像在场景中放置照相机并让它指向某个方向。
-
模型变换
模型变化用于操纵模型和其中的特定对象。这些变换将对象移动到需要的位置,然后在对它们进行旋转和缩放。
-
平移
void m3dTranslationMatrix44(M3DMatrix44f m ,float x,float y,float z)
-
旋转
void m3dRotationMatrix44(M3DMatrix44f m ,float angle,float x,float y,float z)
-
缩放
void m3dScaleMatrix44(M3DMatrix44f m ,float xScale,float yScale,float zScale
-
综合变换
void m3dMatrixMultiply44(M3DMatrix44f product,const M3DMatrix44f a,const M3DMatrix44f b)
-
几何图形
创建一个球体
/*
gltMakeSphere(GLTriangleBatch& sphereBatch, GLfloat fRadius, GLint iSlices, GLint iStacks);
参数1:sphereBatch,三角形批次类对象
参数2:fRadius,球体半径
参数3:iSlices,从球体底部堆叠到顶部的三角形带的数量;其实球体是一圈一圈三角形带组成
参数4:iStacks,围绕球体一圈排列的三角形对数
建议:一个对称性较好的球体的片段数量是堆叠数量的2倍,就是iStacks = 2 * iSlices;
绘制球体都是围绕Z轴,这样+z就是球体的顶点,-z就是球体的底部。
*/
gltMakeSphere(sphereBatch, 3.0, 10, 20);
创建一个环面
// 环面
/*
gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
参数1:torusBatch,三角形批次类对象
参数2:majorRadius,甜甜圈中心到外边缘的半径
参数3:minorRadius,甜甜圈中心到内边缘的半径
参数4:numMajor,沿着主半径的三角形数量
参数5:numMinor,沿着内部较小半径的三角形数量
*/
gltMakeTorus(torusBatch, 3.0f, 0.75f, 15, 15);
创建一个圆锥
/*
void gltMakeCylinder(GLTriangleBatch& cylinderBatch, GLfloat baseRadius, GLfloat topRadius, GLfloat fLength, GLint numSlices, GLint numStacks);
参数1:cylinderBatch,三角形批次类对象
参数2:baseRadius,底部半径
参数3:topRadius,头部半径
参数4:fLength,圆形长度
参数5:numSlices,围绕Z轴的三角形对的数量
参数6:numStacks,圆柱底部堆叠到顶部圆环的三角形数量
*/
gltMakeCylinder(cylinderBatch, 2.0f, 2.0f, 3.0f, 15, 2);
创建一个锥
/*
void gltMakeCylinder(GLTriangleBatch& cylinderBatch, GLfloat baseRadius, GLfloat topRadius, GLfloat fLength, GLint numSlices, GLint numStacks);
参数1:cylinderBatch,三角形批次类对象
参数2:baseRadius,底部半径
参数3:topRadius,头部半径
参数4:fLength,圆形长度
参数5:numSlices,围绕Z轴的三角形对的数量
参数6:numStacks,圆柱底部堆叠到顶部圆环的三角形数量
*/
//圆柱体,从0开始向Z轴正方向延伸。
//圆锥体,是一端的半径为0,另一端半径可指定。
gltMakeCylinder(coneBatch, 2.0f, 0.0f, 3.0f, 13, 2);
创建一个磁盘
/*
void gltMakeDisk(GLTriangleBatch& diskBatch, GLfloat innerRadius, GLfloat outerRadius, GLint nSlices, GLint nStacks);
参数1:diskBatch,三角形批次类对象
参数2:innerRadius,内圆半径
参数3:outerRadius,外圆半径
参数4:nSlices,圆盘围绕Z轴的三角形对的数量
参数5:nStacks,圆盘外网到内围的三角形数量
*/
gltMakeDisk(diskBatch, 1.5f, 3.0f, 13, 3);
矩阵堆栈
在GLTools库中有一个矩阵堆栈来帮助完成矩阵变换,这个类称为GLMatrixStack
。
堆栈操作
-
初始化
这个类的构造函数允许指定堆栈的最大深度,默认的堆栈深度为64。在初始化堆栈时,已经包含了单位矩阵。
GLMatrixStack::GLMatrixStack(int iStackDepth = 64);
-
栈顶载入矩阵
-
单位矩阵
void GLMatrixStack::LoadIdentity(void);
-
任一矩阵
void GLMatrixStack::LoadMatrix(const M3DMatrix44f m);
-
-
矩阵栈顶元素与新元素相乘后的结果存储在堆栈顶部
void GLMatrixStack::MultMatrix(const M3DMatrix44f);
-
获取栈顶元素
-
获取值
const M3DMatrix44f & GLMatrixStaxk::GetMatrix(void);
-
获取副本
void GLMatrixStaxk::GetMatrix(M3DMatrix44f mMatrix);
-
-
压栈
-
栈顶矩阵Copy到栈顶
void GLMatrixStack::PushMatrix(void);
-
将M3DMatrix44f 矩阵对象压入当前矩阵堆栈
void PushMatrix(const M3DMatrix44f mMatrix);
-
将GLFrame对象压入堆栈
void PushMatrix(GLFrame &frame);
-
-
出栈
void GLMatrixStack::PopMatrix(void);