美文网首页
OpenGL-向量/矩阵变换/投影

OpenGL-向量/矩阵变换/投影

作者: Tobesky | 来源:发表于2019-05-20 00:12 被阅读0次

    基本概念

    向量

    从坐标原点指向这个位置点的一个向量(带箭头的线段

    向量在OpenGL里对应的数据类型M3DVector3f(3维浮点向量)、M3DVector4f(4维浮点向量)

    向量 行/列向量

    向量间的几何意义

    矩阵

    矩阵在OpenGL里主要运用于坐标变换,其对应数据类型有M3DMatrix33f(3x3浮点矩阵)、M3DMatrix44f(4x4浮点矩阵)等。

    矩阵与矩阵相乘

    注意:矩阵的乘法不满足交换律( AB != BA)

    变换

    • 视图变换

    用于确定场景中的有利位置,即观察者的位置,就像在场景中放置照相机并让它指向某个方向。

    • 模型矩阵
      物体本身的坐标变换,有旋转、平移、缩放3种基础模型变换。
    • 模型视图变换
      实际上就是视图变换和模型变换的结合,因为视图变换和模型变换实质上是一样的,只是为了程序员方便而区分出来,因为你移动物体向前10m,和观察者向后移动10m,最终效果是一样的。

    • 投影变换
      投影变换分为正投影和透视投影:

      • 正投影(平行投影):无论物体有多远,都会按照同样大小进行绘制。
      • 透视投影:远处的物体看起来会比近处同样大小的物体更小一些。
    • 视口变换
      逻辑窗口坐标映射到物理窗口坐标的变换**,称为视口变换,通常我们不需要为这事操心,图形硬件已经为我们做好了这些。

    代码解析

    • 矩阵变换

    函数定义

    // 加载单位矩阵
    void m3dLoadIdentity44(M3DMatrix44f m);
    // 沿着 x/y/z 轴平移
    void m3dTranslationMatrix44(M3DMatrix44f m, float x, float y, float z);
    // 沿着 x/y/z 轴旋转 angle(弧度)
    void m3dRotationMatrix44(M3DMatrix44f m, float angle, float x, float y, float z);
    // 在 x/y/z 轴上进行缩放
    void m3dScaleMatrix44(M3DMatrix44f m, float xScale, float yScale, float zScale);
    // 矩阵 a 和矩阵 b 相乘得到矩阵 product
    void m3dMatrixMultiply44(M3DMatrix44f product, const M3DMatrix44f a, const  M3DMatrix44f b);
    

    使用

    // 创建3个4x4矩阵,分别是合成矩阵、平移矩阵、旋转矩阵
    M3DMatrix44f mFinalTransform, mTranslationMatrix, mRotationMatrix;
    // 平移(xPos, yPos, 0)的矩阵表示
    m3dTranslationMatrix44(mTranslationMatrix, xPos, yPos, 0.0f);
    // 绕z轴旋转的矩阵,每次旋转角度加 5 度,m3dDegToRad = 角度 -> 弧度
    static float zRot = 0.0f;
    zRot += 5.0f;
    m3dRotationMatrix44(mRotationMatrix, m3dDegToRad(zRot), 0.0f, 0.0f, 1.0f);
    // 矩阵相乘,参数顺序很重要,先平移,后旋转
    m3dMatrixMultiply44(mFinalTransform, mTranslationMatrix, mRotationMatrix);
    
    • 投影矩阵
      通过视景体(GLFrustum)来设置
    [GLFrustum] { // 仅仅表示以下方法是 GLFrustum 的方法
        // 设置正投影矩阵参数,(x, y, z)最小和最大值
        void SetOrthographic(GLfloat xMin, GLfloat xMax, 
                             GLfloat yMin, GLfloat yMax, 
                             GLfloat zMin, GLfloat zMax);
        // 设置透视投影矩阵参数,分别为:透视角,宽高比,近距,远距
        void SetPerspective(float fFov, float fAspect, float fNear, float fFar);
        // 获取投影矩阵
        const M3DMatrix44f& GetProjectionMatrix(void);
    }
    

    为方便管理各个矩阵,GLTools 提供了矩阵堆栈 GLMatrixStack默认堆栈最大深度为 64,有压栈、出栈等操作

    [GLMatrixStack] { // 仅仅表示以下方法是 GLMatrixStack 的方法
        // -------- 矩阵加载 -----------
        // 在栈顶载入单元矩阵,载入即覆盖
        void LoadIdentity(void);
        // 在栈顶载入任何矩阵
        void LoadMatrix(const M3DMatrix44f m);
        // 用栈顶矩阵乘以某个矩阵,得到的结果矩阵覆盖原来的栈顶矩阵
        void MultMatrix(const M3DMatrix44f mMatrix);
        // 获取栈顶矩阵
        const M3DMatrix44f& GetMatrix(void);
        // -------- 出栈压栈 -----------
        // 压栈,在栈顶压入一个矩阵
        void PushMatrix(const M3DMatrix44f mMatrix);
        // 出栈,把栈顶矩阵移除矩阵堆栈
        void PopMatrix(void);
        // -------- 仿射变换 -----------
        // 栈顶矩阵进行缩放变换
        void Scale(GLfloat x, GLfloat y, GLfloat z);
        // 栈顶矩阵进行平移变换
        void Translate(GLfloat x, GLfloat y, GLfloat z);
        // 栈顶矩阵进行旋转变换
        void Rotate(GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
    }
    

    而为了方便管理模型视图矩阵堆栈和投影矩阵堆栈,GLTools 为我们提供了管理管线 GLGeometryTransform,帮助我们跟踪记录这两种矩阵堆栈,并快速检索模型视图矩阵堆栈顶部或投影矩阵堆栈顶部。

    函数定义

    [GLGeometryTransform] { // 仅仅表示以下方法是 GLGeometryTransform 的方法
        // ----------- 设置矩阵堆栈 ---------
        // 单独设置模型视图矩阵堆栈
        void SetModelViewMatrixStack(GLMatrixStack& mModelView);
        // 单独设置投影矩阵堆栈
        void SetProjectionMatrixStack(GLMatrixStack& mProjection);
        // 同时设置模型视图矩阵堆栈和投影矩阵堆栈
        void SetMatrixStacks(GLMatrixStack& mModelView, GLMatrixStack& mProjection);
        // ----------- 获取堆栈顶部 ---------
        // 获取模型视图矩阵堆栈的栈顶矩阵
        const M3DMatrix44f& GetModelViewMatrix(void);
        // 获取投影矩阵堆栈的栈顶矩阵
        const M3DMatrix44f& GetProjectionMatrix(void);
        // 获取2个矩阵堆栈的栈顶矩阵相乘的结果矩阵
        const M3DMatrix44f& GetModelViewProjectionMatrix(void);
    }
    

    使用

    // 设置正投影参数,(xMin, xMax, yMin, yMax, zMin, zMax)
    viewFrustum.SetOrthographic(-130.0f, 130.0f, -130.0f, 130.0f, -130.0f, 130.0f);
    // 获得到的正投影矩阵载入堆栈中
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    // 变换管线,管理2个堆栈
    transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
    
    // 设置透视投影矩阵参数,分别为:透视角,宽高比,近距,远距
    viewFrustum.SetPerspective(35.0f, float(width)/float(height), 1.0f, 1000.0f);
    // 载入透视投影矩阵
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    // 利用变换管线,管理2个堆栈
    transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
    
    
    
    // 窗口渲染回调
    void RenderScene(void) {
        // 定义一个测试运行时间
        static CStopWatch rotTimer;
        // 获取到上一个时间点到当前的时间间隔(单位是每秒刻度数,即  1/60s)
        float yRot = rotTimer.GetElapsedSeconds() * 60.0f;
        // 清空缓冲区
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        // 定义矩阵
        M3DMatrix44f mTranslate, mRotate, mModelview, mModelViewProjection;
        // 向z轴平移的矩阵变换
        m3dTranslationMatrix44(mTranslate, 0.0f, 0.0f, -2.5f);
        // 绕y轴旋转的矩阵变换
        m3dRotationMatrix44(mRotate, m3dDegToRad(yRot), 0.0f, 1.0f, 0.0f);
        // 矩阵变换的合并矩阵
        m3dMatrixMultiply44(mModelview, mTranslate, mRotate);
        // 投影矩阵 + 视图变换矩阵 = 最终物体位置坐标
        m3dMatrixMultiply44(mModelViewProjection, viewFrustum.GetProjectionMatrix(), mModelview);
        // 绘制花托
        GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
        shaderManager.UseStockShader(GLT_SHADER_FLAT, mModelViewProjection, vBlack);
        torusBatch.Draw();
        // 因为是双缓冲区模式,后台缓冲区替换到前台缓存区进行显示
        glutSwapBuffers();
        // 自动触发下次渲染回调,达到动画的效果
        glutPostRedisplay();
    }
    

    相关文章

      网友评论

          本文标题:OpenGL-向量/矩阵变换/投影

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