错误的几何着色器可视化法线

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);
}

我试过多个教程。 tutorial1 tutorial2 还有一些没有结果。

这里必须区分两种不同类型的向量:

  • 描述 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();
}
...