写在前面
这一节隔了好久了,今天终于有时间写完。上一节光照基础学习实现了Phong reflection model,但是还存在不足,本节使用材质属性,以及使用diffuse map和specular map改善上一节的实现。本节示例程序均可以在我的github下载。
本节内容整理自:
1.www.learnopengl.com Materials
2.www.learnopengl.com Lighting maps
通过本节可以了解到
使用材质属性使不同物体对光有不同反映
对光源的不同部分使用不同的强度
使用diffuse map和specular map使物体不同部分对光有不同反映
材质属性-不同物体对光有不同反映
现实世界中,不同的物体对光有不同的反映,例如钢做成的物体通常比土制的花瓶看起来更亮,木质的容器和钢做成的容器对光的反应也不一样。对于镜面反射光,不同的物体接受光照后,高光部分的半径大小也不一样。要模拟不同的物体接受光照后的效果,就需要考虑物体的材质属性,利用材质属性模拟出不同的效果。
上一节我们使用了环境光(ambient),漫反射光(diffuse),镜面反射光(specular)三种成分实现的Phong reflection mode。为物体指定材质属性时,也可以为物体指定这三个不同成分的光的强度作为材质属性,同时加上高光系数shininess,整个材质在片元着色器中定义为如下所示的结构体:
// 材质属性结构体
struct MaterialAttr
{
vec3 ambient; // 环境光
vec3 diffuse; // 漫反射光
vec3 specular; // 镜面光
float shininess; //镜面高光系数
};
利用上述4个属性来定义物体的材质,我们可以模拟出很多现实世界的物体,如何配出具有真实效果的物体光照效果需要丰富的经验,同时也要使用更复杂的模型,后面我们会学习如何加载模型。通过加载丰富的模型,配上光照后,将会更接近现实。
利用上面的材质,我们实现Phone reflection model的片元着色器代码变为:
void main()
{
// 环境光成分
vec3 ambient = lightColor * material.ambient;
// 漫反射光成分
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = lightColor * (diff * material.diffuse);
// 镜面光成分
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir,
reflectDir), 0.0), material.shininess);
vec3 specular = lightColor * (spec * material.specular);
vec3 result = ambient + diffuse + specular;
color = vec4(result, 1.0f);
}
在主程序中设置材质结构体的每个属性,使用结构体变量的分量来设置。例如定义材质结构体变量为: