一、几何着色器
介绍
几何着色器处于顶点着色器与片元着色器之间。
输入:顶点着色器的输入是一个图元的一组顶点。
输出:在几何着色器中可以对这些顶点进行变换,并且可以输出成不同的图元,甚至产生更多的顶点。
例子
#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();
}
(1)图元类型
在几何着色器顶部需要声明输入和输出的图元类型。并且需要指定需要生成多少个输出点,使用"max_vertices"限定符可以让OpenGL提前预分配内存来存储输出图元数据,并且可以优化内存分配和性能。超过指定数量的顶点将会被丢弃。
可输入的图元类型:
points | 绘制GL_POINTS图元时 |
lines | 绘制GL_LINES或GL_LINE_STRIP时 |
lines_adjacency | GL_LINES_ADJACENCY或GL_LINE_STRIP_ADJACENCY |
triangles | GL_TRIANGLES、GL_TRIANGLE_STRIP或GL_TRIANGLE_FAN |
triangles_adjacency | GL_TRIANGLES_ADJACENCY或GL_TRIANGLE_STRIP_ADJACENCY |
可输出的图元类型:
points |
line_strip |
triangle_strip |
(2)顶点数据
前面提到了几何着色的输入是一组的顶点数据,它并没有在代码中展示出来,因为它通过GLSL的内建变量提供。它被声明成一个接口块,形式如下:
in gl_Vertex
{
vec4 gl_Position;
float gl_PointSize;
float gl_ClipDistance[];
} gl_in[];
gl_in 就是输入的顶点数组。
(3)绘制规则
设定了输入输出的图片,以及输出的顶点个数。并且有了顶点数据之后,我们就可以随心绘制自己想要的图案。例子就是将4个输入为点的图元,绘制成4个输出为线的图元。
EmitVertex:调用时,会将当前顶点的数据添加到几何着色器的输出顶点序列中,比如gl_Position。
EndPrimitive:将生成的图元发送到下一阶段的管线中。多次调用可生成多个图元。
二、 爆破物体
爆破效果的实现,实际就是让每个三角形面片沿着法向量移动一段距离。
一个三角形面片法向量的获取:(注意在其次裁剪空间是左手系)
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));
}
使用sin函数实现爆炸效果的循环:
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);
}
完整的几何着色器:
#version 330 core
layout (triangles) in;
layout (triangle_strip, max_vertices = 3) out;
in VS_OUT {
vec2 texCoords;
} gs_in[];
out vec2 TexCoords;
uniform float time;
vec4 explode(vec4 position, vec3 normal) { ... }
vec3 GetNormal() { ... }
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();
}
三、法向量可视化
就是在几何着色器中,将输出输入的三角形图元,输出成三个直线图元,将顶点的法向量可视化。
顶点着色器:
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
out VS_OUT {
vec3 normal;
} vs_out;
uniform mat4 view;
uniform mat4 model;
void main()
{
gl_Position = view * model * vec4(aPos, 1.0);
mat3 normalMatrix = mat3(transpose(inverse(view * model)));
vs_out.normal = normalize(vec3(vec4(normalMatrix * aNormal, 0.0)));
}
几何着色器:
#version 330 core
layout (triangles) in;
layout (line_strip, max_vertices = 6) out;
in VS_OUT {
vec3 normal;
} gs_in[];
const float MAGNITUDE = 0.4;
uniform mat4 projection;
void GenerateLine(int index)
{
gl_Position = projection * gl_in[index].gl_Position;
EmitVertex();
gl_Position = projection * (gl_in[index].gl_Position +
vec4(gs_in[index].normal, 0.0) * MAGNITUDE);
EmitVertex();
EndPrimitive();
}
void main()
{
GenerateLine(0); // 第一个顶点法线
GenerateLine(1); // 第二个顶点法线
GenerateLine(2); // 第三个顶点法线
}
片元着色器:
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}