简述
几何着色器可以多次调用EmitVertex()输出多种数量的图元,它产生的输出图元比输入的图元更多,这种方法叫扩充。使用这种方法可以显示任意物体顶点的法线向量。首先需要创建两个着色器程序,一个不适应几何着色器正常绘制物体,另一个通过几何着色器生成法线向量,然后输出直线(法线向量)。
顶点着色器
在顶点着色器中可以得到模型每个顶点的法线向量,为了适配模型缩放和旋转,我们在将法线变换到裁剪空间坐标之前,先使用法线矩阵变换一次。
mat3 normalMatrix = mat3(transpose(inverse(view * model)));
vs_out.normal = normalize(vec3(projection * vec4(normalMatrix * aNormal, 1.0)));
几何着色器
设置输入类型为triangles类型,所以每次输入一个三角形,即三个顶点。输出类型设置为line_strip类型,每个顶点都自己的需要显示法线向量,所以输出点为6。从内置变量gl_in获得输入点的个数。
for(i = 0; i < gl_in.length(); i++)
{
gl_Position = gl_in[i].gl_Position;
EmitVertex();
gl_Position = gl_in[i].gl_Position + vec4(gs_in[i].normal, 0.0) * 10;
EmitVertex();
EndPrimitive();
}
应用程序
在程序中,绘制完正常的模型后还需要绘制法线向量。
//--------基本模型绘制-------
//激活基本着色器
shader.use();
//模型矩阵变换
.....
//绘制模型
draw();
//--------法线向量绘制-------
//激活输出法线向量的着色器
shader.use();
//模型矩阵变换
.....
//绘制法线向量
draw();
着色器源码
geometry_shader.vs
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aNormal;
out VS_OUT {
vec3 normal;
} vs_out;
uniform mat4 projection;
uniform mat4 view;
uniform mat4 model;
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
mat3 normalMatrix = mat3(transpose(inverse(view * model)));
vs_out.normal = normalize(vec3(projection * vec4(normalMatrix * aNormal, 1.0)));
}
geometry_shader.gs
#version 330 core
layout (triangles) in;
layout (line_strip, max_vertices = 6) out;
in VS_OUT {
vec3 normal;
} gs_in[];
void main()
{
int i;
for(i = 0; i < gl_in.length(); i++)
{
gl_Position = gl_in[i].gl_Position;
EmitVertex();
gl_Position = gl_in[i].gl_Position + vec4(gs_in[i].normal, 0.0) * 10;
EmitVertex();
EndPrimitive();
}
}
geometry_shader.fs
#version 330 core
out vec4 FragColor;
in vec2 TexCoords;
uniform sampler2D texture_diffuse1;
void main()
{
FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}