我有非常基本的OpenGL知识,但我正在尝试复制MeshLab的可视化工具所具有的着色效果。
如果在MeshLab中加载网格物体,您将意识到如果一张脸部朝向相机,它会完全亮起,当您旋转模型时,灯光会随着面向相机的脸部发生变化而变化。我在MeshLab中加载了一个带有12个面的简单单位立方体,并捕获了这些截图以明确我的观点:
在我的头顶,我认为它的工作方式是它以某种方式在着色器中为每个面分配颜色。如果面法线和相机之间的角度为零,则面部会完全亮起(根据面部的颜色),否则它会与法线矢量和相机矢量之间的点积成比例。
我已经有了使用着色器/ VBO绘制网格的代码。我甚至可以分配每顶点颜色。但是,我不知道如何才能达到类似的效果。据我所知,片段着色器处理顶点。快速搜索显示了this之类的问题。但当答案谈到重复顶点时,我感到困惑。
如果它有所不同,在我的应用程序中我加载*.ply
文件,其中包含顶点位置,三角形索引和每顶点颜色。
我创建了重复的顶点数组,并使用以下着色器来实现所需的光照效果。从发布的截图中可以看出,相似性是不可思议的:)
#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;
}
答案 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;