法向量可视化
概念
-
显示任意物体的法向量。当编写光照着色器时,你可能会最终会得到一些奇怪的视觉输出,但又很难确定导致问题的原因。光照错误很常见的原因就是法向量错误,这可能是由于不正确加载顶点数据、错误地将它们定义为顶点属性或在着色器中不正确地管理所导致的。我们想要的是使用某种方式来检测提供的法向量是正确的。检测法向量是否正确的一个很好的方式就是对它们进行可视化,几何着色器正是实现这一目的非常有用的工具。
思路是这样的:我们首先不使用几何着色器正常绘制场景。然后再次绘制场景,但这次只显示通过几何着色器生成法向量。几何着色器接收一个三角形图元,并沿着法向量生成三条线——每个顶点一个法向量。伪代码看起来会像是这样:
shader.use();
DrawScene();
normalDisplayShader.use();
DrawScene();
这次在几何着色器中,我们会使用模型提供的顶点法线,而不是自己生成,为了适配(观察和模型矩阵的)缩放和旋转,我们在将法线变换到裁剪空间坐标之前,先使用法线矩阵变换一次(几何着色器接受的位置向量是剪裁空间坐标,所以我们应该将法向量变换到相同的空间中)。这可以在顶点着色器中完成:
#version 330 core
layout (location = 0) in vec3 aPos;
layout(location = 1) in vec3 aNormal;
layout (location = 2) in vec2 aTexCoords;
out VS_OUT {
// vec2 texCoords;
vec3 normal;
} vs_out;
//uniform 缓冲对象
layout (std140) uniform Matrices
{
mat4 projection;
};
uniform mat4 view;
uniform mat4 model;
void main()
{
vs_out.normal = mat3(transpose(inverse(model)))*aNormal;
// vs_out.texCoords = aTexCoords;
gl_Position = projection * view * model * vec4(aPos, 1.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; //这里相对于教程加长了
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) * MAGNITUDE;
EmitVertex();
EndPrimitive();
}
void main()
{
GenerateLine(0); // first vertex normal
GenerateLine(1); // second vertex normal
GenerateLine(2); // third vertex normal
}
-
像这样的几何着色器应该很容易理解了。注意我们将法向量乘以了一个MAGNITUDE向量,来限制显示出的法向量大小(否则它们就有点大了)。
因为法线的可视化通常都是用于调试目的,我们可以使用片段着色器,将它们显示为单色的线(如果你愿意也可以是非常好看的线):
#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0, 1.0, 0.0, 1.0);
}
- 效果