材质
在现实世界里,每个物体会对光产生不同的反应。比如,钢制物体看起来通常会比陶土花瓶更闪闪发光,一个木头箱子也不会与一个钢制箱子反射同样程度的光。有些物体反射光的时候不会有太多的散射(Scatter),因而产生较小的高光点,而有些物体则会散射很多,产生一个有着更大半径的高光点。要模拟真实的场景,需要针对每种表面定义不同的材质(Material)属性。
上一节中,定义了一个物体和光的颜色,并结合环境光与镜面强度分量,来决定物体的视觉输出,当描述一个表面时,我们可以分别为三个光照分量定义一个材质颜色(Material Color):环境光照(Ambient Lighting)、漫反射光照(Diffuse Lighting)和镜面光照(Specular Lighting),
现在,再添加一个反光度(Shininess)分量,结合上述的三个颜色
#version 330 core
struct Material {
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
uniform Material material;
也可以把它们储存为独立的uniform值,但是作为一个结构体来储存会更有条理一些,这里为风氏光照模型的每个分量都定义一个颜色向量。ambient材质向量定义了在环境光照下这个表面反射的是什么颜色,通常与表面的颜色相同。diffuse材质向量定义了在漫反射光照下表面的颜色。漫反射颜色(和环境光照一样)也被设置为我们期望的物体颜色。specular材质向量设置的是表面上镜面高光的颜色(或者甚至可能反映一个特定表面的颜色)。最后,shininess影响镜面高光的散射/半径。
设置材质
现在有了材质,根据材质的颜色来计算最终的输出颜色
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;
FragColor = vec4(result, 1.0);
}
并设置uniform后
// 材质
//m_CubeShader->SetUniformVec3("material.ambient", m_Material.ambient); //环境光
m_CubeShader->SetUniform1i("material.diffuse", m_Material.diffuse); //漫反射贴图
//m_CubeShader->SetUniformVec3("material.specular", m_Material.specular); //镜面光
m_CubeShader->SetUniform1i("material.specular", m_Material.specular); //镜面光贴图
m_CubeShader->SetUniform1f("material.shininess", m_Material.shininess); //反光度
得到了一个特别亮的物体,这是因为环境光、漫反射和镜面光这三个颜色对任何一个光源都全力反射。光源对环境光、漫反射和镜面光分量也分别具有不同的强度 ,前面的章节中,通过使用一个强度值改变环境光和镜面光强度的方式解决了这个问题,就像:
vec3 ambient = vec3(1.0) * material.ambient;
vec3 diffuse = vec3(1.0) * (diff * material.diffuse);
vec3 specular = vec3(1.0) * (spec * material.specular);
所以物体的每个材质属性对每一个光照分量都返回了最大的强度。对单个光源来说,这些vec3(1.0)值同样可以对每种光源分别改变,通常只是这样既可,现在,物体的环境光分量完全地影响了立方体的颜色,可是环境光分量实际上不应该对最终的颜色有这么大的影响,所以可以将光源的环境光强度设置为一个小一点的值,从而限制环境光颜色,或者说直接创建光源的三个分量的强度向量:
//光照属性
struct Light{
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
一个光源对它的ambient、diffuse和specular光照分量有着不同的强度。
这里的Light的a d s指的是光源的环境光强度,漫反射光强度,镜面反射强度,而本节中的指的是材质的环境光反射颜色,漫反射颜色,镜面光反射颜色。
关于材质的理解 材质就是对光的反射特性
比如说:在阳光下,树叶是绿色的,并不是树叶发出了绿色的光,而是树叶吸收了其他颜色的光,反射绿色的光。 剥离掉树叶这种物质,提取出树叶对光“处理”的特性,这就叫树叶材质。
一般我们使用 漫反射光、镜面反射光、光泽度等属性,来定义一种材质,其实我不喜欢这样的称呼,我更喜欢称作 漫反射率, 镜面反射率。
比如树叶的漫反射率(0.54, 0.89, 0.63), 可以这么理解, 树叶可以反射光照中: 54%的红色光,89%的绿色光,63%的蓝色光, 树叶可以吸收光照中: 1-54%的红色光,1-89%的绿色光,1-63%的蓝色光
[材质 - LearnOpenGL CN](learnopengl-cn.github.io/02 Lighting/03 Materials/)