OpenGL 绘制圆环,开启正背面剔除、深度测试以及位置偏移

892 阅读4分钟

深度缓冲区与深度测试

  • 深度缓冲区,就是一块内存区域,专门存储着每个像素点(绘制在屏幕上的)深度值,深度值(Z值)越大,则离摄像机就越远。 深度缓冲区一般由窗口管理系统,例如GLFW来创建,深度值一般由16位,24位或者32位值表示,通常是24位。当然位数越高的话,深度的精确度越高,同一像素点我们只存粗距离观察者最近的像素点.

  • 开启深度测试 首先在初始化绘制模式 glutInitDisplayMode 中 我们要添加GL_DEPTH

在RenderScene函数中容器类开始绘制前,更改状态机的状态

模型矩阵
着色器管理类设置
glEnable(GL_DEPTH_TEST);
开始绘制
glDisable(GL_DEPTH_TEST);

正背面剔除

任何平面都有2个面,正面/背面,意味着观察者一个时刻只能看到其中一个面,而OpenGL可以通过分析顶点数据的顺序检测到所有此时面向观察者的面并渲染他们,从而丢弃背面的渲染,这样可以节约片元着色器的性能。 怎样区分正背面openGL 默认正背面方式如下 正面:按照逆时针顶点连接顺序的三角形面 背面:按照顺时针顶点连接顺序的三角形面 openGL 也为我们提供了修改正背面方式的函数

//用于修改正面的函数
void glFrontFace(GLenum mode);
//model有两种:GL_CW(顺时针),GL_CCW(逆时针),
//OpenGL中的默认值:GL_CCW

在RenderScene函数中容器类开始绘制前,更改状态机的状态

模型矩阵
着色器管理类设置
glEnable(GL_CULL_FACE);
开始绘制
glDisable(GL_CULL_FACE);

多边形偏移深度

Z-Fighting(Z冲突,闪烁)问题 开启深度测试后,由于深度缓冲区精度有限制,导致深度值在误差极小时,OpenGL出现无法判断的情况,导致出现画面交错闪现的现象,如下图

使用多边形偏移,主要有以下4个步骤

  1. 在绘制前,开启多边形偏移
glEnable(GL_POLYGON_OFFSET_FILL)
多边形偏移枚举值 对应的图像填充模式
GL_POLYGON_OFFSET_POINT GL_POINT
GL_POLYGON_OFFSET_LINE GL_LINE
GL_POLYGON_OFFSET_FILL GL_FILL
  1. 指定偏移量glPolygonOffset (GLfloat factor, GLfloat units);,参数一般填 -1 和 -1
  2. 绘制图形
  3. 在绘制完成后,关闭多边形偏移
glDisable(GL_POLYGON_OFFSET_FILL)

开启颜色混合

深度测试时候当顶层图层为半透明图层当时候需要与下方图层颜色进行混合获取混合后当图层渲染出来,这时候我们需要开启图形混合(GL_BLEND)功能

使用图形混合,主要有以下4个步骤

  1. 通过glEnable开启组合
  2. 通过glBlendFunc,开启组合函数,计算混合因子,并在每次渲染,都会将屏幕上所有的像素点都更新一遍,通常glBlendFunc 不需要设置我们使用系统默认的就够了
  3. 绘制图形
  4. 绘制完成后,需要关闭混合功能,通过glDisable关闭

在RenderScene函数中

模型矩阵
着色器管理类设置
//1.开启混合
    glEnable(GL_BLEND);
    //2.开启组合函数  计算混合颜色因子---每次渲染,会把屏幕上所有的像素点更新一遍
    //混合方程式:Cf = (Cs * S)+(Cd * D)
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    //3.使用着色器管理器
    //*使用 单位着色器
    //参数1:简单的使用默认笛卡尔坐标系(-1,1),所有片段都应用一种颜色。GLT_SHADER_IDENTITY
    //参数2:着色器颜色
    shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
    //4.容器类开始绘制
    squareBatch.Draw();
    //5.关闭混合功能
    glDisable(GL_BLEND);

RenderScene 整体代码如下

void RenderScene(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
    //压栈
    modelViewMatrix.PushMatrix();
    M3DMatrix44f mCamera;
    cameraFrame.GetCameraMatrix(mCamera);

    //矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果随后简存储在堆栈的顶部
    modelViewMatrix.MultMatrix(mCamera);
    
    M3DMatrix44f mObjectFrame;
    //只要使用 GetMatrix 函数就可以获取矩阵堆栈顶部的值,这个函数可以进行2次重载。用来使用GLShaderManager 的使用。或者是获取顶部矩阵的顶点副本数据
    objectFrame.GetMatrix(mObjectFrame);
    
    //矩阵乘以矩阵堆栈的顶部矩阵,相乘的结果随后简存储在堆栈的顶部
    modelViewMatrix.MultMatrix(mObjectFrame);
    
    /* GLShaderManager 中的Uniform 值——平面着色器
     参数1:平面着色器
     参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
     --transformPipeline.GetModelViewProjectionMatrix() 获取的
     GetMatrix函数就可以获得矩阵堆栈顶部的值
     参数3:颜色值(黑色)
     */
  
    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vGreen);
    
    //画黑色边框
    glPolygonOffset(-1.0f, -1.0f);// 偏移深度,在同一位置要绘制填充和边线,会产生z冲突,所以要偏移
    glEnable(GL_POLYGON_OFFSET_LINE);
    
    // 画反锯齿,让黑边好看些
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    
    //绘制线框几何黑色版 三种模式,实心,边框,点,可以作用在正面,背面,或者两面
    //通过调用glPolygonMode将多边形正面或者背面设为线框模式,实现线框渲染
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
    //设置线条宽度
    glLineWidth(2.5f);
    
    /* GLShaderManager 中的Uniform 值——平面着色器
     参数1:平面着色器
     参数2:运行为几何图形变换指定一个 4 * 4变换矩阵
         --transformPipeline.GetModelViewProjectionMatrix() 获取的
          GetMatrix函数就可以获得矩阵堆栈顶部的值
     参数3:颜色值(黑色)
     */

    shaderManager.UseStockShader(GLT_SHADER_FLAT, transformPipeline.GetModelViewProjectionMatrix(), vBlack);
    pBatch->Draw();

    // 复原原本的设置
    //通过调用glPolygonMode将多边形正面或者背面设为全部填充模式
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
    glDisable(GL_POLYGON_OFFSET_LINE);
    glLineWidth(1.0f);
    glDisable(GL_BLEND);
    glDisable(GL_LINE_SMOOTH);
}