目录
一、前言
二、物体材质
三、光源材质
一、前言
OpenGL材质是模拟现实世界中不同材质物体表面,如木制箱子和钢制箱子对光的反射程度不同。物体材质对接受光散射程度不同,较少散射产生较小高光点,较多散射则会产生较大高光点。前面章节定义了物体颜色、环境光照、漫反射、镜面反射,本文再添加一个反光度分量,则可以表达材质所有属性。
模拟现实世界物体表面材质,会使得渲染图形接收光照后更加逼真,物体材质的所有属性分量包括环境光照ambient、漫反射光照Diffuse、镜面光照Specular Lighting、反射度Shining。
- ambient材质向量定义在环境光照下这个表面反射的是什么颜色,通常与表面的颜色相同
- diffuse材质向量定义在漫反射光照下表面的颜色。漫反射颜色(和环境光照一样)也被设置为我们期望的物体颜色
- specular材质向量设置的是表面上镜面高光的颜色(或者甚至可能反映一个特定表面的颜色)
- shininess影响镜面高光的散射/半径
二、物体材质
#version 330 core
struct Material{
vec3 ambient;
vec3 diffuse;
vec3 specular;
float shininess;
};
out vec4 FragColor;
in vec3 Normal; //法向量:垂直于顶点表面的向量
in vec3 FragPos; //片段位置向量:世界坐标系下
uniform vec3 lightPos; //光源位置向量
uniform vec3 viewPos; //观察者位置向量
uniform vec3 lightColor;
uniform Material material;
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);
// 镜面反射 + 反光强度Shininess(镜面高光散射半径)
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);
}
ObjShader.setVec3("material.ambient", 1.0f, 0.5f, 0.31f);
ObjShader.setVec3("material.diffuse", 1.0f, 0.5f, 0.31f);
ObjShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f);
ObjShader.setFloat("material.shininess", 32.0f);
三、光源材质
上述光源反射太亮了,原因是环境光、漫反射、镜面光对物体全力反射。, 光源对这三种分量有不同的强度,设置光源的“材质”来限制这三个分量的强度。在着色器中进一步增加光源材质结构体:
......
struct Light{
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
......
uniform Light light;
void main()
{
// 环境光照
vec3 ambient =light.ambient * material.ambient;
// 漫反射
......
vec3 diffuse = light.diffuse*(diff * material.diffuse);
// 镜面反射 + 反光强度Shininess(镜面高光散射半径)
......
vec3 specular = light.specular*(spec * material.specular);
vec3 result = ambient + diffuse + specular;
FragColor = vec4(result, 1.0);
}
app
ObjShader.setVec3("light.ambient", 0.2f, 0.2f, 0.2f);
ObjShader.setVec3("light.diffuse", 0.5f, 0.5f, 0.5f); // 将光照调暗了一些以搭配场景
ObjShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f);
变化的颜色:
利用sin和glfwGetTime函数改变光源的环境光和漫反射颜色,从而很容易地让光源的颜色随着时间变化。
glm::vec3 lightColor;
lightColor.x = sin(glfwGetTime() * 2.0f);
lightColor.y = sin(glfwGetTime() * 0.7f);
lightColor.z = sin(glfwGetTime() * 1.3f);
glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f); // 降低影响
glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f); // 很低的影响
lightingShader.setVec3("light.ambient", ambientColor);
lightingShader.setVec3("light.diffuse", diffuseColor);
参考:
材质 - LearnOpenGL CN (learnopengl-cn.github.io)