4.7 几何着色器
4.7.1 基本概念
1、顶点和片段着色器之间有一个可选的几何着色器,几何着色器的输入是一个图元(如点或三角形)的一组顶点,顶点发送到下一着色器之前可对它们随意变换,将顶点变换为完全不同的图元,并且还能生成比原来更多的顶点。
#version 330 core
layout (points) in;
layout (line_strip, max_vertices = 2) out;
void main() {
gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0);
EmitVertex();
gl_Position = gl_in[0].gl_Position + vec4( 0.1, 0.0, 0.0, 0.0);
EmitVertex();
EndPrimitive();
}
2、在几何着色器的顶部,在in关键字前声明一个布局修饰符,声明从顶点着色器输入的图元类型,括号内的数字表示的是一个图元所包含的最小顶点数。
- points:绘制GL_POINTS图元时(1)。
- lines:绘制GL_LINES或GL_LINE_STRIP时(2)
- lines_adjacency:GL_LINES_ADJACENCY或GL_LINE_STRIP_ADJACENCY(4)
- triangles:GL_TRIANGLES、GL_TRIANGLE_STRIP或GL_TRIANGLE_FAN(3)
- triangles_adjacency:GL_TRIANGLES_ADJACENCY或GL_TRIANGLE_STRIP_ADJACENCY(6)
3、在out关键字前面加一个布局修饰符,指定几何着色器输出的图元类型:
- points
- line_strip
- triangle_strip
4、同时可以设置一个它最大能够输出的顶点数量(超过了这个值,OpenGL将不会绘制多出的顶点),使用上面定义的着色器输出一条线段,最大顶点数等于2:
5、几何着色器中有一个内建接口块变量gl_in[]
,包含了几个变量。其中,gl_Position
与顶点着色器输出非常相似,它被声明为一个数组,因为几何着色器的输入是一个图元的所有顶点。
in gl_Vertex
{
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
} gl_in[];
6、利用几何着色器函数EmitVertex
和EndPrimitive
来生成新的数据了。调用EmitVertex
时,gl_Position
中的向量会被添加到图元中来。当EndPrimitive
被调用时,所有发射出的顶点都会合成为指定的输出渲染图元。在一个或多个EmitVertex
调用之后重复调用EndPrimitive
能够生成多个图元。
void main() {
gl_Position = gl_in[0].gl_Position + vec4(-0.1, 0.0, 0.0, 0.0);
EmitVertex();
gl_Position = gl_in[0].gl_Position + vec4( 0.1, 0.0, 0.0, 0.0);
EmitVertex();
EndPrimitive();
}
7、在这个例子中,接受一个点图元作为输入,从原始顶点位置平移了0.1,发射了两个顶点。之后调用EndPrimitive
,将这两个顶点合成为一个包含两个顶点的线条。即以这个点为中心,创建一条水平的线图元。
glDrawArrays(GL_POINTS, 0, 4);
4.7.2 使用几何着色器
1、在标准化设备坐标的z平面上绘制四个点,包含顶点信息和颜色信息
float points[] = {
-0.5f, 0.5f, 1.0f, 0.0f, 0.0f, // 左上
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, // 右上
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, // 右下
-0.5f, -0.5f, 1.0f, 1.0f, 0.0f // 左下
};
2、顶点着色器在z平面绘制点,使用一个接口块将颜色属性发送到几何着色器中。
#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec3 aColor;
out VS_OUT{
vec3 color;
}vs_out;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
vs_out.color = aColor;
}
3、创建一个传递几何着色器,接收点图元,在每个点的位置上绘制一个房子。每个顶点都是原始点的位置加上一个偏移量,来组成一个大的三角形带。使用三角形带(Triangle Strip
)绘制,使用的顶点更少。在第一个三角形绘制完之后,每个后续顶点将会在上一个三角形边上生成另一个三角形,每3个临近的顶点将会形成一个三角形,得到(1, 2, 3)、(2, 3, 4)、(3, 4, 5)3个三角形。一个三角形带有N个顶点,会生成N-2个三角形。
4、几何着色器的输出
- 将几何着色器的输出设置为
triangle_strip
, - 在几何着色器中声明相同的接口块(使用一个不同的接口名
VS_OUT
)接受颜色属性,因为几何着色器是作用于输入的一组顶点的,从顶点着色器发来输入数据总是会以数组的形式表示出来。 - 为片段着色器阶段声明一个输出颜色向量
fColor
,因为片段着色器只需要一个插值的颜色,就是一个单独的向量。
#version 330 core
layout (points) in;
layout (triangle_strip, max_vertices = 5) out;
in VS_OUT {
vec3 color;
} gs_in[];
out vec3 fColor;
void build_house(vec4 position)
{
fColor = gs_in[0].color; // gs_in[0] 因为只有一个输入顶点
gl_Position = position + vec4(-0.2, -0.2, 0.0, 0.0); // 1:左下
EmitVertex();
gl_Position = position + vec4( 0.2, -0.2, 0.0, 0.0); // 2:右下
EmitVertex();
gl_Position = position + vec4(-0.2, 0.2, 0.0, 0.0); // 3:左上
EmitVertex();
gl_Position = position + vec4( 0.2, 0.2, 0.0, 0.0); // 4:右上
EmitVertex();
gl_Position = position +