用于遮蔽每个面的OpenGL着色器类似于MeshLab的可视化器

时间:2015-12-28 01:26:43

标签: opengl glsl shader

我有非常基本的OpenGL知识,但我正在尝试复制MeshLab的可视化工具所具有的着色效果。

如果在MeshLab中加载网格物体,您将意识到如果一张脸部朝向相机,它会完全亮起,当您旋转模型时,灯光会随着面向相机的脸部发生变化而变化。我在MeshLab中加载了一个带有12个面的简单单位立方体,并捕获了这些截图以明确我的观点:

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

  • 模型稍微旋转(注意面部有点暗): Rotated

  • 更多旋转(注意所有面部现在变暗):
    Rotated

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

我已经有了使用着色器/ VBO绘制网格的代码。我甚至可以分配每顶点颜色。但是,我不知道如何才能达到类似的效果。据我所知,片段着色器处理顶点。快速搜索显示了this之类的问题。但当答案谈到重复顶点时,我感到困惑。

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

the answer by @DietrichEpp

之后的结果

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

顶点着色器:

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

片段着色器:

#version 330 core

in vec4 color;

out vec4 out_frag_color;

void main(void)
{
    out_frag_color = color;
}

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

Result 1

Result 2

2 个答案:

答案 0 :(得分:3)

看起来效果是每面法线的简单照明效果。您可以通过几种不同的方式来实现每个法线:

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

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

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

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

答案 1 :(得分:0)

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

vec3 x = dFdx(FragPos);
vec3 y = dFdy(FragPos);
vec3 normal = cross(x, y);
vec3 norm = normalize(normal);

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

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