• 使用OpenGL来画个甜甜圈


    • 首先定义变量
     1 //设置角色帧,作为相机
     2 GLFrame             viewFrame;
     3 //使用GLFrustum类来设置透视投影
     4 GLFrustum           viewFrustum;
     5 //三角形批次类
     6 GLTriangleBatch     torusBatch;
     7 //模型视图矩阵
     8 GLMatrixStack       modelViewMatix;
     9 //投影矩阵
    10 GLMatrixStack       projectionMatrix;
    11 //着色器管道
    12 GLGeometryTransform transformPipeline;
    13 //着色器管理器
    14 GLShaderManager     shaderManager;
    • 然后是main函数,我们之前已经讲过,都是一些固定的操作
    • 接下来SetupRC进行一些初始化,包括设置背景色,初始化着色器管理器,设置观察者视角
     1 void SetupRC()
     2 {
     3     //1.设置背景颜色
     4     glClearColor(0.3f, 0.3f, 0.3f, 1.0f );
     5     
     6     //2.初始化着色器管理器
     7     shaderManager.InitializeStockShaders();
     8     
     9     //3.将相机向后移动7个单元:肉眼到物体之间的距离
    10     viewFrame.MoveForward(10);
    11 
    12     //4.创建一个甜甜圈
    13     gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);
    14     
    15     //5.点的大小(方便点填充时,肉眼观察)
    16     glPointSize(4.0f);
    17 }

    这个地方,我们用到了gltMakeTorus函数,它的每个参数分表代表GLTriangleBatch 容器帮助类,外边缘半径,内边缘半径以及主半径和从半径的细分单元数量

    void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
    • 然后通过ChangeSize函数设置视口,投影模式,初始化投影矩阵和渲染管线
     1 void ChangeSize(int w, int h)
     2 {
     3     //1.防止h变为0
     4     if(h == 0)
     5         h = 1;
     6     
     7     //2.设置视口窗口尺寸
     8     glViewport(0, 0, w, h);
     9     
    10 
    11     // 3.设置透视模式,初始化其透视矩阵
    12     viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 100.0f);
    13     
    14     //4.把透视矩阵加载到透视矩阵对阵中
    15     projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
    16     
    17     //5.初始化渲染管线
    18     transformPipeline.SetMatrixStacks(modelViewMatix, projectionMatrix);
    19 }
    • 最后通过RenderScene渲染场景(清缓存,设置MVP矩阵,渲染颜色,图元组合模式)
     1 void RenderScene()
     2 {
     3     //1.清除窗口和深度缓冲区
     4     //不清空颜色/深度缓冲区时.渲染会造成什么问题-->残留数据,颜色混合
     5     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     6     
     7     //2.把摄像机矩阵压入模型矩阵中
     8     modelViewMatix.PushMatrix(viewFrame);
     9 
    10     //3.设置绘图颜色
    11     GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    12     
    13     //4.
    14     //使用平面着色器
    15     //参数1:平面着色器
    16     //参数2:模型视图投影矩阵
    17     //参数3:颜色
    18     shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vRed);
    19     
    20     //5.绘制
    21     torusBatch.Draw();
    22 
    23     //6.出栈 绘制完成恢复
    24     modelViewMatix.PopMatrix();
    25     
    26     //7.交换缓存区
    27     glutSwapBuffers();
    28 }

    这样,一个甜甜圈就绘制完成了,如果想要移动这个甜甜圈,那么还可以:

    • 通过上下左右键移动控制观察者角度
     1 void SpecialKeys(int key, int x, int y)
     2 {
     3     //1.判断方向
     4     if(key == GLUT_KEY_UP)
     5         //2.根据方向调整观察者位置 绕Y轴选择-5度
     6         viewFrame.RotateWorld(m3dDegToRad(-5.0), 1.0f, 0.0f, 0.0f);
     7     
     8     if(key == GLUT_KEY_DOWN) //绕Y轴选择5度
     9         viewFrame.RotateWorld(m3dDegToRad(5.0), 1.0f, 0.0f, 0.0f);
    10     
    11     if(key == GLUT_KEY_LEFT) //绕X轴选择-5度
    12         viewFrame.RotateWorld(m3dDegToRad(-5.0), 0.0f, 1.0f, 0.0f);
    13     
    14     if(key == GLUT_KEY_RIGHT)//绕X轴选择5度
    15         viewFrame.RotateWorld(m3dDegToRad(5.0), 0.0f, 1.0f, 0.0f);
    16     
    17     //3.重绘
    18     glutPostRedisplay();
    19 }

     甜甜圈画出来,乍一看是没问题,只要旋转变换过后,就会出现黑色的bug。

    问题原因:

    a) 从观察者视角,不可见部分也进行了渲染--->不可见区域应该丢弃,即隐藏面消除(Hidden surface elimination)

    b) 从观察者视角,位于同一个平面的像素点,渲染出现问题--->开启深度测试

    弊端:

    远近离观察者一致时,无法处理--->深度测试

    多余的去绘制 --->正背面剔除

    3. 正面&背⾯剔除

    何为正面?

    默认从观察者角度,逆时针的面为正面,开发者也可以修改和指定正面,但此状态是全局的,一处修改其他渲染位置同时遵循指定的正面规则

    正面&背⾯剔除,就是检查所有正面朝向观察者的面,渲染它们.而丢弃背面朝向的面. 同时用户也可以选择剔除哪一个面

     1 //开启表⾯剔除(默认背面剔除)
     2 void glEnable(GL_CULL_FACE);
     3 
     4 //关闭表面剔除(默认背面剔除)
     5 void glDisable(GL_CULL_FACE);
     6 
     7 
     8 //⽤户选择剔除那个面(正面/背面) 
     9 //mode参数为: GL_FRONT,GL_BACK,GL_FRONT_AND_BACK ,默认GL_BACK ⽤户指定绕序那个为正面
    10 void glCullFace(GLenum mode);
    11 
    12 //指定正面
    13 //GL_CW:指定顺时针环绕的多边形为正面;
    14 //GL_CCW:指定逆时针环绕的多边形为正面
    15 //mode参数为: GL_CW,GL_CCW,默认值:GL_CCW
    16 void glFrontFace(GLenum mode);
    17 
    18 //剔除正面,方法一:
    19 glCullFace(GL_BACK);
    20 glFrontFace(GL_CW); 
    21 
    22 //剔除正面,方法二:
    23 glCullFace(GL_FRONT);

    正背面剔除之后,背面黑色部分绘制的问题解决了,可是一旋转,又产生了新的问题。

    如果前后两个点都是正面或者背面,这时候OpenGL无法区分哪个面在前,哪个面在后。

    下一篇 深度测试 中,我们将讨论如何解决这样的问题。

  • 相关阅读:
    leetcode319
    leetcode516
    leetcode46
    leetcode337
    leetcode287
    leetcode328
    leetcode241
    2018-6-30-dotnet-设计规范-·-抽象类
    2018-6-30-dotnet-设计规范-·-抽象类
    2018-8-10-WPF-如何画出1像素的线
  • 原文地址:https://www.cnblogs.com/hadyt/p/13280269.html
Copyright © 2020-2023  润新知