关于OpenGL隐藏面剔除

首先我们渲染一个甜甜圈, 来看一下效果. 部分代码如下:

直接调用框架内写好的方法, 不需要自己处理顶点坐标.

    // 设置背景颜色
    glClearColor(0.3f, 0.3f, 0.3f, 1.0f );
    
    //初始化着色器管理器
    shaderManager.InitializeStockShaders();
    
    //将相机向后移动7个单元:肉眼到物体之间的距离
    viewFrame.MoveForward(7.0);
    
    //创建一个甜甜圈
    //void gltMakeTorus(GLTriangleBatch& torusBatch, GLfloat majorRadius, GLfloat minorRadius, GLint numMajor, GLint numMinor);
    //参数1:GLTriangleBatch 容器帮助类
    //参数2:外边缘半径
    //参数3:内边缘半径
    //参数4、5:主半径和从半径的细分单元数量
   
    gltMakeTorus(torusBatch, 1.0f, 0.3f, 52, 26);
    
    //点的大小
    glPointSize(4.0f);

进行渲染

    //把摄像机矩阵压入模型矩阵中
    modelViewMatix.PushMatrix(viewFrame);
    
    GLfloat vRed[] = { 1.0f, 0.0f, 0.0f, 1.0f };
    
    //使用平面着色器
    //参数1:平面着色器
    //参数2:模型视图投影矩阵
    //参数3:颜色
    //shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vRed);
    
    //使用默认光源着色器
    //通过光源、阴影效果跟提现立体效果
    //参数1:GLT_SHADER_DEFAULT_LIGHT 默认光源着色器
    //参数2:模型视图矩阵
    //参数3:投影矩阵
    //参数4:基本颜色值
//    shaderManager.UseStockShader(GLT_SHADER_DEFAULT_LIGHT, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vRed);
    
    GLfloat vLight[] = { -1.0f, 0.5f, 10.0f };
    shaderManager.UseStockShader(GLT_SHADER_POINT_LIGHT_DIFF, transformPipeline.GetModelViewMatrix(), transformPipeline.GetProjectionMatrix(), vLight, vRed);
    //绘制
    torusBatch.Draw();
    
    //出栈
    modelViewMatix.PopMatrix();

运行之后效果如下

image.png

因为案例中采用固定管线进行绘制, 使用的默认光源着色器, 片元着色器在处理看不见的面时, 会计算为黑色.
所以在渲染3D图形的时候, 需要决定哪些面是不可见的, 哪些面是可见的, 看不见的面要丢弃, 这种情况叫做"隐藏面消除"

这种渲染结果是由于GPU无法判断是渲染正面(红色)还是渲染背面(黑色), 会发生颜色混乱. 那么如何解决这种情况呢?

一、油画法(一般不被采用, 了解即可)

-先绘制场景中距离观察者较远的物体, 后绘制近的物体.


image.png

如图, 先绘制红色面, 最后绘制灰色面, 即可以解决隐藏面消除的问题. 但是是否会有弊端呢?

image.png
  1. 如图所示, 由于涉及深度问题(Z值), 从而无法判断面的前后, 所以无法进行处理.
  2. 效率问题, 面与面重叠的部分会进行多次绘制, 从而导致片元着色器效率低.
二、正背面剔除

任何物体都有两个面, 正面和背面, OpenGL可以做到区分正反面, 所有可以通过绘制正面或反面解决隐藏面消除的问题.

那么OpenGL是如何做到区分正反面的呢? 答案是通过顶点计算.

正背面区分:
1.正面:按逆时针顶点顺序连接的三角形面.
2.背面:按顺时针顶点顺序连接的三角形面.

image.png

如图所示, 在同一个角度观察, 正面的三角形顶点连接顺序为逆时针, 而背面顶点为顺时针连接, OpenGL也提供api可以修改规则, 可以把顺时针修改为正面, 反之为背面, 但是一般我们使用默认即可.

正背面剔除代码如下:

开启正背面剔除
glEnable(GL_CULL_FACE);
glFrontFace(GL_CCW);//默认为GL_CCW, 表示逆时针为正面 GL_CW表示顺时针为正面
glCullFace(GL_BACK);//剔除背面

关闭正背面剔除
glDisable(GL_CULL_FACE);

例如,剔除正⾯面实现(1)
glCullFace(GL_BACK); 
glFrontFace(GL_CW);

例如,剔除正⾯面实现(2)
glCullFace(GL_FRONT);

接下来我们开启正背面剔除之后, 运行代码

image.png

之前的问题解决了, 没有发生颜色混乱的问题, 但是又出现了新的问题.

想解决这个问题, 请看下一遍OpenGL深度测试.

你可能感兴趣的:(关于OpenGL隐藏面剔除)