美文网首页
OpenGL 基础变化

OpenGL 基础变化

作者: 江海寄余生12138 | 来源:发表于2021-05-30 21:21 被阅读0次
    • 顶点变换管线


      image.png
    • GLMatrixStack 矩阵堆栈

    //类型
    GLMatrixStack::GLMatrixStack(int iStackDepth = 64); 
    //在堆栈顶部载⼊⼀个单元矩阵
    void GLMatrixStack::LoadIdentity(void); 
    //在堆栈顶部载⼊任何矩阵
    //参数:4*4矩阵
    void GLMatrixStack::LoadMatrix(const M3DMatrix44f m); 
    //矩阵乘以矩阵堆栈顶部矩阵,相乘结果存储到堆栈的顶部
    void GLMatrixStack::MultMatrix(const M3DMatrix44f); 
    //获取矩阵堆栈顶部的值 GetMatrix 函数
    //为了适应GLShaderMananger的使⽤,或者获取顶部矩阵的副本
    const M3DMatrix44f & GLMatrixStack::GetMatrix(void); 
    void GLMatrixStack::GetMatrix(M3DMatrix44f mMatrix);
    //将当前矩阵压⼊堆栈
    void GLMatrixStack::PushMatrix(void);
    //将M3DMatrix44f 矩阵对象压⼊当前矩阵堆栈
    void PushMatrix(const M3DMatrix44f mMatrix);
    //将GLFame 对象压⼊矩阵对象
    void PushMatrix(GLFame &frame); 
    //出栈(出栈指的是移除顶部的矩阵对象)
    void GLMatrixStack::PopMatrix(void);
    // 仿射变换,旋转平移缩放
    //Rotate 函数angle参数是传递的度数
    void MatrixStack::Rotate(GLfloat angle,GLfloat x,GLfloat y,GLfloat z);
    void MatrixStack::Translate(GLfloat x,GLfloat y,GLfloat z);
    void MatrixStack::Scale(GLfloat x,GLfloat y,GLfloat z);
    

    GLFrame -参考帧

    • 其中存储了1个世界坐标点和2个世界坐标下的方向向量,也就是9个glFloat值,分别用来表示:当前位置点,向前方向向量,向上方向向量
    • GLFrame可以表示世界坐标系中任意物体的位置与方向。无论是相机还是模型,都可以使用GLFrame来表示。对任意一个使用GLFrame来表示的物体而言,涉及到的坐标系有两个:永远不变的世界坐标系,针对于自身的物体坐标系(即绘图坐标系)
    • 一般来说,针对于物体自身的物体坐标系有如下特点:X轴永远平行于视口的水平方向,+X的方向根据右手定则由+Y与+Z得出;Y轴永远平行于视口的竖直方向,竖直向上为+Y;Z轴永远平行于视口的垂直纸面向里方向,正前方为+Z。也就是说,在世界坐标系中,物体坐标系的Y轴看上去就是GLFrame的向上方向向量,Z轴看上去就是GLFrame的向前方向向量,而X轴由Y轴方向向量与Z轴方向向量根据右手定则可得出
    class GLFrame  { 
     protected: 
     M3DVector3f vOrigin; // Where am I? 
     M3DVector3f vForward; // Where am I going? 
     M3DVector3f vUp; // Which way is up? 
    
    public:
    //默认构造函数(世界坐标系,位置在(0,0,0)点,up为(0,1,0)朝+Y,forward为(0,0,-1)朝向-Z)
      GLFrame(void)
    //设置/获取世界坐标系下模型/相机的位置
    inline void SetOrigin(const M3DVector3f vPoint)
    inline void SetOrigin(float x, float y, float z)
    inline void GetOrigin(M3DVector3f vPoint)
    //获取世界坐标系下模型/相机位置的X/Y/Z分量
    inline float GetOriginX(void)
    inline float GetOriginY(void)
    inline float GetOriginZ(void)
     
    //设置/获取世界坐标系下模型/相机向前的方向向量
    inline void SetForwardVector(const M3DVector3f vDirection)
    inline void SetForwardVector(float x, float y, float z)
    inline void GetForwardVector(M3DVector3f vVector)
     
    //设置/获取世界坐标系下模型/相机向上的方向向量
    inline void SetUpVector(const M3DVector3f vDirection)
    inline void SetUpVector(float x, float y, float z)
    inline void GetUpVector(M3DVector3f vVector)
     
    //获取世界坐标系下模型/相机X/Y/Z轴方向向量
    inline void GetZAxis(M3DVector3f vVector) {GetForwardVector(vVector); }
    inline void GetYAxis(M3DVector3f vVector) { GetUpVector(vVector); }
    inline void GetXAxis(M3DVector3f vVector) {m3dCrossProduct(vVector, vUp, vForward); }
     
    // 以世界坐标系下(x,y,z)偏移量移动模型/相机
    inline void TranslateWorld(float x, float y, float z)
    // 以物体坐标系下(x,y,z)偏移量移动模型/相机
    inline void TranslateLocal(float x, float y, float z)
    // 沿物体坐标系下Z轴以指定偏移fDelta量移动模型/相机
    inline void MoveForward(float fDelta)
    // 沿物体坐标系下Y轴以指定偏移fDelta移动物体/相机
    inline void MoveUp(float fDelta)
    // 沿物体坐标系下X轴以指定偏移fDelta移动物体/相机
    inline void MoveRight(float fDelta)
     
    // 获取一个用于描述模型属性的4×4的矩阵
    void GetMatrix(M3DMatrix44f matrix, bool bRotationOnly = false)
    // 获取一个用于描述相机属性的4×4的矩阵
    inline void GetCameraOrientation(M3DMatrix44f m)
     
    // 应用所有的相机变换。该函数仅用于相机
    inline void ApplyCameraTransform(bool bRotOnly = false)
    // 应用所有的物体变换。该函数仅用于除相机外的物体
    void ApplyActorTransform(bool bRotationOnly = false)
    // 令物体/相机以自身位置为中心,绕X/Y/Z轴旋转。其角度以PI为单位
    void RotateLocalX(float fAngle)
    void RotateLocalY(float fAngle)
    void RotateLocalZ(float fAngle)
     
    // Reset axes to make sure they are orthonormal. This should be called on occasion
    // if the matrix is long-lived and frequently transformed.
    // 规范化
    void Normalize(void)
    // 模型/相机绕世界坐标系下的指定轴(x,y,z)旋转fAngle度
    void RotateWorld(float fAngle, float x, float y, float z)
     // 模型/相机绕当前物体坐标系下的指定轴(x,y,z)旋转fAngle度
    void RotateLocal(float fAngle, float x, float y, float z)
     
    // 将点/向量vLocal从当前物体坐标系转换为世界坐标系
    void LocalToWorld(const M3DVector3f vLocal, M3DVector3f vWorld)
     
    // 将点/向量vLocal从世界坐标系转换为当前物体坐标系
    void WorldToLocal(const M3DVector3f vWorld, M3DVector3f vLocal)
     
    // 通过当前frame矩阵将vPointSrc点变换为vPointDst点
    void TransformPoint(M3DVector3f vPointSrc, M3DVector3f vPointDst)
     //通过当前frame矩阵将vVectorSrc向量旋转为vVectorDst向量
    void RotateVector(M3DVector3f vVectorSrc, M3DVector3f vVectorDst)
    }
    
    • GLFrustum - 视景体
    // 设置正投影
    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) { return projMatrix; }
    
    • GLBatch - 批次容器
      GLTools库中,包含了一个容器类GLBatch,可以作为7种图元批次容器使用,它知道使用GLShaderManager支持的任意存储着色器时,如何对图元进行渲染。
    // 参数1:图元
    // 参数2:顶点个数
    // 参数3:一组或两组纹理图标
    void GLBatch::Begain(GLeunm primitive,GLuint nVerts,GLuint nTexttureUnints = 0);
    // 复制顶点
    void CopyVertexData3f(M3DVector3f *vVerts);
    // 复制表面法线
    void GLBatch::CopyNormalDataf(GLfloat *vNorms);
    // 复制颜色
    void GLBatch::CopyColorData4f(GLfloat *vColors);
    // 复制纹理坐标
    void GLBatch::CopyTexCoordData2f(GLFloat *vTextCoords,GLuint u
    iTextureLayer);
    // 重置
    void Reset(void);
    // 设置顶点
    void Vertex3f(GLfloat x, GLfloat y, GLfloat z);
     void Vertex3fv(M3DVector3f vVertex);
    // 设置法线        
    void Normal3f(GLfloat x, GLfloat y, GLfloat z);
    void Normal3fv(M3DVector3f vNormal);
    // 设置颜色    
    void Color4f(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
    void Color4fv(M3DVector4f vColor);
    // 设置纹理        
    void MultiTexCoord2f(GLuint texture, GLclampf s, GLclampf t);
    void MultiTexCoord2fv(GLuint texture, M3DVector2f vTexCoord);
    // 画
    virtual void Draw(void);
    // 绘制结束
    void GLBatch::End(void);
    
    • GLTriangleBatch - 三角形批次类
    // Use these three functions to add triangles
    void BeginMesh(GLuint nMaxVerts);
    void AddTriangle(M3DVector3f verts[3], M3DVector3f vNorms[3], M3DVector2f vTexCoords[3]);
    void End(void);
    virtual void Draw(void);
    
    • GLGeometryTransform - 几何变换管道
    // 设置模型视图矩阵堆栈
    inline void SetModelViewMatrixStack(GLMatrixStack& mModelView) { _mModelView = &mModelView; }
    // 设置投影视图矩阵堆栈
    inline void SetProjectionMatrixStack(GLMatrixStack& mProjection) { _mProjection = &mProjection; }
    // 设置模型视图投影矩阵堆栈
    inline void SetMatrixStacks(GLMatrixStack& mModelView, GLMatrixStack& mProjection)  {
        _mModelView = &mModelView;
        _mProjection = &mProjection;
    }
    // 获取模型视图投影矩阵
    const M3DMatrix44f& GetModelViewProjectionMatrix(void)
    // 获取模型视图矩阵
    inline const M3DMatrix44f& GetModelViewMatrix(void) { return _mModelView->GetMatrix(); }
    // 获取投影视图矩阵
    inline const M3DMatrix44f& GetProjectionMatrix(void) { return _mProjection->GetMatrix(); }
    
    

    绘制流程

    • main函数
    int main(int argc, char* argv[])
    {
        // 设置工作路径
        gltSetWorkingDirectory(argv[0]);
        // 这个函数用来初始化 GLUT 库
        glutInit(&argc, argv);
        //申请一个双缓存区,颜色缓存区、深度缓存区、模板缓存区
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
        //设置window 的尺寸
        glutInitWindowSize(800, 600);
        //创建window的名称
        glutCreateWindow("GL_POINTS");
        //注册回调函数(改变尺寸)
        glutReshapeFunc(ChangeSize);
        //点击空格时,调用的函数
        glutKeyboardFunc(KeyPressFunc);
        //特殊键位函数(上下左右)
        glutSpecialFunc(SpecialKeys);
        //显示函数
        glutDisplayFunc(RenderScene);
        
        //判断一下是否能初始化glew库,确保项目能正常使用OpenGL 框架
        GLenum err = glewInit();
        
        if (GLEW_OK != err) {
            fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
            return 1;
        }
        
        // 此函数在呈现上下文中进行任何必要的初始化。.
        // 这是第一次做任何与opengl相关的任务。
        SetupRC();
        
        //runloop运行循环
        glutMainLoop();
        
        return 0;
    }
    
    • 上下文初始化等工作
    void SetupRC()
    {
        // Black background
        glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
        
        //初始化固定着色管理器
        shaderManager.InitializeStockShaders();
        
        //开启深度测试
        glEnable(GL_DEPTH_TEST);
        
        //通过GLGeometryTransform管理矩阵堆栈
        //使用transformPipeline 管道管理模型视图矩阵堆栈 和 投影矩阵堆栈
        transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
        
        //将观察者坐标位置Z移动往屏幕里移动15个单位位置
        //表示离屏幕之间的距离 负数,是往屏幕后面移动;正数,往屏幕前面移动
        cameraFrame.MoveForward(-15.0f);
        
        //利用三角形批次类构造图形对象
        // 球
        /*
          gltMakeSphere(GLTriangleBatch& sphereBatch, GLfloat fRadius, GLint iSlices, GLint iStacks);
         参数1:sphereBatch,三角形批次类对象
         参数2:fRadius,球体半径
         参数3:iSlices,从球体底部堆叠到顶部的三角形带的数量;其实球体是一圈一圈三角形带组成
         参数4:iStacks,围绕球体一圈排列的三角形对数
         
         建议:一个对称性较好的球体的片段数量是堆叠数量的2倍,就是iStacks = 2 * iSlices;
         绘制球体都是围绕Z轴,这样+z就是球体的顶点,-z就是球体的底部。
         */
        gltMakeSphere(sphereBatch, 3.0, 10, 20);
        
        // 环面
        /*
         gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
         参数1:torusBatch,三角形批次类对象
         参数2:majorRadius,甜甜圈中心到外边缘的半径
         参数3:minorRadius,甜甜圈中心到内边缘的半径
         参数4:numMajor,沿着主半径的三角形数量
         参数5:numMinor,沿着内部较小半径的三角形数量
         */
        gltMakeTorus(torusBatch, 3.0f, 0.75f, 15, 15);
        
        // 圆柱
        /*
         void gltMakeCylinder(GLTriangleBatch& cylinderBatch, GLfloat baseRadius, GLfloat topRadius, GLfloat fLength, GLint numSlices, GLint numStacks);
         参数1:cylinderBatch,三角形批次类对象
         参数2:baseRadius,底部半径
         参数3:topRadius,头部半径
         参数4:fLength,圆形长度
         参数5:numSlices,围绕Z轴的三角形对的数量
         参数6:numStacks,圆柱底部堆叠到顶部圆环的三角形数量
         */
        gltMakeCylinder(cylinderBatch, 2.0f, 2.0f, 3.0f, 15, 2);
        
        //锥
        /*
         void gltMakeCylinder(GLTriangleBatch& cylinderBatch, GLfloat baseRadius, GLfloat topRadius, GLfloat fLength, GLint numSlices, GLint numStacks);
         参数1:cylinderBatch,三角形批次类对象
         参数2:baseRadius,底部半径
         参数3:topRadius,头部半径
         参数4:fLength,圆形长度
         参数5:numSlices,围绕Z轴的三角形对的数量
         参数6:numStacks,圆柱底部堆叠到顶部圆环的三角形数量
         */
        //圆柱体,从0开始向Z轴正方向延伸。
        //圆锥体,是一端的半径为0,另一端半径可指定。
        gltMakeCylinder(coneBatch, 2.0f, 0.0f, 3.0f, 13, 2);
        
        // 磁盘
        /*
        void gltMakeDisk(GLTriangleBatch& diskBatch, GLfloat innerRadius, GLfloat outerRadius, GLint nSlices, GLint nStacks);
         参数1:diskBatch,三角形批次类对象
         参数2:innerRadius,内圆半径
         参数3:outerRadius,外圆半径
         参数4:nSlices,圆盘围绕Z轴的三角形对的数量
         参数5:nStacks,圆盘外网到内围的三角形数量
         */
        gltMakeDisk(diskBatch, 1.5f, 3.0f, 13, 3);
    }
    
    
    • 屏幕大小发生改变
    void ChangeSize(int w, int h)
    {
        // 修改视口大小
        glViewport(0, 0, w, h);
        
        //设置透视投影
        viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
        
        //projectionMatrix 矩阵堆栈 加载透视投影矩阵
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
        
        //modelViewMatrix 矩阵堆栈 加载单元矩阵
        modelViewMatrix.LoadIdentity();
    }
    
    • 绘制场景
    //召唤场景
    void RenderScene(void)
    {
        //用当前清除颜色清除窗口背景
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
        
        //模型视图矩阵栈堆,压栈
        modelViewMatrix.PushMatrix();
        //获取摄像头矩阵
        M3DMatrix44f mCamera;
        //从camereaFrame中获取矩阵到mCamera
        cameraFrame.GetCameraMatrix(mCamera);
        //模型视图堆栈的 矩阵与mCamera矩阵 相乘之后,存储到modelViewMatrix矩阵堆栈中
        modelViewMatrix.MultMatrix(mCamera);
        
        //创建矩阵mObjectFrame
        M3DMatrix44f mObjectFrame;
        //从ObjectFrame 获取矩阵到mOjectFrame中
        objectFrame.GetMatrix(mObjectFrame);
        //将modelViewMatrix 的堆栈中的矩阵 与 mOjbectFrame 矩阵相乘,存储到modelViewMatrix矩阵堆栈中
        modelViewMatrix.MultMatrix(mObjectFrame);
        
        //判断你目前是绘制第几个图形
        switch(nStep) {
            case 0:
                DrawWireFramedBatch(&sphereBatch);
                break;
            case 1:
                DrawWireFramedBatch(&torusBatch);
                break;
            case 2:
                DrawWireFramedBatch(&cylinderBatch);
                break;
            case 3:
                DrawWireFramedBatch(&coneBatch);
                break;
            case 4:
                DrawWireFramedBatch(&diskBatch);
                break;
        }
        
        modelViewMatrix.PopMatrix();
        
        // Flush drawing commands
        glutSwapBuffers();
    }
    
    void DrawWireFramedBatch(GLTriangleBatch* pBatch)
    {
        //平面着色器,绘制三角形
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
       
        //传过来的参数,对应不同的图形Batch
        pBatch->Draw();
        
        // 画出黑色轮廓
        glPolygonOffset(-1.0f, -1.0f);
        
        //开启线段抗锯齿
        glEnable(GL_LINE_SMOOTH);
        
        //开启混合功能
        glEnable(GL_BLEND);
        
        //颜色混合,设置混合因子
        //表示源颜色乘以自身的alpha 值,目标颜色乘以1.0减去源颜色的alpha值,这样一来,源颜色的alpha值越大,则产生的新颜色中源颜色所占比例就越大,而目标颜色所占比例则减 小。这种情况下,我们可以简单的将源颜色的alpha值理解为“不透明度”。这也是混合时最常用的方式。
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        
        //通过程序点大小模式来设置点的大小
        glEnable(GL_POLYGON_OFFSET_LINE);
        
        //多边形模型(背面、线) 将多边形背面设为线框模式
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        
        //线条宽度
        glLineWidth(2.5f);
        
        //平面着色器绘制线条
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
    
        pBatch->Draw();
        
        // 恢复多边形模式和深度测试
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        glDisable(GL_POLYGON_OFFSET_LINE);
        glLineWidth(1.0f);
        glDisable(GL_BLEND);
        glDisable(GL_LINE_SMOOTH);
    }
    
    • 按键控制
    //上下左右,移动图形
    void SpecialKeys(int key, int x, int y)
    {
        if(key == GLUT_KEY_UP)
            //移动世界坐标系,而不是去移动物体。
            //将世界坐标系在X方向移动-5.0
            objectFrame.RotateWorld(m3dDegToRad(-5.0f), 1.0f, 0.0f, 0.0f);
        
        if(key == GLUT_KEY_DOWN)
            objectFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
        
        if(key == GLUT_KEY_LEFT)
            objectFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
        
        if(key == GLUT_KEY_RIGHT)
            objectFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
        
        glutPostRedisplay();
    }
    
    //点击空格,切换渲染图形
    void KeyPressFunc(unsigned char key, int x, int y)
    {
        if(key == 32)
        {
            nStep++;
            
            if(nStep > 4)
                nStep = 0;
        }
        
        switch(nStep)
        {
            case 0:
                glutSetWindowTitle("Sphere");
                break;
            case 1:
                glutSetWindowTitle("Torus");
                break;
            case 2:
                glutSetWindowTitle("Cylinder");
                break;
            case 3:
                glutSetWindowTitle("Cone");
                break;
            case 4:
                glutSetWindowTitle("Disk");
                break;
        }
        
        glutPostRedisplay();
    }
    
    

    相关文章

      网友评论

          本文标题:OpenGL 基础变化

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