美文网首页
OpenGL-矩阵相乘之为什么要先设置观察者Camera

OpenGL-矩阵相乘之为什么要先设置观察者Camera

作者: 过气的程序员DZ | 来源:发表于2020-07-11 15:57 被阅读0次

开场白


最近在学习OpenGL的知识,写了一些Demo。每次都是先将观察者Camera矩阵入栈,如果改变矩阵入栈顺序就得不到想要的效果。所以这篇文章来聊聊这方面的问题。

文中使用本人另一篇文章OpenGL-MVP模式的六种图元绘制中的demo为例

精简后的代码


本文只研究矩阵的入栈时机,所以多余代码就省略了:

......
//模型视图矩阵
GLMatrixStack modelViewMatrix;
//投影矩阵
GLMatrixStack projectionMatrix;
//观察者
GLFrame cameraFrame;
//物体
GLFrame objectFrame;
//视图椎体
GLFrustum viewFrustum;
...
//几何变化管道
GLGeometryTransform transformPipeline;
......

void ChangeSize(int w,int h)
{
    ......
    //视图椎体变量设置观察者位置
    viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
    //从视图椎体中加载投影矩阵
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    //模型视图矩阵设置为单元矩阵
    modelViewMatrix.LoadIdentity();
}

void SetupRC()
{
    ......
    //设置变化管线的矩阵堆栈
    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
    //设置camera位置
    cameraFrame.MoveForward(-15.0f);
    ......
}
......

void RenderScene(void) {
    ......
    //入栈
    modelViewMatrix.PushMatrix();
    
    //将camera frame转换成矩阵,并入栈
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.MultMatrix(mCamera);
    
    //将object frame转换成矩阵,并入栈
    M3DMatrix44f mObjectFrame;
    objectFrame.GetMatrix(mObjectFrame);
    modelViewMatrix.MultMatrix(mObjectFrame);
    
    //设置着色器
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
    ......
}

1.ChangeSize回调方法

projectionMatrix栈

投影矩阵栈projectionMatrix是GLMatrixStack实例,通过类名就可以了解到它就是一个栈。我们来看看GLMatrixStack的构造方法:


GLMatrixStack构造方法

这个可以看到栈中会加入一个单元矩阵,作为栈顶元素。

projectionMatrix会调用LoadMatrix方法,参数是viewFrustum.GetProjectionMatrix()

projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());

viewFrustum是GLFrustm实例,Frustum是椎体的意思,可以理解为以观察者为顶点,到屏幕形成椎体几何图形。
在viewFrustum调用SetPerspective方法中:

viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);

已经初始化好了Objection矩阵:



所以viewFrustum.GetProjectionMatrix作为参数传入到projectionMatrix.LoadMatrix()方法中,就可以将projection的矩阵传入到projectionMatrix栈中。
LoadMartix()方法就是一个入栈操作:


modelViewMatrix栈

modelViewMatrix也是GLMatrixStack实例,

    modelViewMatrix.LoadIdentity();

其实这句代码可以不写,这句代码的意思就是将栈顶元素设置为单元矩阵,上面我们了解到,在构造方法中已经做过这一步了,所以写不写都可以。


2. SetupRC回调方法

    transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);

将modelViewMatrix和projectionMatrix放入到管线中。
设置cameraFrame的位置

    cameraFrame.MoveForward(-15.0f);

3. SetupRC回调方法

    modelViewMatrix.PushMatrix();

modelViewMatrix调用PushMatrix()入栈方法,其实就是将栈顶元素再次入栈,可以看看实现:


    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);
    modelViewMatrix.MultMatrix(mCamera);

    M3DMatrix44f mObjectFrame;
    objectFrame.GetMatrix(mObjectFrame);
    modelViewMatrix.MultMatrix(mObjectFrame);

先将camera转换成矩阵,加入modelViewMatrix栈中,再讲objcet转换成矩阵加入到modelViewMatrix栈中,我们来看看MutlMatrix()方法的实现:


是将栈顶元素取出用赋值给mTemp,然后吧mTemp与参数mMatrix的城际后存入到栈顶。
通过上面的代码,就可以理解为[单元矩阵] * [camera矩阵] * [object矩阵],其实这个过程就是model矩阵乘以object矩阵的到modelView矩阵的过程,camera就是观察者矩阵,其实就是我们平时说的View矩阵。object矩阵就是物体矩阵,也就是model矩阵。得到公式1:modeView_M = view_M * model_M

