• 使用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无法区分哪个面在前,哪个面在后。

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

  • 相关阅读:
    安装lnmp 时如何修改数据库数据存储地址及默认访问地址
    ubuntu 设置root用户密码并实现root用户登录
    解决ubuntu 远程连接问题
    linux 搭建FTP服务器
    PHP 根据ip获取对应的实际地址
    如何发布自己的composer包
    使用composer安装composer包报Your requirements could not be resolved to an installable set of packages
    laravel 框架配置404等异常页面
    使用Xshell登录linux服务器报WARNING! The remote SSH server rejected X11 forwarding request
    IoTSharp 已支持国产松果时序数据库PinusDB
  • 原文地址:https://www.cnblogs.com/hadyt/p/13280269.html
Copyright © 2020-2023  润新知