OpenGL的矩阵

作者: 黑眼豆豆_ | 来源:发表于2020-07-19 22:45 被阅读0次

假设,在空间中有一个点,使用XYZ描述它的位置。此时让它进行旋转或者平移,我们需要知道这个点的新位置,那么此时,我们就可以用矩阵进行计算得出新点的位置。

定义

矩阵(Matrix)是一个按照长方阵列排列的复数实数集合 [1] ,最早来自于方程组系数常数所构成的方阵

表达式

假如我们定义一个n行m列的矩阵A,那么我们可以用如下的公式进行表达:


矩阵.jpg

上图就是一个n行m列的矩阵,其中a为矩阵中的元素,a的第一个下标表示所处行的位置,第二个下标表示所处列的位置。

矩阵只有一行或者一列的时候,这个矩阵可以称之为向量。

在OpenGL中,矩阵可以进行以下定义:

//3*3的矩阵
M3DMatrix33f transform
//4*4的矩阵
M3DMatrix44f transform

矩阵的运算

  • 加法
    矩阵加法就是矩阵里对应的元素进行加法,公式如下:

    矩阵加法.jpg 矩阵的加法满足下列运算律:
    A+B = B+A
    (A+B)+C = A+(B+C)
    矩阵加法必须是同型矩阵,即A,B矩阵行列相同
  • 数乘
    矩阵的数乘等于数乘以矩阵里的每一个元素,公式如下:

    矩阵数乘.jpg
  • 转置
    把矩阵A的行和列互相交换所产生的矩阵称为A的转置矩阵 ,这一过程称为矩阵的转置。公式如下:

    矩阵转置.jpg
  • 矩阵相乘
    矩阵相乘公式如下:

    矩阵相乘.jpg 注意:两个矩阵的乘法仅当第一个矩阵A的列数和另一个矩阵B的行数相等时才能定义。例如,当A矩阵为mn矩阵时,B矩阵必须为nx才能进行矩阵相乘,切得到的结果为m**x。
    故矩阵相乘不满足交换律。

单元矩阵

单元矩阵是一个对角线为非零元素,其它元素为零的方形矩阵。


单元矩阵.jpg

上图就是一个单元矩阵,对角线元素为1,其他元素为0。
单元矩阵用m3d库定义方法:

//3*3的单元矩阵(float)
void m3dLoadIdentity33(M3DMatrix33f m);
//3*3的单元矩阵(double)
void m3dLoadIdentity33(M3DMatrix33d m);
//4*4的单元矩阵(float)
void m3dLoadIdentity44(M3DMatrix44f m);
//4*4的单元矩阵(double)
void m3dLoadIdentity44(M3DMatrix44d m);

行优先矩阵和列优先矩阵

行优先矩阵:指的是矩阵元素以行的顺序进行排列。
列优先矩阵:指的是矩阵元素以列的顺序进行排列。

行优先矩阵和列优先矩阵.jpg 在OpenGL中,我们一般使用列优先矩阵。

OpenGL中的变化

变换 解释
视图变换 观察者的位置变化
模型变换 在场景中物体的变换(平移、缩放、旋转等)
模型视图变换 模型、视图变换相乘后的结果
投影 改变视景体的大小和设置投影方式(正投影、透视投影)
视口 对窗口进行缩放

视图变换

一般来说,视图变换是引用场景中的第一个变换,它用来确定观察者的位置,默认情况中,在透视投影下位于原点(0,0,0),并沿着Z轴往负方向观察。(如同从屏幕上往屏幕里面看)。
为什么说,视图变换要放在最开始呢?
这是因为对于坐标系而言,进行试图变换,就会更换坐标系,接下来的变换都会基于新的坐标系进行。(就像我们看电视,会想用一个更舒服、更好的姿势进行观看)

模型变换

模型变换指的是针对物体进行的一系列操作变换,例如平移、旋转、缩放等。

  • 平移
    平移顾名思义指的是一个物体大小、弧度不变,按照一个方向进行移动。 平移
    如图所示,该正方形沿着Z轴进行了平移,公式如下:
//m是一个指针,存储了变换后的结果
//x表示x轴移动的距离
//y表示y轴移动的距离
//z表示z轴移动的距离
inline void m3dTranslationMatrix44(M3DMatrix44f m, float x, float y, float z)
  • 旋转
    *平移值得是一个物体 在某个点进行旋转
    image.png

如图所示,该正方形在原点进行旋转,公式如下:

//m是一个指针,存储了变换后的结果
//angle表示旋转的角度
//x表示x轴移动的距离
//y表示y轴移动的距离
//z表示z轴移动的距离
void m3dRotationMatrix44(M3DMatrix44d m, double angle, double x, double y, double z);
  • 缩放
    缩放指的是一个物体按一定比例进行大小的变换。
    image.png 公式如下:
//m是一个指针,存储了变换后的结果
//x表示x轴缩放的比例
//y表示y轴缩放的比例
//z表示z轴缩放的比例
inline void m3dScaleMatrix44(M3DMatrix44f m, float xScale, float yScale, float zScale)
  • 投影变换
    投影变换分为正投影和透视投影。 投影投影和正投影.jpg
    上图中,第一个投影是透视投影,模型距离屏幕越近时,物体看起来越大,越远时越小。
    第二个投影是正投影,不论物体的远近,大小看起来都是一样的。
  • 综合变换
    当我们需要对模型先进行平移火旋转时怎么处理呢?我们使用矩阵相乘。公式如下:
