OpenGL & Metal

OpenGL的矩阵

2020-07-19  本文已影响0人  黑眼豆豆_

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

定义

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

表达式

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


矩阵.jpg

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

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

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

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

矩阵的运算

单元矩阵

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


单元矩阵.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轴往负方向观察。(如同从屏幕上往屏幕里面看)。
为什么说,视图变换要放在最开始呢?
这是因为对于坐标系而言,进行试图变换,就会更换坐标系,接下来的变换都会基于新的坐标系进行。(就像我们看电视,会想用一个更舒服、更好的姿势进行观看)

模型变换

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

//m是一个指针,存储了变换后的结果
//x表示x轴移动的距离
//y表示y轴移动的距离
//z表示z轴移动的距离
inline void m3dTranslationMatrix44(M3DMatrix44f m, float x, float y, float z)

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

//m是一个指针,存储了变换后的结果
//angle表示旋转的角度
//x表示x轴移动的距离
//y表示y轴移动的距离
//z表示z轴移动的距离
void m3dRotationMatrix44(M3DMatrix44d m, double angle, double x, double y, double z);
//m是一个指针,存储了变换后的结果
//x表示x轴缩放的比例
//y表示y轴缩放的比例
//z表示z轴缩放的比例
inline void m3dScaleMatrix44(M3DMatrix44f m, float xScale, float yScale, float zScale)
//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--从而移除最顶上的元素。

上一篇 下一篇

猜你喜欢

热点阅读