关于glsl:类似于MeshLab的可视化器的OpenGL着色器可为每个面着色

OpenGL shader to shade each face similar to MeshLab's visualizer

我具有非常基础的OpenGL知识,但是我正在尝试复制MeshLab可视化器具有的阴影效果。

如果在MeshLab中加载网格,您将意识到,如果一个面向相机的面完全发光,并且在旋转模型时,光照会随着面向相机的面的变化而变化。我在MeshLab中加载了一个带有12个面的简单单位立方体,并捕获了以下屏幕截图,以使我的观点清晰明了:

  • 加载了模型(注意面部如何完全变灰):
    Loaded up

  • 略微旋转模型(注意面部变暗):
    Rotated

  • 旋转更多(注意现在所有面孔都变黑了):
    Rotated

在我的头上,我认为它的工作方式是通过某种方式在着色器中为每个面分配颜色。如果脸部法线与摄影机之间的角度为零,则脸部将完全照亮(根据脸部的颜色),否则,照亮与法向矢量和照相机矢量之间的点积成比例。

我已经有了使用着色器/ VBO绘制网格的代码。我什至可以分配每个顶点的颜色。但是,我不知道如何实现类似的效果。据我所知,片段着色器可以在顶点上工作。快速搜索发现了这样的问题。但是,当答案涉及重复顶点时,我感到困惑。

如果有什么不同,在我的应用程序中,我加载*.ply文件,其中包含顶点位置,三角形索引和每个顶点的颜色。

@DietrichEpp回答后的结果

我创建了重复的顶点数组,并使用以下着色器实现了所需的照明效果。从发布的屏幕截图中可以看出,相似之处是不可思议的:)

顶点着色器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#version 330 core

uniform mat4 projection_matrix;
uniform mat4 model_matrix;
uniform mat4 view_matrix;

in vec3 in_position;    // The vertex position
in vec3 in_normal;      // The computed vertex normal
in vec4 in_color;       // The vertex color

out vec4 color;     // The vertex color (pass-through)

void main(void)
{
    gl_Position = projection_matrix * view_matrix * model_matrix * vec4(in_position, 1);

    // Compute the vertex's normal in camera space
    vec3 normal_cameraspace = normalize(( view_matrix * model_matrix * vec4(in_normal,0)).xyz);
    // Vector from the vertex (in camera space) to the camera (which is at the origin)
    vec3 cameraVector = normalize(vec3(0, 0, 0) - (view_matrix * model_matrix * vec4(in_position, 1)).xyz);

    // Compute the angle between the two vectors
    float cosTheta = clamp( dot( normal_cameraspace, cameraVector ), 0,1 );

    // The coefficient will create a nice looking shining effect.
    // Also, we shouldn't modify the alpha channel value.
    color = vec4(0.3 * in_color.rgb + cosTheta * in_color.rgb, in_color.a);
}

片段着色器:

1
2
3
4
5
6
7
8
9
10
#version 330 core

in vec4 color;

out vec4 out_frag_color;

void main(void)
{
    out_frag_color = color;
}

不可思议的结果与单位立方体:

Result 1

Result 2


看起来该效果是具有按面法线的简单照明效果。有几种不同的方法可以实现按面法线:

  • 您可以创建一个具有法线属性的VBO,然后为法线不相同的面复制顶点位置数据。例如,一个立方体将具有24个顶点而不是8个顶点,因为"重复项"将具有不同的法线。

  • 您可以使用几何着色器来计算每面法线。

  • 您可以在片段着色器中使用dFdx()dFdy()来近似法线。

我推荐第一种方法,因为它很简单。您可以在程序中提前预先计算法线,然后使用它们来计算顶点着色器中的面部颜色。


这是简单的平面着色,您可以使用此GLSL代码段来评估每个面法线,而不必使用每个顶点法线:

1
2
3
4
vec3 x = dFdx(FragPos);
vec3 y = dFdy(FragPos);
vec3 normal = cross(x, y);
vec3 norm = normalize(normal);

然后使用norm施加一些漫射照明:

1
2
3
4
// diffuse light 1
vec3 lightDir1 = normalize(lightPos1 - FragPos);
float diff1 = max(dot(norm, lightDir1), 0.0);
vec3 diffuse = diff1 * diffColor1;