再接下来我们看看设置着色器中的参数第二个参数:

shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);

GetModelViewProjectionMatrix()方法的实现:


这个方法就是获取modelViewProjection矩阵,而这个矩阵是通过projection矩阵与modeView矩阵的乘积,得到公式2:modelViewProjection_M = projection_M * modelView_M

通过上面公式可以得到矩阵的乘积顺序:
mvp_M = projection_M * view_M * model_M
注意:矩阵相乘是没有交换律的,所以这个顺序是不可以变的。
这也就是为什么我们开发的时候要先设置观察者camera(view矩阵),这样可以先求出modelView矩阵,进而求出mvp矩阵。

4.OpenGL中的矩阵是列优先


这张图在我之前的文章里用到过,我们再来仔细看看:
物体在本地坐标系中,通过model矩阵变换到世界坐标系,在通过观察者矩阵变换到观察者坐标系,在通过投影矩阵,剪裁等操作,最后展示到屏幕坐标系中。这个过程可以用下面公式简单标示一下:(_v代表点,_m代表矩阵)
clip_v = local_v * model_m * view_m * projection_m

有没有发现这个公式和我们上面推到的公式是相反的。

其实是因为OpenGL中矩阵使用的是‘列优先顺序’,如图:



而在我们学习中都是以‘行优先的顺序’,所以整个过程是正好相反的。


矩阵列优先和行优先

我们平时说矩阵都是行优先,比如说一个矩阵A是[2x3]矩阵:

//行优先
1 2 3
4 5 6 

//列优先
1 4
2 5
3 6

我们再来一个矩阵B[3x1]:

//行优先
7 8 9

//列优先
7
8
9

在行优先的情况下,A * B是可以相乘的,[2x3] * [3x1]= [2x1],
而如果是列优先,B * A才能进行相乘,[1x3] * [3x2] = [1x2]

相关文章

  • OpenGL-矩阵相乘之为什么要先设置观察者Camera

    开场白 最近在学习OpenGL的知识,写了一些Demo。每次都是先将观察者Camera矩阵入栈,如果改变矩阵入栈顺...

  • 矩阵

    1. 线性方程组 2. 矩阵定义 3. 矩阵运算 矩阵的加法矩阵的加法 数与矩阵相乘数与矩阵相乘 矩阵与矩阵相乘矩...

  • 第3章 动态规划——矩阵连乘最优计算方式查找

      问题:如何得到n个矩阵连乘的最少计算次数的计算顺序?先计算,还是先计算?其中,为矩阵的维度。 1、两个矩阵相乘...

  • 矩阵运算

    矩阵与标量的乘法 每个元素与标量相乘 矩阵相乘 只有第一个矩阵的列数与第二个矩阵的行数相同,才可以相乘。新矩阵行数...

  • OpenGL笔记六:纹理常用API(一)

    前言 期待您移步上篇:OpenGL笔记五:综合实例理解-压栈、出栈、堆栈矩阵相乘、矩阵相乘、向量相乘 纹理 纹理只...

  • 矩阵论-矩阵乘法的意义

    推荐书籍: 《神奇矩阵》 AB矩阵相乘的表示形式我喜欢这种。 当然有了矩阵相乘也有其反向操作,矩阵的分解。

  • 矩阵和矩阵的相乘_线性代数_day15

    矩阵在图像变换中的应用 矩阵乘法的定义 矩阵和矩阵的相乘,就是分成每一个矩阵和向量的相乘 矩阵A的列数必须和矩阵B...

  • WarMj:简单矩阵乘法代码解析

    目前还不会申请动态数组(需要指针),所以先分析固定数组,之后补上。 矩阵分析 矩阵相乘条件 形如 ma[row][...

  • numpy -- 实现线性代数

    Python 实现线性代数 m_n 与 n_k 这样的矩阵才能相乘 矩阵求逆 矩阵和矩阵的逆相乘结果为单位矩阵 qr分解

  • 矩阵相乘

    /*矩阵相乘 题目描述:两个矩阵的乘法仅当第一个矩阵A的行数和另一个 矩阵B的列数相等时才能定义...

网友评论

      本文标题:OpenGL-矩阵相乘之为什么要先设置观察者Camera

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