【问题标题】:OpenGL shader to shade each face similar to MeshLab's visualizerOpenGL 着色器对每个面进行着色,类似于 MeshLab 的可视化器
【发布时间】:2015-12-28 01:26:43
【问题描述】:

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

如果您在 MeshLab 中加载一个网格,您会发现,如果一个脸面向相机,它会完全被照亮,并且当您旋转模型时,照明会随着面向相机的脸的变化而变化。我在 MeshLab 中加载了一个具有 12 个面的简单单位立方体,并捕获了这些屏幕截图以明确我的观点:

  • 模型加载完毕(注意脸部完全是灰色的):

  • 模型略微旋转(注意脸部如何变暗):

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

在我的脑海中,我认为它的工作方式是它以某种方式在着色器中为每个面分配颜色。如果人脸法线与相机的夹角为零,则人脸是完全照亮的(根据人脸的颜色),否则按法线向量和相机向量的点积成正比照亮。

我已经有了使用着色器/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;
}

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

【问题讨论】:

  • 在相机上放一盏灯不是更容易吗? “片段着色器也适用于顶点”:不,它们适用于fragments
  • @NicolBolas 但这不会需要使用固定函数管道吗?抱歉,我只是不知道在 OpenGL 中有可以作为单独实体使用的照明。想详细说明一下吗?

标签: opengl glsl shader


【解决方案1】:

看起来效果是一个带有每个面法线的简单光照效果。有几种不同的方法可以实现每个面的法线:

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

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

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

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

【讨论】:

  • @DeitrichEpp 因此,如果我对#1 的理解是正确的,我的立方体正面将有 6 个顶点(所有这些顶点的法线都为 (0, 0, 1))。然后在片段着色器中,我会根据每个顶点与相机法线的角度(点积)为每个顶点分配颜色,对吗?
  • @M2X:这基本上是正确的。六个顶点并不是绝对必要的,因为你可以摆脱四个。如果需要,您还可以选择在顶点着色器而不是片段着色器中计算颜色。
  • 谢谢!让我试一试,然后回复你!
  • 您是最棒的!我在问题中包含了最终着色器。
【解决方案2】:

这是简单的平面着色,而不是使用每个顶点法线,您可以使用此 GLSL sn-p 评估每个面法线:

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; 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多