一般我們只使用了頂點和片段着色器,這也是基本和必須的兩個着色器,而幾何着色器是一個可選的着色器,其位於頂點和片段着色器之間。
幾何着色器接收來自頂點着色器的一個片元的一組頂點,然后可以對其進行變換,可以輸出新的不同類型的片元,也可以增加頂點數,其功能非常強大。
一般寫法如下:
#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(); }
可以看到首先定義了輸入和輸出布局修飾符。
輸入修飾符:
layout (points) 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)
輸出修飾符:
layout (line_strip, max_vertices = 2) out;
max_vertices=2 表示:對應頂點着色器輸出的每個片元,幾何着色器每次處理的最大頂點數量,超出的頂點就不再處理了。
可供選擇的輸出修飾符有:
points
line_strip
triangle_strip
效果展示:
1、輸入片元為points,渲染“房子”
#version 430 core layout (points) in; layout (triangle_strip, max_vertices=5) out; in VS_OUT{ vec3 color; }gs_in[]; out vec3 fColor; void build_Quad(vec4 p){ fColor=gs_in[0].color; gl_Position=p+vec4(-0.2,-0.2, 0, 0); EmitVertex(); gl_Position=p+vec4( 0.2,-0.2, 0, 0); EmitVertex(); gl_Position=p+vec4(-0.2, 0.2, 0, 0); EmitVertex(); gl_Position=p+vec4( 0.2, 0.2, 0, 0); EmitVertex(); gl_Position=p+vec4( 0.0, 0.4, 0, 0); fColor=vec3(1.0,1.0,1.0); EmitVertex(); EndPrimitive(); } void main(){ build_Quad(gl_in[0].gl_Position); }
2、nanosuit模型爆炸效果
#version 430 core layout (triangles) in; layout (triangle_strip, max_vertices = 3) out; in VS_OUT{ vec3 FragPos; vec2 TexCoords; vec3 Normal; }gs_in[]; out vec2 TexCoords; uniform float time; vec3 GetNormal(){ vec3 a=vec3(gl_in[0].gl_Position) - vec3(gl_in[1].gl_Position); vec3 b=vec3(gl_in[2].gl_Position) - vec3(gl_in[1].gl_Position); return normalize(cross(a,b)); } vec4 explode(vec4 position, vec3 normal){ float magnitude=2.0; vec3 direction=normal*((sin(time)+1.0)/2.0)*magnitude; return position+vec4(direction,0.0); } void main(){ vec3 normal = GetNormal(); gl_Position=explode(gl_in[0].gl_Position,normal); TexCoords=gs_in[0].TexCoords; EmitVertex(); gl_Position=explode(gl_in[1].gl_Position,normal); TexCoords=gs_in[1].TexCoords; EmitVertex(); gl_Position=explode(gl_in[2].gl_Position,normal); TexCoords=gs_in[2].TexCoords; EmitVertex(); EndPrimitive(); }
3、nanosuit模型的法線可視化
#version 430 core layout (triangles) in; layout (line_strip, max_vertices = 6) out; in VS_OUT{ vec3 FragPos; vec2 TexCoords; vec3 Normal; }gs_in[]; void GenerateLine(int index){ gl_Position=gl_in[index].gl_Position; EmitVertex(); gl_Position=gl_in[index].gl_Position + vec4(gs_in[index].Normal,0.0) * 0.4; EmitVertex(); EndPrimitive(); } void main(){ GenerateLine(0); GenerateLine(1); GenerateLine(2); }