//product存放矩阵相乘后的结果
//a表示第一个矩阵
//b表示第二个矩阵
void m3dMatrixMultiply44(M3DMatrix44f product, const M3DMatrix44f a, const M3DMatrix44f b);

矩阵堆栈

在之前的用OpenGL绘制金字塔、圆环、扇形案例中,我们已经提到过矩阵堆栈。

矩阵堆栈.png
如上图所示,在栈的流程中,后来的矩阵都是通过push的方式往里面加入,而且新假如的矩阵都是存放在栈顶。当要离开栈时,需要用到pop方法,pop时是将栈顶的元素从栈中拿出来,所以栈遵循先进后出的规则(FILO)。

用法

  • 矩阵定义
//矩阵的深度为64
GLMatrixStack(int iStackDepth = 64);
  • 单元矩阵堆栈
//加载单元矩阵
inline void LoadIdentity(void) {
    m3dLoadIdentity44(pStack[stackPointer]); 
}

正如我们所说的矩阵堆栈流程,加载单元矩阵其实就是往栈顶加载一个元素,但是并没有告诉我们是什么元素,那就是默认添加一个单元矩阵。

  • 添加矩阵
//加载矩阵
inline void LoadMatrix(const M3DMatrix44f mMatrix) { 
    m3dCopyMatrix44(pStack[stackPointer], mMatrix); 
}

加载矩阵就是往栈顶添加了一个元素。

  • 矩阵相乘
inline void MultMatrix(const M3DMatrix44f mMatrix) {
      M3DMatrix44f mTemp;
      m3dCopyMatrix44(mTemp, pStack[stackPointer]);  
      m3dMatrixMultiply44(pStack[stackPointer], mTemp, mMatrix);
}

由代码可以看出,首先从栈顶复制一个矩阵存放在mTemp矩阵里,然后和传入的mMatrix相乘后存入栈顶。

  • 入栈(无参数)
inline void PushMatrix(void) {
            if(stackPointer < stackDepth) {
                stackPointer++;
                m3dCopyMatrix44(pStack[stackPointer], pStack[stackPointer-1]);
                }
            else
                lastError = GLT_STACK_OVERFLOW;
            }

可以看到,判断stackPointer是否大于栈的深度,如果小于,那么stackPointer加一,然后把栈里的第二个元素复制到栈顶

  • 入栈(有参数)
void PushMatrix(const M3DMatrix44f mMatrix) {
            if(stackPointer < stackDepth) {
                stackPointer++;
                m3dCopyMatrix44(pStack[stackPointer], mMatrix);
                }
            else
                lastError = GLT_STACK_OVERFLOW;
            }

可以看到,判断stackPointer是否大于栈的深度,如果小于,那么stackPointer加一,然后把传入的参数放到栈顶

  • 出栈
inline void PopMatrix(void) {
            if(stackPointer > 0)
                stackPointer--;
            else
                lastError = GLT_STACK_UNDERFLOW;
            }

把stackPointer--从而移除最顶上的元素。

相关文章

  • OpenGL中矩阵的行主序与列主序

    行主序与列主序 OpenGL中使用的矩阵,都是数学意义上的标准矩阵。但是各个OpenGL应用在实现矩阵时,根据存储...

  • OpenGL:矩阵的计算(平移,缩放,旋转)

    OpenGL:矩阵的计算(平移,缩放,旋转)

  • 音视频开发之旅(11) OpenGL ES矩阵变换与坐标系统

    目录 矩阵与矩阵变换 坐标系统 OpenGL的矩阵与矩阵变换 实践:平移、旋转、缩放、3D 资料 收获 一、矩阵与...

  • OPenGL 中的矩阵压栈/出栈

    我们知道OPenGL 中的图形变化是用矩阵来记录保存的.OpenGL 矩阵基础变化 简单来讲,当你做了一些移动或旋...

  • OpenGL--向量和矩阵

    在我们OpenGL中涉及到图形变换的时候经常会运用到向量/矩阵的运算。今天我们就来了解下OpenGL中的向量、矩阵...

  • OpenGL 矩阵

    矩阵 假设,在空间上有一个点,使用xyz描述它的位置,此时让其围绕任意位置旋转一定角度后,我们需要知道这个点的新的...

  • OpenGL的矩阵

    假设,在空间中有一个点,使用XYZ描述它的位置。此时让它进行旋转或者平移,我们需要知道这个点的新位置,那么此时,我...

  • opengles-坐标系和矩阵

    坐标系和矩阵是opengl的基础也是难点,本文总结了opengl的各种坐标系和矩阵,如果有错误欢迎指正。 1.什么...

  • OpenGL矩阵堆栈处理

    为什么要使用矩阵堆栈? OpenGL在进行渲染的时候是通过模型视图矩阵和投影矩阵运算得到最终显示的坐标。 模型矩阵...

  • OpenGL学习之路(5.3) 矩阵堆栈的了解和使用方法

    什么是矩阵堆栈? OpenGL的矩阵堆栈指的就是内存中专门用来存放矩阵数据的某块特殊区域。一般说来,矩阵堆栈常用于...

网友评论

    本文标题:OpenGL的矩阵

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