美文网首页
OpenGL-MVP模式的六种图元绘制

OpenGL-MVP模式的六种图元绘制

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

    开场白


    这篇文章主要聊聊使用MVP模式的图元绘制,先来看看效果


    运行效果

    1.空格切换绘制模式:


    main函数中增加键盘的回调函数,用来响应‘空格’按键:

    int main(int argc, char* argv[]){
        ...
        glutKeyboardFunc(KeyPressFunc);
        ...
    }
    

    然后我们来看看KeyPressFunc实现

    void KeyPressFunc(unsigned char key, int x, int y) {
        if(key == 32)
        {
            nStep++;
            
            if(nStep > 6)
                nStep = 0;
        }
        
        switch(nStep)
        {
            case 0:
                glutSetWindowTitle("GL_POINTS");
                break;
            case 1:
                glutSetWindowTitle("GL_LINES");
                break;
            case 2:
                glutSetWindowTitle("GL_LINE_STRIP");
                break;
            case 3:
                glutSetWindowTitle("GL_LINE_LOOP");
                break;
            case 4:
                glutSetWindowTitle("GL_TRIANGLES");
                break;
            case 5:
                glutSetWindowTitle("GL_TRIANGLE_STRIP");
                break;
            case 6:
                glutSetWindowTitle("GL_TRIANGLE_FAN");
                break;
        }
        
        glutPostRedisplay();
    }
    
    1. key == 32是判断是否为空格键,32是ascll码
    2. 当点击空格键后,修改全局变量nStep
    3. switch判断当前的nStep,显示不同的窗口title
    4. 调用glut的重绘函数

    2.SetupRC实现


    void SetupRC()
    {
        //设置背景色
        glClearColor(0.7f, 0.7f, 0.7f, 1.0f );
        //初始化着色管理器
        shaderManager.InitializeStockShaders();
        //开启深度测试
        glEnable(GL_DEPTH_TEST);
        //设置变化管线的矩阵堆栈
        transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
        //设置camera位置
        cameraFrame.MoveForward(-15.0f);
        
        //后续代码是设置一些顶点信息,不是本文章的重点。   
        ...
    }
    

    本段代码主要设置了管线transformPipeline,并且设置了矩阵堆栈,目的是使用MVP模式进行绘图。MVP模式就是model-view-projection的三个矩阵变换,来渲染图片。
    设置了camera的位置,cameraFrame.MoveForward为-15的位置,这个可以理解为在屏幕前,距离屏幕15的位置。

    3.ChangeSize实现


    void ChangeSize(int w,int h)
    {
        glViewport(0, 0, w, h);
        //视图椎体变量设置观察者位置
        viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 500.0f);
        //从视图椎体中加载投影矩阵
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
        //模型视图矩阵设置为单元矩阵
        modelViewMatrix.LoadIdentity();
    }
    
    1. 设置视口,
    2. 视图椎体viewFrustum,设置观察者的位置。视图椎体:以camera(观察者)在的位置为顶点,以Far clip plane(远端平截面)为底的几何椎体。请参考下图:


      视图椎体示意[图片上传中...(image.png-c04e57-1594315058378-0)]
    1. 设置视图矩阵projectionMatrix和模型视图矩阵modelViewMatrix,视图矩阵初始值是单元矩阵,该单元矩阵乘以从视图椎体中取出视图矩阵,将值赋值给视图矩阵projectionMatrix。模型视图矩阵设置为单元矩阵(默认值就是单元矩阵,所以此行代码可以不写。),因为当前还没有模型视图,所以设置为初始值。


      坐标系转换

    4.RenderScene


    本文的重点部分

    void RenderScene(void) {
        //1.清除一个或一组特定的缓冲区
        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT);
        
        //2.记录当前模型视图矩阵,当前的值是单元矩阵,所以入栈的是单元矩阵。目的是本次改变后,调用出栈方法,将模型视图矩阵重新复制成单元矩阵,下面有对应PopMatrix函数调用
        modelViewMatrix.PushMatrix();
        
        //3.将camera frame转换成矩阵
        M3DMatrix44f mCamera;
        cameraFrame.GetCameraMatrix(mCamera);
        //modelViewMatrix矩阵乘以camera矩阵栈,相乘的结果存放到modelViewMatrix
        modelViewMatrix.MultMatrix(mCamera);
        
        //4.将object frame转换成矩阵,objectFrame在键盘上下左右时设置的值
        M3DMatrix44f mObjectFrame;
        objectFrame.GetMatrix(mObjectFrame);
        //modelViewMatrix矩阵乘以object矩阵栈,相乘的结果存放到modelViewMatrix
        modelViewMatrix.MultMatrix(mObjectFrame);
        
        //5.使用平面着色器,参数2是从变换管线transformPipeline中获取MVP(ModelViewProjectionMatrix)矩阵
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
        
        //6.
        switch (nStep) {
            case 0:
                glPointSize(4.0f);
                pointBatch.Draw();
                glPointSize(1.0f);
                break;
            case 1:
                glLineWidth(2.0f);
                lineBatch.Draw();
                glLineWidth(1.0f);
                break;
    
            case 2:
                glLineWidth(2.0f);
                lineStripBatch.Draw();
                glLineWidth(1.0f);
                break;
    
            case 3:
                glLineWidth(2.0f);
                lineLoopBatch.Draw();
                glLineWidth(1.0f);
                break;
    
            case 4:
                DrawWireFramedBatch(&triangleBatch);
                break;
    
            case 5:
                DrawWireFramedBatch(&triangleStripBatch);
                break;
    
            case 6:
                DrawWireFramedBatch(&triangleFanBatch);
                break;
                
        }
        
        //7.出栈,将modelViewMatrix还原成单元矩阵
        modelViewMatrix.PopMatrix();
        
        //8.将在后台缓冲区进行渲染,然后在结束时交换到前台
        glutSwapBuffers();
    }
    
    1. 清除缓冲区
    2. modelViewMatrix.PushMatrix();入栈处理。此时modelViewMatrix还是单元矩阵(矩阵的初始值,任何矩阵✖️单元矩阵,还是等于本身),目的是本次修改后还可以恢复到原来的初始值。
    3. 获取camera的矩阵,并将camera矩阵与modelView矩阵,也就是将camera的位置信息混入modelView矩阵中。
    4. 将objectFrame也转换成矩阵,并和第三步一样,混入到modelView矩阵中。objectFrame的变化是在‘空格键’响应函数中进行修改的(KeyPressFunc)。
    5. 调用平面着色器,参数2是从变换管线transformPipeline中获取MVP(ModelViewProjectionMatrix)矩阵
    6. 根据当前nStep,获取不同的容器批次类进行绘制。
    7. 出栈。对应第2步
    8. 交换缓冲区。

    5. DrawWireFramedBatch


    在RenderScene的实现中的switch case 4-6中调用了DrawWireFramedBatch函数,该函数作用是为了渲染复杂3d几何图形时需要进行的一些处理,我们先来看看实现

    void DrawWireFramedBatch(GLBatch* pBatch)
    {
        //1.上色
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlue);
        pBatch->Draw();
        
        //2.设置线相关内容
        
        // 偏移深度,在同一位置要绘制填充和边线,会产生z冲突,所以要偏移
        glPolygonOffset(-1.0f, -1.0f);
        //根据glPolygonOffset的设置,启用线的深度偏移
        glEnable(GL_POLYGON_OFFSET_LINE);
        
        //启用锯齿
        glEnable(GL_LINE_SMOOTH);
        //启用颜色混合
        glEnable(GL_BLEND);
        //混合方式,使用alpha,1-alpha方式混合
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        
        //多边形模式,正反面都用画线模式
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
        glLineWidth(2.5f);
        
        //画线
        shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
        pBatch->Draw();
        
        //3.复原状态
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
        glDisable(GL_POLYGON_OFFSET_LINE);
        glLineWidth(1.0f);
        glDisable(GL_BLEND);
        glDisable(GL_LINE_SMOOTH);
    }
    
    1. 填充颜色,使用平面着色器进行图形内部颜色填充
    2. 设置线相关内容
      • glEnable()用于启用各种功能
      • GL_POLYGON_OFFSET_LINE:偏移深度,在同一位置要绘制填充和边线,会产生z冲突,所以要偏移
      • GL_LINE_SMOOTH:启用锯齿
      • GL_BLEND:启用颜色混合
      • glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA):混合方式,使用alpha,1-alpha方式混合
      • glPolygonMode多边形模式,正反面都用画线模式
      • 画线,用定义好的黑色
    3. 复原相关设置

    代码地址


    OpenGL_MVP_demo

    相关文章

      网友评论

          本文标题:OpenGL-MVP模式的六种图元绘制

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