OpenGL 向量/矩阵

2020-07-22  本文已影响0人  _涼城
向量
什么是向量

  在3D笛卡坐标系中,基本上,一个顶点就是XYZ坐标空间上的一个位置。而在空间中给定的一个位置,恰恰是由一个单独的XYZ定义的。而这样的XYZ就是向量。长度为1的的向量为单位向量向量长度计算公式为,

\sqrt[2]{x^2+y^2+z^2}

  如果一个向量不是单位向量,而我们把它缩放到1,这个过程叫做标准化,将一个向量进行标准化就是将它缩为1;也叫做单位化向量。使用一个非零向量除以它的模(向量的长度),就可以得到方向相同的单位向量。

  如下图所示,点A的坐标为(1,0,0) ,这个向量A在X轴上为+1,其它两个方向为0,向量长度为1,则点A为单位向量

坐标系.jpg
向量的定义

  在math3d库中,有两个数据类型,能够表示一个三维或四维向量。M3DVector3f表示一个三维向量(x,y,z)M3DVector4f表示一个四维向量(x,y,z,w)

  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,不会发生任何改变。

理解变换
变化 解释
视图变换 指定观察者位置
模型变换 在场景中移动物体
模型视图 描述视图/模型变化的二元性
投影 改变视景体大小和它的投影方式
视口 伪变化,对窗口上最终输出进行缩放
几何图形
创建一个球体
  /*
      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

堆栈操作
上一篇下一篇

猜你喜欢

热点阅读