https://www.khronos.org/opengl/wiki/Face_Culling
一、说明
基元汇编是 OpenGL 渲染管道中的阶段,在该阶段,基元被划分为一系列单独的基本基元。经过一些小的处理后,如下所述,它们被传递到光栅器进行渲染。
二 早期原始组装
基元组装步骤的目的是将顶点流转换为基基元序列。例如,一个包含 12 个顶点的行列表的基元需要生成 11 个行基基元。
完整的原始组装步骤(包括下面的处理)将在 Vertex 后处理期间进行。但是,某些顶点处理步骤需要将基元分解为一系列基本基元。例如,几何着色器对基元序列中的每个输入基元进行操作。因此,在 GS 可以执行之前,必须发生一种形式的原始程序集。
这个早期的基元程序集只执行到基本基元的转换。它不执行以下任何处理步骤。
如果“几何着色器”或“曲面细分”处于活动状态,则必须进行此类早期处理。曲面细分的早期组装步骤已简化,因为 Patch 基元始终是 Patch 序列。
2.1 原始秩序
处理基元的顺序是明确定义的(在大多数情况下)。顺序定义如下:
单个 Vertex Rendering 命令中的所有基元都先于后续此类命令中的任何基元。
如果绘图命令是多绘制命令,则一个子绘制的所有基元都排列在后续子绘制的基元之前。
在绘制或多重绘制的子绘制中,如果绘图命令是实例化渲染命令,则一个实例中的所有基元都排在具有较大gl_InstanceID值的基元之前。
在特定的绘制/子绘制/实例中,基元根据顶点流和该绘制的渲染参数进行排序,由渲染命令提供的基元类型解释。
如果曲面细分评估着色器处于活动状态,则通过曲面细分单个面片生成的所有基元都先于具有较大gl_PrimitiveID值的面片生成的任何基元。
相对于从同一补丁生成的其他基元,由特定补丁生成的任何给定基元的顺序都是不确定的。
如果几何着色器处于活动状态,则根据上述排序规则,从特定输入基元生成的基元在由后续输入基元生成的基元之前排序。
对于特定的输入基元,如果 GS 使用 Geometry Shader Instancing,则实例生成的所有基元都排在具有较大 gl_InvocationID值的实例生成的基元之前。
在 GS 调用中,GS 生成的基元按发出这些基元及其组件顶点的调用顺序排序。
2.2 光栅器丢弃
所有基元都可以通过启用GL_RASTERIZER_DISCARD来丢弃。这样可以防止栅格化任何基元。
这对于测试先前渲染阶段的性能很有用,但对于防止渲染在转换反馈操作期间生成的基元也很有用。
三、背面剔除
所有变换步骤之后的三角形基元都具有特定的朝向。这是由构成三角形的三个顶点的顺序以及它们在屏幕上的表观顺序定义的。三角形可以根据其表面的表面被丢弃,这一过程称为面剔除。
3.1 绕线顺序
当用户发出绘图命令时,渲染管线处理的顶点将按照顶点规范提供的顺序进行处理。几何着色器可以更改顺序,但即便如此,每个 GS 调用创建的顶点也是相对于其他顶点排序的。“曲面细分评估着色器”可以使用特殊选项直接控制曲面细分面片中顶点的顺序。
在基元组装过程中将顶点分解为基元时,会记录顶点相对于基元中其他顶点的顺序。三角形中顶点的顺序与它们的视觉方向相结合时,可用于确定三角形是从“正面”还是“背面”看到。
这是由三角形的缠绕顺序决定的。给定三角形的三个顶点的顺序,三角形可以看起来具有顺时针绕组或逆时针绕组。顺时针意味着三个顶点按顺序绕三角形的中心顺时针旋转。逆时针是指三个顶点按顺序绕三角形中心逆时针旋转。
哪一侧被认为是“正面”,由此功能控制:
void glFrontFace(GLenum mode);
这是全局状态。模式可以是GL_CW或GL_CCW,这意味着顺时针或逆时针分别是正面的。在新创建的 OpenGL 上下文中,默认正面为 GL_CCW。
非三角形基元将始终被视为显示其正面。
3.1.1 曲面细分
主条目:曲面细分绕线顺序
在曲面细分期间生成的抽象面块顶点的缠绕顺序由曲面细分评估着色器控制。它是 TES 指定的布局选项,而不是运行时值。绕组顺序根据方向指定:cw 和 ccw。哪个被认为是“前端”仍然由 glFrontFace 定义。
请注意,这仅指定抽象面片空间中三角形的缠绕顺序。每个三角形的最终缠绕顺序将基于这些顶点的位置如何通过 TES(或后续的几何着色器)进行转换。所以这个设置只是一个起点,而不是终点。
3.2 面剔除
设置三角形正面的主要用途是允许剔除正面或背面三角形。
考虑一个立方体;它由 12 个三角形组成,但其中 6 个将与其他 6 个朝向相反的方向。除非立方体是透明的,否则其中 6 个三角形将始终被其他 6 个三角形覆盖。事实上,根据投影的不同,可以覆盖 6 个以上的三角形;想象一下,从正面看一个离相机很近的立方体。透视缩短意味着即使是侧面也背对着相机。
面部剔除允许在昂贵的光栅化和片段着色器操作之前删除闭合表面的不可见三角形。
要激活背面剔除,必须先使用 glEnable 启用GL_CULL_FACE。默认情况下,脸面剔除处于禁用状态。要选择要剔除的一侧,请使用以下函数:
void glCullFace(GLenum mode));
模式可以设置为GL_FRONT、GL_BACK或GL_FRONT_AND_BACK。后者将剔除所有三角形。这与 glEnable(GL_RASTERIZER_DISCARD) 不同,因为后者将关闭所有基元,而剔除两个面只会剔除三角形(因为只有它们有面)。
默认情况下,GL_BACK 是要剔除的面。
3.3 片段着色器
主条目:Fragment_Shader#System_inputs
片段着色器能够检测基元的栅格化面。如果从正面看到基元(或者是没有正面的基元),则内置 FS 输入gl_FrontFacing将为 true,如果从背面看到,则为 false。