实践项目:https://github.com/JackieLong/OpenGL/tree/main/project_geometry_shader_test
在顶点着色器和片段着色器之间有一个可选的几何着色器。输入是一个图元的一组顶点(三角形的三个顶点),它能这组顶点变换为不同的图元,还可以生成更多的顶点。
点击查看【processon】
一个简单的几何着色器例子如下:
#version 330 core// 输入的图元类型,不同类型也指定了图元包含的最少顶点数layout (points) in; // glDrawArrays(GL_POINTS, ...)时,输入的图元顶点,以下同理。// 最少顶点数1。layout (lines) in; // GL_LINES、GL_LINE_STRIP,最少顶点数2。layout (lines_adjacency) in; // GL_LINES_ADJACENCY、GL_LINE_STRIP_ADJACENCY,最少顶点数4。layout (triangles) in; // GL_TRIANGLES、GL_TRIANGLES_STRIP、GL_TRIANGLES_FAN,最少顶点数3。layout (triangles_adjacency) in; // GL_TRIANGLES_ADJACENCY、GL_TRIANGLE_STRIP_ADJACENCY,最少顶点数1。// 输出图元类型,max_vertices表示最大输出顶点数量,不会绘制超出的顶点。下面的数字仅仅是例子。layout (points, max_vertices = 2) out;layout (line_strip, max_vertices = 4) out;layout (triangle_strip, max_vertices = 3) out;// ******************************// 这是前一着色阶段的输出in gl_Vertex{vec4 gl_Position;float gl_PointSize;float gl_ClipDistance[];} gl_in[]; // 数组,一般图元都包含多于1个顶点// ******************************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(); // 将发射的顶点按上面的输出类型,组成相应图元}
简单示例
这里展示一个顶点着色器、几何着色器、片段着色器三者联合使用的例子,绘制指令如下:
//顶点数据:4个顶点,组成三个三角形,画出一个最简单的房子。float vertices_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 // 左下};......while(!glfwWindowShouldClose()){......shader.use();glBindVertexArray( VAO_points );glDrawArrays( GL_POINTS, 0, 4 ); // 简单的绘制4个点。......}......
输出结果如下,虽然绘制指令是绘制4个点,但是最终输出远不止4个顶点,而且还是三角形图元。
顶点着色器代码如下:
#version 330 corelayout (location = 0) in vec2 aPos;layout (location = 1) in vec3 aColor;// 数据传递方式一:以接口块的方式传递数据到下一个着色器阶段(几何着色器)out VS_OUT{vec3 color;} vs_out;// 数据传递方式二:out vec3 color;void main(){vs_out.color = aColor;color = aColor;gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);}
几何着色器代码如下:
#version 330 core// *******************************// 一、从上一个着色器阶段接收的输入数据// *******************************in VS_OUT{vec3 color;} gs_in[]; // 注意都是数组,因为几何着色器接收的是组成一个图元的顶点数据,哪怕只有一个顶点,也是在数组中in vec3 color[];// *******************************// 二、指定接收的输入图元类型// *******************************layout(points) in; // 几何着色器的输入是点图元。// *******************************// 三、指定接收的输入图元类型// *******************************layout(triangle_strip, max_vertices = 5) out; // 几何着色器的输出图元是5个点构成的三角形带(就是一个简单房子形状)// *******************************// 四、指定输出到下以着色器阶段的数据// *******************************out vec3 fColor; // 输出到片段着色器的数据void build_house(vec4 position){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();fColor = vec3(1.0, 1.0, 1.0); // 指定绘制这个顶点时片段颜色gl_Position = position + vec4( 0.0, 0.4, 0.0, 0.0); // 5:顶部EmitVertex();EndPrimitive(); // 根据当前加入的所有顶点,绘制输出类型的图元,这里是一个三角形带。}void main() {//fColor = gs_in[0].color;fColor = color[0];build_house(gl_in[0].gl_Position);}
片段着色器代码如下:
#version 330 corein vec3 fColor;out vec4 FragColor;void main(){FragColor = vec4(fColor, 1.0);}
