[OpenGL入门教程] 11. 材质与光照贴图

材质

不同的物体对光的反射效果也不同,这里用材质来描述这种性质。

struct Material {
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
    float shininess;
}; 

材质的定义是与光照模型的定义相对应的,按照之前使用的冯氏光照模型,物体颜色的组成主要有四个部分:环境光照、漫反射光照,镜面光照以及反光度。根据上述规则可以定义出对应该模型的材质的结构体。

实际实践中,环境光照一般都取与反射光照相同的颜色,因此可以不用添加,如果你希望的话,也可以保留。而为了更加精细的对物体的每个片段单独设置颜色,可以使用漫反射纹理贴图与镜面反射纹理贴图来进行控制,替代直接使用分量全局执行。

镜面反射纹理贴图是一个专门用于镜面高光的纹理贴图。它是一个黑白的(如果你想得话也可以是彩色的)纹理,来定义物体每部分的镜面光强度。在镜面反射纹理贴图中,一个像素越「白」,物体的镜面光分量就会越亮。如图所示是一个镜面反射纹理贴图:

使用Photoshop或Gimp之类的工具,将漫反射纹理转换为镜面光纹理还是比较容易的,只需要剪切掉一些部分,将图像转换为黑白的,并增加亮度/对比度就好了。

因此,进一步可以将材料结构体定义如下:

struct Material {
    sampler2D diffuse;
    sampler2D specular;
    float shininess;
}; 
in vec2 TexCoords;
uniform Material material;

这里使用纹理的方式与之前基本完全相同。而由于这里还需要纹理坐标,因此和之前的类似,还需要传入纹理坐标。

接着,从CPU程序中通过uniform将材质传入。注意,从外面传结构体时,需要对结构体的每个变量单独传值。具体实现如下:

shader.SetUniform1i("material.specular", 1);
shader.SetUniform1f("material.shininess", 25.0f);
shader.SetUniform1i("material.diffuse", 0);

光源

影响物体表现的除了物体本身,当然还有光源的情况。同样的,对应的光源属性也有四个,用于控制这四种光照对物体的影响。

struct Light {
    vec3 position;
    vec3 ambient;
    vec3 diffuse;
    vec3 specular;
};

uniform Light light;

这里将其定义为向量形式即可,因为这里光源本身可以视作是一个整体。

同样,将对应值通过uniform传入即可。

那么,根据上面定义好的物理材质和光源属性,就可以得到对应的光照情况下的物体了。基本上就是在之前的光照模型的基础上稍加改动,将固定值改为了传入的材料和光源属性。

void main()
{
    vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));

    vec3 norm = normalize(Normal);
    vec3 lightDir = normalize(LightPos - FragPos);

    float diff = max(dot(norm, lightDir), 0.0);
    vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));

    vec3 viewDir = normalize(-FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
    vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));

    vec3 result = ambient + diffuse + specular;
    FragColor = vec4(result, 1.0);
}

加入了上述结构后,可以使得程序显示出一个更加真实的光照情况。最终效果如下:

参考资料

[1] https://learnopengl-cn.readthedocs.io/zh/latest/01%20Getting%20started/03%20Hello%20Window/