错误的几何着色器可视化法线
Faulty geometry shaders to visualise normals
我的法线可视化出了点问题。
正如您在此 video 中所见,法线有问题并且似乎在移动。
鸭子和球体加载了 .dea 文件(使用 assimp),我自己对立方体进行了硬编码。
这是我的着色器:
顶点着色器:
#version 430
layout(location = 0) in vec3 inPos;
layout(location = 1) in vec3 inNormal;
out vec4 vertex_normal;
void main(void) {
gl_Position = vec4(inPos, 1.0);
vertex_normal = vec4(inNormal, 1.0f);
}
几何着色器:
#version 430
layout(triangles) in;
layout(line_strip, max_vertices = 6) out;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform mat4 normalMatix;
in vec4 vertex_normal[3];
out vec4 outColor;
void main(void)
{
//The "NormalViewProjection" matrix for the normals
mat4 NVP = projectionMatrix * viewMatrix * normalMatix;
//The ModelViewProjection matrix for the vertices
mat4 MVP = projectionMatrix * viewMatrix * modelMatrix;
//Normals transformed to screen space
const vec4 normals[] = {
normalize(NVP * vertex_normal[0]),
normalize(NVP * vertex_normal[0]),
normalize(NVP * vertex_normal[0]),
};
const float normalLength = 1.2f;
//gl_in.length() = 3, since we are working with triangles
for(int i = 0; i < gl_in.length(); i++)
{
outColor = normals[i];
const vec4 position = MVP * gl_in[i].gl_Position;
//First vertex
gl_Position = position;
EmitVertex();
//Second vertex
gl_Position = position + normals[i] * normalLength;
EmitVertex();
//Send the line to the fragment shader
EndPrimitive();
}
}
片段着色器:
#version 430
layout(location = 0) out vec4 fragColor;
in vec4 outColor;
void main(void)
{
fragColor = vec4(outColor.xyz, 1.0f);
}
这里必须区分两种不同类型的向量:
- 描述 3D 位置的位置向量 space。例如顶点,and
- 方向向量,描述的是方向,而不是位置。例如法线就是这样的方向向量。
投影只能为您提供位置向量的正确结果,而不是方向向量。这正是您代码中的问题所在:您将法线(方向)视为位置。
在我看来,正确的代码应该是这样的:
...
for(int i = 0; i < gl_in.length(); i++)
{
const vec4 position = MVP * gl_in[i].gl_Position;
//First vertex
gl_Position = position;
EmitVertex();
//Second vertex
const vec4 position2 = MVP * vec4(gl_in[i].gl_Position.xyz + vertex_normal[i].xyz, 1.0);
gl_Position = position2;
EmitVertex();
}
...
这里先在模型space(gl_in[i].gl_Position.xyz + vertex_normal[i].xyz
)中计算出法线尖端的位置,然后进行投影
编辑:当您在模型矩阵中使用缩放并希望所有法线具有相同的长度时,您可能必须在添加之前将法线和位置转换为世界 space:
mat4 VP = projectionMatrix * viewMatrix;
...
for(int i = 0; i < gl_in.length(); i++)
{
const vec4 position_ws = modelMatrix * gl_in[i].gl_Position;
//First vertex
gl_Position = VP * position_ws;
EmitVertex();
//Second vertex
const vec4 normal_ws = normalize(normalMatrix * vertex_normal[i]);
gl_Position = VP * vec4(position_ws.xyz + normal_ws.xyz, 1.0);
EmitVertex();
}
...
我的法线可视化出了点问题。
正如您在此 video 中所见,法线有问题并且似乎在移动。 鸭子和球体加载了 .dea 文件(使用 assimp),我自己对立方体进行了硬编码。
这是我的着色器:
顶点着色器:
#version 430
layout(location = 0) in vec3 inPos;
layout(location = 1) in vec3 inNormal;
out vec4 vertex_normal;
void main(void) {
gl_Position = vec4(inPos, 1.0);
vertex_normal = vec4(inNormal, 1.0f);
}
几何着色器:
#version 430
layout(triangles) in;
layout(line_strip, max_vertices = 6) out;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
uniform mat4 modelMatrix;
uniform mat4 normalMatix;
in vec4 vertex_normal[3];
out vec4 outColor;
void main(void)
{
//The "NormalViewProjection" matrix for the normals
mat4 NVP = projectionMatrix * viewMatrix * normalMatix;
//The ModelViewProjection matrix for the vertices
mat4 MVP = projectionMatrix * viewMatrix * modelMatrix;
//Normals transformed to screen space
const vec4 normals[] = {
normalize(NVP * vertex_normal[0]),
normalize(NVP * vertex_normal[0]),
normalize(NVP * vertex_normal[0]),
};
const float normalLength = 1.2f;
//gl_in.length() = 3, since we are working with triangles
for(int i = 0; i < gl_in.length(); i++)
{
outColor = normals[i];
const vec4 position = MVP * gl_in[i].gl_Position;
//First vertex
gl_Position = position;
EmitVertex();
//Second vertex
gl_Position = position + normals[i] * normalLength;
EmitVertex();
//Send the line to the fragment shader
EndPrimitive();
}
}
片段着色器:
#version 430
layout(location = 0) out vec4 fragColor;
in vec4 outColor;
void main(void)
{
fragColor = vec4(outColor.xyz, 1.0f);
}
这里必须区分两种不同类型的向量:
- 描述 3D 位置的位置向量 space。例如顶点,and
- 方向向量,描述的是方向,而不是位置。例如法线就是这样的方向向量。
投影只能为您提供位置向量的正确结果,而不是方向向量。这正是您代码中的问题所在:您将法线(方向)视为位置。
在我看来,正确的代码应该是这样的:
...
for(int i = 0; i < gl_in.length(); i++)
{
const vec4 position = MVP * gl_in[i].gl_Position;
//First vertex
gl_Position = position;
EmitVertex();
//Second vertex
const vec4 position2 = MVP * vec4(gl_in[i].gl_Position.xyz + vertex_normal[i].xyz, 1.0);
gl_Position = position2;
EmitVertex();
}
...
这里先在模型space(gl_in[i].gl_Position.xyz + vertex_normal[i].xyz
)中计算出法线尖端的位置,然后进行投影
编辑:当您在模型矩阵中使用缩放并希望所有法线具有相同的长度时,您可能必须在添加之前将法线和位置转换为世界 space:
mat4 VP = projectionMatrix * viewMatrix;
...
for(int i = 0; i < gl_in.length(); i++)
{
const vec4 position_ws = modelMatrix * gl_in[i].gl_Position;
//First vertex
gl_Position = VP * position_ws;
EmitVertex();
//Second vertex
const vec4 normal_ws = normalize(normalMatrix * vertex_normal[i]);
gl_Position = VP * vec4(position_ws.xyz + normal_ws.xyz, 1.0);
EmitVertex();
}
...