有缺陷的几何着色器可视化法线

时间:2015-07-14 08:28:23

标签: opengl 3d glsl normals geometry-shader

对我的法线进行可视化是错误的。

正如你在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();
        }
}

Fragment Shader:

#version 430 
layout(location = 0) out vec4 fragColor;
in vec4 outColor;
void main(void)
{    
    fragColor = vec4(outColor.xyz, 1.0f);
}

我尝试了多个教程。 tutorial1 tutorial2以及其他一些结果。

1 个答案:

答案 0 :(得分:1)

这里必须区分两种不同类型的载体:

  • 位置矢量,描述3D空间中的位置。例如顶点和
  • 方向矢量,描述方向,但不描述位置。例如,法线就是这样的方向向量。

投影仅为您提供位置矢量的正确结果,但不提供方向矢量。这正是代码中存在的问题所在:您将法线(方向)视为位置。

在我看来,正确的代码必须看起来像这样:

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

此处,法线尖端的位置首先在模型空间(gl_in[i].gl_Position.xyz + vertex_normal[i].xyz)中计算,然后进行投影。

编辑:当您在模型矩阵中使用缩放并希望所有法线处于相同的长度时,您可能必须在添加之前将法线和位置转换为世界空间:

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