概述

几何着色器(Geometry Shader)是pipeline中的可选阶段,位于vertex shader和tcs和tes之后,在fragment shader之前,几何着色器用单个基元作为输入,然后输入零个或多个基元,所以理论上geometry shader阶段可以更改图元类型


示例

  • vertex shader

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #version 450
    layout(location = 0) in vec3 position;
    layout(location = 1) in vec3 in_color;
    layout(location = 2) in float in_point_size;
    layout(location = 0) out vec4 vout_color;
    layout(location = 1) out float vout_point_size;

    void main()
    {
    gl_Position = vec4(position, 1.0);
    gl_PointSize = in_point_size;

    vout_color = vec4(in_color, 1.0);
    vout_point_size = in_point_size;
    }
  • geometry shader

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #version 450

    struct Vertex {
    vec4 color;
    float point_size;
    };

    layout(triangles, invocations =1) in;
    layout(location = 0) in Vertex vout[];
    layout(points, max_vertices = 4) out;
    layout(location = 0) out Vertex gout;

    void generate(int i) {
    gl_Position = (gl_in[i].gl_Position + gl_in[(i+1)%3].gl_Position) / 2;
    gl_PointSize = vout[i].point_size;
    gout.color = vout[i].color;
    gout.point_size = vout[i].point_size;
    EmitVertex();
    }

    void main() {
    generate(0);
    generate(1);
    generate(2);

    gl_Position = (gl_in[0].gl_Position + gl_in[1].gl_Position + gl_in[2].gl_Position) / 3;
    gl_PointSize = (vout[0].point_size + vout[1].point_size + vout[2].point_size) / 3;
    gout.color = (vout[0].color + vout[1].color + vout[2].color) / 3;
    gout.point_size = gl_PointSize;
    EmitVertex();
    }
  • fragment shader

    1
    2
    3
    4
    5
    6
    7
    8
    #version 450
    layout(location = 0) in vec4 vout_color;
    layout(location = 1) in float vout_point_size;
    layout(location = 0) out vec4 fout_color;

    void main() {
    fout_color = vout_color;
    }

输出图片如上图所示,和例子相符,输入的顶点数据格式为

1
2
3
4
5
6
// x y z   r g b  point_size
// 每个顶点为坐标xyz,然后是rgb,最后是点的大小
// 每个顶点数据用7个float表示
// 0.5, -0.5, 0.0, 1.0, 0.0, 0.0, 3.0, // 0
// 0.5, 0.5, 0.0, 0.0, 1.0, 0.0, 9.0, // 2
// -0.5, 0.5, 0.0, 0.0, 0.0, 1.0, 15.0, // 2


关键字说明

layout(triangles, invocations =1) in :这条语句表示基本输入的图元是三角形 invocations=1定义了几何着色器的实例化次数为1,表示每个输入的图元会被处理invocation次,这个值不设置默认为1
layout(points, max_vertices = 4) out; :这条语句表示gs输出的图元为点类型,而max_vertices表示最多生成4个新的顶点

1
2
3
4
5
6
7
void generate(int i) {
gl_Position = (gl_in[i].gl_Position + gl_in[(i+1)%3].gl_Position) / 2;
gl_PointSize = vout[i].point_size;
gout.color = vout[i].color;
gout.point_size = vout[i].point_size;
EmitVertex();
}

这个函数的功能是取三角形的两个顶点的中点,在中点的位置生成新的点
EmitVertex() :表示将生成的点发送到pipeline的下一个阶段(fragment shader)