与曲面细分一样,几何着色器使程序员能够以顶点着色器中无法实现的方式操纵顶点组。在某些情况下,可以使用曲面细分着色器或者几何着色器完成同样的任务,因为它们的功能在某些方面重叠。
几何着色器(Geometry Processor)是一个可编程单元,它对输入顶点的数据进行操作在顶点处理后组装的基本体,并输出形成输出的顶点序列原语。使用OpenGL着色语言编写并在此处理器上运行的编译单元是称为几何着色器。成功编译和链接一组几何着色器后,它们将生成在几何处理器上运行的几何着色器可执行文件。
对几何处理器上的几何体着色器可执行文件的单个调用将在具有固定顶点数的声明输入基元。这个调用可以发出一个变量组装成声明的输出基本体类型和类型的基本体的顶点数传递到后续管道阶段。
OpenGL中的逐个图元处理
几何着色器阶段位于曲面细分和光栅化之间,位于用于图元处理的管线段内。顶点着色器允许一次操作一个顶点,而片段着色器一次可以操作一个片段(实际上是一个像素),但几何着色器却可以一次操作一个图元。

图元是 OpenGL 中绘制对象的基本元件。只有少数几种类型的图元;我们将主要关注操纵三角形图元的几何着色器。因此,当我们说几何着色器可以一次操作一个图元时,我们通常意味着着色器一次可以访问三角形的 3 个顶点。几何着色器允许一次性访问图元中的所有顶点,然后:
- 输出相同的图元保持不变;
- 输出修改了顶点位置的相同类型图元;
- 输出不同类型的图元;
- 输出更多的其他图元;
- 删除图元(根本不输出)。
与曲面细分评估着色器类似,可以在几何着色器中将传入的顶点属性作为数组进行访问。但是,在几何着色器中,传入属性数组仅索引到图元尺寸那么大。例如,如果图元是三角形,则可用索引为 0、 1、 2。使用预先定义的数组 gl_in 访问顶点数据本身,如下所示。
gl_in[2].gl_Position;// 第三个顶点的位置
与曲面细分评估着色器类似,几何着色器输出的顶点属性都是标量。也就是说,输出是形成图元的各个顶点(它们的位置和其他属性变量,如果有的话)的流。
有一个布局修饰符用于设置图元输入/输出类型和输出大小。特殊的 GLSL 命令EmitVertex()指定了将要输出一个顶点。特殊的 GLSL 命令 EndPrimitive()表示一个特定的图元构建完成。
有一个内置变量 gl_PrimitiveIDIn,它保存当前图元的 ID。 ID 从 0 开始,并计数到图元总数减1。
我们将探讨四种常见的操作类型:
- 修改图元;
- 删除图元;
- 添加图元;
- 更改图元类型。
void EmitVertex()
向第一个顶点流发送顶点。
它将输出变量的当前值发送到第一个(可能只有一个)图元流上的当前输出图元。
void EndPrimitive()
在第一个顶点流上完成当前输出图元。
它在第一个(可能是唯一的)顶点流上完成当前输出图元,并启动一个新的输出图元。不发送顶点。
内建变量:
in gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
float gl_CullDistance[];
} gl_in[];
in int gl_PrimitiveIDIn;
in int gl_InvocationID;
out gl_PerVertex {
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
float gl_CullDistance[];
};
out int gl_PrimitiveID;
out int gl_Layer;
out int gl_ViewportIndex;
修改图元
当通过对图元(通常为三角形)的单独更改就可以影响对象形状的改变时,使用几何着色器就很方便。
C++/OpenGL 应用程序需要编译几何着色器并在链接之前将其附加到着色器程序。新着色器被指定为几何着色器,如下所示。
GLuint gShader = glCreateShader(GL_GEOMETRY_SHADER);
// 几何着色器
#version 430
in vec3 varyingNormal[];// 来自顶点着色器的输入
in vec3 varyingLightDir[];
in vec3 varyingHalfVector[];
out vec3 varyingNormalG;// 输出给光栅着色器然后到片段着色器
out vec3 varyingNormalDirG;
out vec3 varyingHalfVectorG;
layout(triangles) in;// 指定[输入]图元类型
layout(triangle_strip, max_vertices = 3) out;// 指定[输出]图元类型
// 矩阵和光照统一变量和以前一样
...
void main() {
// 沿着法向量移动顶点,并将其他顶点属性原样传递
for (int i = 0; i < 3; i++) {
gl_Position = proj_matrix * gl_in[i].gl_Position
+ normalize(vec4(varyingNormal[i], 1.0)) * 0.4;
varyingNormalG = varyingNormal[i];
varyingLightDirG = varyingLightDir[i];
varyingHalfVectorG = varyingHalfVector[i];
EmitVertex();// 指定[输出]一个顶点:gl_Position、varying....标量
}
EndPrimitive();// 完成一个图元的构建
}
与顶点着色器的输出变量对应的输入变量被声明为数组。

最低0.47元/天 解锁文章
565

被折叠的 条评论
为什么被折叠?



