OpenGL 隐藏面消除及混合

在绘制3D场景的时候,我们需要决定哪些部分是对观察者可见,或者哪些部分是对观察者不可见的。对于不可见的部分,就不应该渲染。这种情况叫做隐藏面消除(Hidden surface elimination)。

  • 正背面剔除(Face Culling)

    • 默认情况下,按照逆时针顶点连接顺序的三角形面为正面

    • 默认情况下,按照顺时针顶点连接顺序的三角形面为背面

    • 开启正背面剔除(默认背面剔除)

      void glEnable(GL_CULL_FACE)
      
    • 关闭表面剔除(默认背面剔除)

      void glDisable(GL_CULL_FACE) 
      
    • 选择剔除那个面

      void glCullFace(GLenum mode)
      mode参数为: GL_FRONT, GL_BACK, GL_FRONT_AND_BACK, 默认GL_BACK
      
    • 指定绕序那个为正面

      void glFrontFace(GLenum mode)
      mode的参数为: GL_CW, GL_CCW, 默认值: GL_CCW
      
  • 深度缓冲区

    • 专门存储每个像素点的深度值,深度值越大,则离摄像机越远。
    • 在不使用深度测试的时候,如果我们先绘制一个距离比较近的物体,再绘制距离较远的物体,则距离远的物体因为后绘制而把距离近的物体覆盖掉。有了深度缓冲区后,绘制物体的顺序就不那么重要的。只要存在深度缓冲区,OpenGL都会把像素的深度值写入到缓冲区中。除非调用glDepthMask(GL_FALSE)来禁止写入。
  • 深度测试

    • 深度缓冲区(DepthBuffer)和颜色缓冲区(ColorBuffer)是对应的。

    • 在决定是否绘制一个物体表面时,首先要将表面对应的像素深度值与当前深度缓冲区中的值进行比较。如果大于深度缓冲区中的值,则丢弃这部分,否则利用这个像素对应的深度值和颜色值分别更新深度缓冲区和颜色缓冲区,这个过程称为深度测试。

    • 深度值一般由16位、24位、32位值表示。通常是24位,位数越高,深度精确度更好。

    • 开启深度测试

      glEnable(GL_DEPTH_TEST)
      
    • 清除深度缓冲区(默认值为1.0,表示最大的深度值,深度值的范围为[0, 1]之间,值越小表示越靠近观察者,值越大表示越远离观察者)

      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
      
    • 深度测试判断模式

      glDepthFunc(GLEnum mode)
      
      枚举值 描述
      GL_NEVER 总是不能通过测试
      GL_ALWAYS 总是通过测试
      GL_LESS 当前深度值 < 存储的深度值时通过
      GL_LEQUAL 当前深度值 <= 存储的深度值时通过
      GL_EQUAL 当前深度值 = 存储的深度值时通过
      GL_GEQUAL 当前深度值 >= 存储的深度值时通过
      GL_GREATER 当前深度值 > 存储的深度值时通过
      GL_NOTEQUAL 当前深度值 != 存储的深度值时通过
    • 打开/阻断 深度缓冲区写入

      glDepthMask(GLboolean flag)
      flag: GL_TRUE 开启深度缓冲区写入,GL_FALSE 关闭深度缓冲区写入
      
  • ZFighting闪烁问题

    • 由于深度缓冲区精度的限制,对于深度值相差非常小的情况,OpenGL就可能出现不能正确判断两者的深度值,就会导致深度测试的结果不可预测,显示出来的现象就是交错闪烁两个画面。

    • 启用 Polygon Offset(多边形偏移),让深度值之间产生间隔。

      glEnable(GL_POLYGON_OFFSET_FILL)
      
      参数列表:
      GL_POLYGON_OFFSET_POINT  对应光栅化模式:GL_POINT
      GL_POLYGON_OFFSET_LINE   对应光栅化模式:GL_LINE
      GL_POLYGON_OFFSET_FILL   对应光栅化模式:GL_FILL
      
    • 指定偏移量

      glPolygonOffset(GLFloat factor, GLFloat units)
      
      应用到片段上总偏移计算方程式:
      Depth Offset = (Dz * factor) + (r * units)
      Dz: 深度值
      r: 使得深度缓冲区产生变化的最小值
      
      可以设置factor和units为-1,-1。
      
    • 关闭 Polygon Offset

      glDisable(GL_POLYGON_OFFSET_FILL)
      
  • 裁剪

    • 用于渲染时限制绘制区域。

    • 开启裁剪

      glEnable(GL_SCISSOR_TEST)
      
    • 关闭裁剪

      glDisable(GL_SCISSOR_TEST)
      
    • 指定裁剪窗口

      void glScissor(GLint x, GLint y, GLsize width, GLsize height)
      
    • 窗口、视口、裁剪区域

      • 窗口:显示界面
      • 视口:窗口中用来显示图形的一块矩形区域,它可以和窗口等大,也可以比窗口大或者小。只有绘制在视口区域中的图形才能被显示,如果图形有一部分超出视口区域,那么那一部分是看不到的。通过glViewPort()函数设置。
      • 裁剪区域(平行投影):视口矩形区域的最小最大x坐标(left, right)和最小最大y坐标(bottom, top),而不是窗口的最小最大x坐标和y坐标。通过glOrtho()函数设置,这个函数还需指定最近最远z坐标,形成一个立体的裁剪区域。
    • 混合

      • 开启混合

        glEnable(GL_BLEND)
        
      • 组合颜色
        目标颜色:已经存储在颜色缓存区的颜色值
        源颜色:作为当前渲染命令结果进入颜色缓存区的颜色值
        在默认情况下,混合方程式如下:

        Cf = (Cs * S) + (Cd * D)
        Cf: 结果颜色
        Cs: 源颜色
        Cd: 目标颜色
        S: 源混合因子
        D: 目标混合因子
        
      • 设置混合因子

        glBlendFunc(GLenum S, GLenum D)
        S: 源混合因子
        D: 目标混合因子
        
        枚举值 RGB混合因子 AlPha混合因子
        GL_ZERO (0,0,0) 0
        GL_ONE (1,1,1) 1
        GL_SRC_COLOR (Rs,Gs,Bs) As
        GL_ONE_MINUS_SRC_COLOR (1,1,1)-(Rs,Gs,Bs) 1-As
        GL_DST_COLOR (Rd,Gd,Bd) Ad
        GL_ONE_MINUS_DST_COLOR (1,1,1)-(Rd,Gd,Bd) 1-Ad
        GL_SRC_ALPHA (As,As,As) As
        GL_ONE_MINUS_SRC_ALPHA (1,1,1)-(As,As,As) 1-As
        GL_DST_ALPHA (Ad,Ad,Ad) Ad
        GL_ONE_MINUS_DST_ALPHA (1,1,1)-(Ad,Ad,Ad) 1-Ad
        GL_CONSTANT_COLOR (Rc,Gc,Bc) Ac
        GL_ONE_MINUS_CONSTANT_COLOR (1,1,1)-(Rc,Gc,Bc) 1-Ac
        GL_CONSTANT_ALPHA (Ac,Ac,Ac) Ac
        GL_ONE_MINUS_CONSTANT_ALPHA (1,1,1)-(Ac,Ac,Ac) 1-Ac
        GL_SRC_ALPHA_SATURATE (f,f,f)*f=min(As,1-Ad) 1

        表中R、G、B、A分别表示红、绿、蓝、alpha
        下标s、d,分别表示源、目标
        表中c代表常量颜色(默认黑色)

      • 改变混合方程式

        glBlendEquation(GLenum mode)
        
        枚举值 RGB混合因子
        GL_FUNC_ADD Cf=(Cs * S) + (Cd * D)
        GL_FUNC_SUBTRACT Cf=(Cs * S) - (Cd * D)
        GL_FUNC_REVERSE_SUBTRACT Cf=(Cd * D) - (Cs * S)
        GL_MIN Cf=min(Cs,Cd)
        GL_MAX Cf=max(Cs,Cd)
      • 设置混合因子(RGB和Alpha分开设置)

        void glBlendFuncSeparate(GLenum strRGB, GLenum dstRGB, GLenum strAlpha, GLenum dstAlpha)
        
      • 设置常量混合颜色

        void glBlendColor(GLclampf red, GLclampf green, GLclamf blue, GLclampf alpha)
        
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容