美文网首页
六、OpenGL 中的向量、矩阵

六、OpenGL 中的向量、矩阵

作者: 致青春_bf42 | 来源:发表于2020-07-17 15:00 被阅读0次

    向量

    1. 首先让我们了解什么是标量

    标量亦称“无向量”。有些物理量,只具有数值大小,而没有方向,部分有正负之分。这些量之间的运算遵循一般的代数法则。用通俗的说法,标量是只有大小,没有方向的量。
    物理学中,标量指在坐标变换下保持不变的物理量。

    2. 那什么是向量呢?

    向量是有方向的标量,即不仅有大小,还有方向

    2.1 单位向量

    在 X轴上的向量 (1,0,0). 向量⻓度为1. 我们称为⻓度为1的向量为单位向量.
    向量⻓度(向量的模)计算公式: 如果⼀个向量不是单位向量, ⽽我们把它缩放到1.这个过程叫做标准化. 将⼀个向量进⾏标准化就是将它的缩为1; 也叫做单位化向量

    向量长度通过下列公式计算
    2251862-a4150ad957f82d09.png
    2.2 向量 点乘
    • 点乘只能发生在两个向量之间,且点乘时,两向量必须是单位向量,如果不是,需要将向量进行单位化后,再点乘
    • 点乘得到的是两个向量之间的夹角的余弦值 即 cos α,范围在[-1, 1]之间,是一个标量
    2251862-e68f9ca988b7a75c.png
    • OpenGL中针对相应点乘,提供了两个函数
    #mark m3dDotProduct3:获得2个向量量之间的点乘结果,即余弦值 = cos α
    float  m3dDotProduct3(const M3DVector3f u,const M3DVector3f v)
    
     #mark m3dGetAngleBetweenVector3:获取2个向量之间夹⻆的弧度值,即α = arccos(余弦值)
    float m3dGetAngleBetweenVector3(const M3DVector3f u,const M3DVector3f v);
    
    2.3 向量 叉乘
    • 两个向量之间叉乘得到结果同样是一个向量,且该向量垂直于两个向量所构成的平面
    • 由于结果与两向量构成平面垂直,也可以理解为得到的结果是该平面的法线
    2251862-5e6585de9ac775a4.png
    • OpenGL中针对相应叉乘,也提供了函数
    #mark m3dCrossProduct3 函数获得2个向量之间的叉乘结果得到⼀个新的向量
    void m3dCrossProduct3(M3DVector3f result,const M3DVector3f u ,const M3DVector3f v);
    
    2.3 OpenGL 如何定义向量 [ math3d 库]

    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
    };
    

    矩阵

    1. 我们为什么要用矩阵

    假设, 在空间有⼀个点.使⽤ xyz 描述它的位置. 此时让其围绕任意位置旋转⼀定⻆度后. 我们需要知道这个点的新的位置. 此时需要通过矩阵进⾏计算;
    为什么?
    因为新的位置的x 不单纯与原来的x还和旋转的参数有关. 甚⾄于y和z坐标有关;矩阵只有⼀⾏或者⼀列都是合理的. 只有⼀⾏或者⼀列数字可以称为向量. 也可以称为矩阵;

    2. 单位矩阵
    • 主对角线上数据都是1,其余元素都是0,即为单元矩阵
    • 向量 X 单元矩阵 = 向量 X 1,不会发生任何变化
    • 向量与单元矩阵相乘的前提是:向量的列数 == 单元矩阵的行数
    2.1 矩阵分类
    • 行优先矩阵:一行一行读取
    • 列优先矩阵:一列一列读取
    • 两者的关系为:行优先矩阵经过转置 即可的到列优先矩阵
    2251862-3c95268cd1ee2e11.png
    2.2 矩阵的点乘
    • 矩阵可以进行点乘的前提:两个矩阵的行列数相等
    • 矩阵A · 矩阵B = 矩阵C
    2251862-10d9214dcad60b5e.png
    2.3 矩阵的叉乘
    • 矩阵可以进行叉乘的前提:第一个矩阵的列数 = 第二个矩阵的行数
    • 矩阵A X 矩阵B = 矩阵C
      矩阵A第一行与矩阵B第一列对应元素乘积的综合 = 矩阵C的第一个元素
      2251862-6c438eca22426bb8.png
    2.4 OpenGL中的矩阵
    • OpenGL中单元矩阵有3中初始化方法
    #mark 1.通过GLFloat定义一个一维数组
    GLFloat m[] = {
    1,0,0,0, //X Column
    0,1,0,0, //Y Column
    0,0,1,0, //Z Column
    0,0,0,1 // Translation
    }
    
    #mark  2.单元矩阵初始化⽅式 
    M3DMatrix44f m = {
    1,0,0,0, //X Column
    0,1,0,0, //Y Column
    0,0,1,0, //Z Column
    0,0,0,1 // Translation
    }
    
    #mark  3.单元矩阵初始化⽅式
    void m3dLoadIdentity44f(M3DMatrix44f m); 
    
    
    • OpenGL中,使用较多的矩阵都是一维数组创建的,且规定使用以列为主的矩阵排序。
    • OpenGL中的矩阵都是4x4的,每一列都是由4个元素组成的向量,⼀个4*4矩阵是如何在3D空间中表示⼀个位置和⽅向的列向量
      特别的标注:矩阵的最后⼀⾏都为0,只有最后⼀个元素为1
    • 如果将⼀个对象所有的顶点向量 乘以这个矩阵,就能让整个
      对象变换到空间中给定的位置和⽅向;


      截屏2020-07-16 下午11.16.38.png
    2.5 OpenGL中的矩阵相乘
    2.5.1 线性代数角度去分析
    • 数学中为了方便计算,都是以行矩阵为标准,从左到右的顺序进行计算,所以在数学中,顶点将以行向量的方式表示
    • 从数学角度理解mvp矩阵的计算,由于顶点是行向量,要满足矩阵相乘的规定条件(即 叉乘的前提),必须将mvp矩阵放在右边,属于右乘
      顶点向量 = V_local * M_model * M_view * M_pro
      顶点向量 = 顶点 * 模型矩阵 * 观察矩阵 * 投影矩阵
    截屏2020-07-17 下午2.09.45.png
    2.5.2 OpenGL角度
    • OpenGL中的矩阵规定是以列为主,所以顶点以列向量的方式表示
    • 从OpenGL角度理解mvp矩阵的计算,由于顶点是列向量,如果项进行矩阵规则,就需要满足矩阵相乘的条件,需要将mvp矩阵的顺序颠倒为pvm,且放在列向量的左边,属于左乘
      变换顶点向量 = M_pro * M_view * M_model * V_local
      变换顶点向量 = 投影矩阵 * 视图变换矩阵 * 模型矩阵 * 顶点
      截屏2020-07-17 下午2.20.30.png
    OpenGL矩阵堆栈中矩阵相乘源码分析
    • 1.从栈顶获取栈顶矩阵,复制到mTemp
    • 2.将栈顶矩阵 mTemp 左乘 mMatrix
    • 3.将结果放回栈顶,覆盖栈顶矩阵
    源码分析

    而我们在观察者不动、物体动的观察方式中,根据之前Demo代码可知

    代码分析
        //2.模型视图矩阵栈堆,压栈
        modelViewMatrix.PushMatrix();
        
        //3.获取摄像头矩阵
        M3DMatrix44f mCamera;
        //从camereaFrame中获取矩阵到mCamera
        cameraFrame.GetCameraMatrix(mCamera);
        //模型视图堆栈的 矩阵与mCamera矩阵 相乘之后,存储到modelViewMatrix矩阵堆栈中
        modelViewMatrix.MultMatrix(mCamera);
        
        //4.创建矩阵mObjectFrame
        M3DMatrix44f mObjectFrame;
        //从ObjectFrame 获取矩阵到mOjectFrame中
        objectFrame.GetMatrix(mObjectFrame);
        //将modelViewMatrix 的堆栈中的矩阵 与 mOjbectFrame 矩阵相乘,存储到modelViewMatrix矩阵堆栈中
        modelViewMatrix.MultMatrix(mObjectFrame);
    
    • 由此我们可以知道得到投影矩阵,将投影矩阵压入投影矩阵堆栈栈顶,并与模型视图矩阵栈顶相乘,将结果覆盖栈顶,即 投影矩阵 * 单元矩阵 = 投影矩阵
    • 将栈顶矩阵copy一份,然后将观察者矩阵与模型视图矩阵堆栈栈顶相乘,其结果覆盖栈顶矩阵,即投影矩阵 * 视图矩阵 = 视图投影矩阵
    • 得到模型矩阵,将模型矩阵与栈顶矩阵相乘,其结果覆盖栈顶矩阵,即 栈顶 = 模型视图投影矩阵
    2251862-fa5b4e4f8e28fcd5.png

    相关文章

      网友评论

          本文标题:六、OpenGL 中的向量、矩阵

          本文链接:https://www.haomeiwen.com/subject/fjnmhktx.html