美文网首页
3.OpenGL渲染技巧

3.OpenGL渲染技巧

作者: bytebytebyte | 来源:发表于2020-11-27 07:19 被阅读0次

    1.渲染过程产生的问题
    看到了不透明墙壁后面的东西,不应该渲染墙壁后的东西(隐藏面消除)

    2.油画渲染
    距离观察者由远及近的绘制物体,可以解决。
    但是这出现了新的问题,如果3个三角形互相叠加,油画算法将无法渲染。

    3.正背面剔除
    OpenGL可以检查朝向观察者的面并渲染它们,而丢弃背面。
    OpenGL如何区分正背面?
    通过分析顶点数据的顺序。

    4.深度测试
    深度:3D世界中像素点距离摄像机的距离。
    深度缓冲区:一块内存区域、存储着每个像素点的深度值,值越大距离摄像机越远。
    为何需要深度缓冲区?绘制顺序就不重要了。
    深度测试:是否绘制物体表面,表面深度值和当前缓冲区深度值比较,大于则丢弃,否则更新像素颜色值和深度值。

    5.多边形模型
    6.多边形偏移
    7.裁剪
    8.颜色混合

    1.谈谈图形图像渲染中的深度缓冲区?
    一块内存区域、存储着每个像素点的深度值,值越大距离摄像机越远。
    为何需要深度缓冲区?绘制顺序就不重要了。

    2.阐述隐藏面消除解决方案?
    正背面剔除、深度测试

    3.阐述深度缓冲区带来的隐患、解决方案、预防方案?
    原因:深度缓冲区的限制导致深度相差很小。
    隐患:交错闪烁出现2个画面
    解决方案:让深度值之间产生间隔,在执行深度测试前将立方体的深度值做一些细微的增加,区分重叠的2个图形深度值。
    第一步:Polygon Offset方式解决。
    glEnable(GL_POLYGON_OFFSET_FILL)
    第二步:指定偏移量
    void glPolygonOffset(Glfloat factor,Glfloat units);
    第三步: 关闭Polygon Offset
    glDisable(GL_POLYGON_OFFSET_FILL)

    预防方案:
    不要将2个物体靠的太近;将裁剪面设置的离观察者远一些;使用高位数的深度缓冲区。

    1.深度测试

    //演示OpenGL背面剔除、深度测试、多边形模型
    #include "GLTools.h"
    #include "GLMatrixStack.h"
    #include "GLFrame.h"
    #include "GLFrustum.h"
    #include "GLGeometryTransform.h"
    #include <math.h>
    
    #ifdef __APPLE__
    #include <glut/glut.h>
    #else
    #define FREEGLUT_STATIC
    #include <GL/glut.h>
    #endif
    
    GLFrame viewFrame; //设置角色帧,作为相机
    GLFrustum viewFrustum; //使用此类设置透视投影
    GLTriangleBatch torusBatch;
    GLMatrixStack modelViewMatrix;
    GLMatrixStack projectionMatrix;
    GLGeometryTransform transformPipeline;
    GLShaderManager shaderManager;
    
    //标记背面剔除、深度测试
    int iCull = 0;
    int iDepth = 0;
    
    
    //开始渲染
    void renderScene(void) {
        //1.清除窗口和深度缓冲区
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //可以注掉看看效果
        
        //开启关闭正背面剔除功能
        if (iCull) {
            glEnable(GL_CULL_FACE);
            glFrontFace(GL_CCW);
            glCullFace(GL_BACK);
        }
        else {
            glDisable(GL_CULL_FACE);
        }
        
        //根据设置iDepth标记来判断是否开启深度测试
        if (iDepth) {
            glEnable(GL_DEPTH_TEST);
        }
        else {
            glDisable(GL_DEPTH_TEST);
        }
        
        //2.把摄像机矩阵压入模型矩阵中
        //    modelViewMatrix.PushMatrix(viewFrame);
        //或者
        modelViewMatrix.PushMatrix();
        M3DMatrix44f mCamera;
        cameraFrame.GetCameraMatrix(mCamera);
        modelViewMatrix.MultMatrix(mCamera);
    
        M3DMatrix44f mObjectFrame;
        viewFrame.GetMatrix(mObjectFrame);
        modelViewMatrix.MultMatrix(mObjectFrame);
        //3.设置绘图颜色
        GLfloat vRed[] = {1.0f, 0.0f, 0.0f, 1.0f};
        /*4.使用默认光源着色器通过光源阴影效果体现立体效果
         参数1 GLT_SHADER_DEFAULT_LIGHT 默认光源着色器
         参数2 模型视图矩阵
         参数3 投影矩阵
         参数4 基本颜色值
         */
        shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vRed);
        //5.绘制
        torusBatch.Draw();
        //6.出栈 绘制完成恢复
        modelViewMatrix.PopMatrix();
        //7.交换缓冲区
        glutSwapBuffers();
        
    }
    
    //为程序做一次性的设置
    void setupRC() {
        //1.设置背景色
        glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
        //2.初始化着色器管理器
        shaderManager.InitializeStockShaders();
        //3.将相机后移7个单位
        viewFrame.MoveForward(7.0);
        //4.创建一个甜甜圈
        /*
         参数1:容器帮助类
         参数2:外边缘半径
         参数3:内边缘半径
         参数4、5:主半径和从半径的细分单元数量
         */
        gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);
        //5.点的大小(方便点填充时,肉眼观察)
        glPointSize(4.0f);
    }
    
    //通过camera即viewFrame的移动从而改变视口
    void specialKeys(int key, int x, int y) {
        //1.判断方向
        if (key == GLUT_KEY_UP) {
            //2.根据方向调整观察者位置
            viewFrame.RotateWorld(m3dDegToRad(-5.0), 1.0f, 0.0f, 0.0f);
        }
        if (key == GLUT_KEY_DOWN) {
            viewFrame.RotateWorld(m3dDegToRad(5.0f), 1.0f, 0.0f, 0.0f);
        }
        if (key == GLUT_KEY_LEFT) {
            viewFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
        }
        if (key == GLUT_KEY_RIGHT) {
            viewFrame.RotateWorld(m3dDegToRad(5.0f), 0.0f, 1.0f, 0.0f);
        }
        //3.重新刷新
        glutPostRedisplay();
    }
    
    //窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
    void ChangeSize(int w, int h) {
        //1.防止h变为0
        if (h == 0) {
            h = 1;
        }
        //2.设置视口窗口尺寸
        glViewport(0, 0, w, h);
        //3.SetPerspective函数的参数是一个从顶点方向看上去的视场角度,用角度值表示
        viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 100.0f);
        //4.把透视矩阵加载到透视矩阵堆栈中
        projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
        //5.初始化渲染管线
        transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
        
        
    }
    
    void processMenu(int value) {
        switch (value) {
            case 1:
                iDepth = !iDepth;
                break;
            case 2:
                iCull = !iCull;
                break;
            case 3:
                glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                break;
            case 4:
                glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
                break;
            case 5:
                glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
                break;
        }
        glutPostRedisplay();
    }
    
    
    int main(int argc, char *argv[]) {
    
        gltSetWorkingDirectory(argv[0]);
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
        glutInitWindowSize(800, 600);
        glutCreateWindow(" Geometry Test Program");
        glutReshapeFunc(ChangeSize);
        glutSpecialFunc(specialKeys);
        glutDisplayFunc(renderScene);
        
        //添加右击菜单栏
        glutCreateMenu(processMenu);
        glutAddMenuEntry("Toggle depth test", 1);
        glutAddMenuEntry("Toggle cull backface", 2);
        glutAddMenuEntry("Set Fill Mode", 3);
        glutAddMenuEntry("Set Line Mode", 4);
        glutAddMenuEntry("Set Point Mode", 5);
        glutAttachMenu(GLUT_RIGHT_BUTTON);
        
        GLenum err = glewInit();
        if (GLEW_OK != err) {
            fprintf(stderr, "GLEW Error:%s\n",glewGetErrorString(err));
            return 1;
        }
        setupRC();
        glutMainLoop();
        
        return 0;
    }
    

    2.OpenGL 裁剪

    #include "GLTools.h"
    
    #ifdef __APPLE__
    #include <GLUT/GLUT.h>
    #else
    #define FREEGLUT_STATIC
    #include <GL/glut.h>
    #endif
    
    //开始渲染
    void renderScene(void) {
        //设置清屏颜色为蓝色
        glClearColor(0.0f, 0.0f, 1.0f, 0.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        
        // 1.裁剪一个红色的小矩形
        //(1)设置裁剪区颜色为红色
        glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
        //(2)设置裁剪尺寸
        glScissor(100, 100, 600, 400);
        //(3)开启裁剪测试
        glEnable(GL_SCISSOR_TEST);
        //(4)开启清屏,执行裁剪
        glClear(GL_COLOR_BUFFER_BIT);
        
        // 2.裁剪一个绿色的小矩形
        //(1)设置裁剪区颜色为绿色
        glClearColor(0.0f, 1.0f, 0.0f, 0.0f);
        //(2)设置裁剪尺寸
        glScissor(200, 200, 400, 200);
        //(3)开启清屏,执行裁剪
        glClear(GL_COLOR_BUFFER_BIT);
        
        //关闭裁剪测试
        glDisable(GL_SCISSOR_TEST);
        //强制执行缓存区
        glutSwapBuffers();
        
    }
    
    //窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
    void ChangeSize(int w, int h) {
        if (h == 0) {
            h = 1;
        }
        glViewport(0, 0, w, h);
    }
    
    int main(int argc, char *argv[]) {
    
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
        glutInitWindowSize(800, 800);
        glutCreateWindow("OpenGL Scissor");
        glutReshapeFunc(ChangeSize);
        glutDisplayFunc(renderScene);
        glutMainLoop();
        
        return 0;
    }
    

    3.OpenGL混合

    #include "GLShaderManager.h"
    #include "GLTools.h"
    
    #ifdef __APPLE__
    #include <GLUT/GLUT.h>
    #else
    #define FREEGLUT_STATIC
    #include <GL/glut.h>
    #endif
    
    
    GLBatch squareBatch;
    GLBatch greenBatch;
    GLBatch redBatch;
    GLBatch blueBatch;
    GLBatch blackBatch;
    
    GLShaderManager shaderManager;
    
    GLfloat blockSize = 0.2f;
    GLfloat vVerts[] = {
        -blockSize, -blockSize, 0.0f,
        blockSize, -blockSize, 0.0f,
        blockSize, blockSize, 0.0f,
        -blockSize, blockSize, 0.0f
    };
    
    
    //为程序做一次性的设置
    void setupRC() {
        glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
        shaderManager.InitializeStockShaders();
        //绘制一个移动矩形
        squareBatch.Begin(GL_TRIANGLE_FAN, 4);
        squareBatch.CopyVertexData3f(vVerts);
        squareBatch.End();
        
        //绘制4个固定矩形
        GLfloat vBlock[] = {
            0.25f, 0.25f, 0.0f,
            0.75f, 0.25f, 0.0f,
            0.75f, 0.75f, 0.0f,
            0.25f, 0.75f, 0.0f
        };
        
        greenBatch.Begin(GL_TRIANGLE_FAN, 4);
        greenBatch.CopyVertexData3f(vBlock);
        greenBatch.End();
        
        GLfloat vBlock2[] = {
            -0.75f, 0.25f, 0.0f,
            -0.25f, 0.25f, 0.0f,
            -0.25f, 0.75f, 0.0f,
            -0.75f, 0.75f, 0.0f
        };
        redBatch.Begin(GL_TRIANGLE_FAN, 4);
        redBatch.CopyVertexData3f(vBlock2);
        redBatch.End();
        
        
        GLfloat vBlock3[] = {
            -0.75f, -0.75f, 0.0f,
            -0.25f, -0.75f, 0.0f,
            -0.25f, -0.25f, 0.0f,
            -0.75f, -0.25f, 0.0f
        };
        blueBatch.Begin(GL_TRIANGLE_FAN, 4);
        blueBatch.CopyVertexData3f(vBlock3);
        blueBatch.End();
        
        GLfloat vBlock4[] = {
            0.25f, -0.75f, 0.0f,
            0.75f, -0.75f, 0.0f,
            0.75f, -0.25f, 0.0f,
            0.25f, -0.25f, 0.0f
        };
        blackBatch.Begin(GL_TRIANGLE_FAN, 4);
        blackBatch.CopyVertexData3f(vBlock4);
        blackBatch.End();
        
        
    }
    
    void specialKeys(int key, int x, int y) {
        GLfloat stepSize = 0.025f;
        GLfloat blockX = vVerts[0];
        GLfloat blockY = vVerts[7];
        if (key == GLUT_KEY_UP) {
            blockY += stepSize;
        }
        if (key == GLUT_KEY_DOWN) {
            blockY -= stepSize;
        }
        if (key == GLUT_KEY_LEFT) {
            blockX -= stepSize;
        }
        if (key == GLUT_KEY_RIGHT) {
            blockX += stepSize;
        }
    
        if (blockX < -1.0f) {
            blockX = -1.0f;
        }
        if (blockX > 1.0f - blockSize * 2) {
            blockX = 1.0f - blockSize * 2;
        }
        if (blockY < - 1.0f + blockSize * 2) {
            blockY = - 1.0f + blockSize * 2;
        }
        if (blockY > 1.0f) {
            blockY = 1.0f;
        }
        vVerts[0] = blockX;
        vVerts[1] = blockY - blockSize * 2;
    
        vVerts[3] = blockX + blockSize * 2;
        vVerts[4] = blockY - blockSize * 2;
    
        vVerts[6] = blockX + blockSize * 2;
        vVerts[7] = blockY;
    
        vVerts[9] = blockX;
        vVerts[10] = blockY;
    
        squareBatch.CopyVertexData3f(vVerts);
        glutPostRedisplay();
    }
    
    //开始渲染
    void renderScene(void) {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
        
        GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 0.5f };
        GLfloat vGreen[] = { 0.0f, 1.0f, 0.0f, 1.0f };
        GLfloat vBlue[] = { 0.0f, 0.0f, 1.0f, 1.0f };
        GLfloat vBlack[] = { 0.0f, 0.0f, 0.0f, 1.0f };
        
        //将4个固定矩形绘制好
        shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vGreen);
        greenBatch.Draw();
        
        shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
        redBatch.Draw();
        
        shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlue);
        blueBatch.Draw();
        
        shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vBlack);
        blackBatch.Draw();
        
        //组合的核定代码 glEnable glBlendFunc glDisable注释掉后就就不会混合了,可以注释掉看效果
        //1.开启混合
        glEnable(GL_BLEND);
        //2.开启组合函数,计算混合颜色因子
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        //3.使用着色器管理
        //参数1 使用单位着色器  参数2 着色器颜色
        shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
        //4.容器类开始绘制
        squareBatch.Draw();
        //5.关闭混合
        glDisable(GL_BLEND);
        //同步绘制命令
        glutSwapBuffers();
    }
    
    //窗口改变时接受新的宽度和高度,0,0代表窗口中视口的左下角坐标,w,h代表像素
    void ChangeSize(int w, int h) {
        glViewport(0, 0, w, h);
    }
    
    int main(int argc, char *argv[]) {
        gltSetWorkingDirectory(argv[0]);
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
        glutInitWindowSize(800, 600);
        glutCreateWindow("移动矩形,观察颜色");
        GLenum err = glewInit();
        if (GLEW_OK != err) {
            fprintf(stderr, "Error:%s\n",glewGetErrorString(err));
            return 1;
        }
        
        glutReshapeFunc(ChangeSize);
        glutDisplayFunc(renderScene);
        glutSpecialFunc(specialKeys);
        setupRC();
        glutMainLoop();
        
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:3.OpenGL渲染技巧

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