太阳光,即平行光,我们假设太阳光的位置离我们无限远,但是它的光照方向对于每个顶点都是相同的。
//方向光着色器代码
struct DirLight{
vec3 direction;
vec3 ambient;
vec3 diffuse;
vec3 specular;
};
vec3 CalcDirLight(DirLight light, vec3 normal, vec3 viewDir)
{
vec3 lightDir = normalize(-light.direction);//平行光的光照方向取反 就是光源到片元的方向
float diff = max(dot(normal, lightDir), 0.0);//漫反射因子
vec3 reflectDir = reflect(-lightDir, normal);//通过光的方向和法线计算出反射光方向
float spec = pow(max(dot(reflectDir, viewDir), 0.0), material.shininess);//镜面光因子
vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;
vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;
vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;
return (ambient + diffuse + specular);
}
点光源,如火把、灯泡等,点光源的位置是固定的,光照方向对于每个顶点来说,都需要计算得出,点光源最重要的一点是,随着与点光源距离的增加,光的强度存在衰减。
//点光源着色器代码
struct PointLight {
vec3 position;
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;
float linear;
float quadratic;
};
vec3 CalcPointLight(PointLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
//漫反射因子
//先得到从片元指向光源的方向向量
vec3 lightDir = normalize(light.position - fragPos);
float diff = max(dot(lightDir, normal), 0.0);
//镜面光因子
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(reflectDir, viewDir), 0.0), material.shininess);
//点光源要计算衰减
float distance = length(light.position - fragPos);//计算出片元与光源之间的距离
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
//合并
vec3 ambient = light.ambient * texture(material.diffuse, TexCoords).rgb;
vec3 diffuse = light.diffuse * diff * texture(material.diffuse, TexCoords).rgb;
vec3 specular = light.specular * spec * texture(material.specular, TexCoords).rgb;
ambient *= attenuation;
diffuse *= attenuation;
specular *= attenuation;
return (ambient + diffuse + specular);
}
聚光灯,如手电筒,我们经常在恐怖游戏中使用。聚光灯最重要的是存在内圆锥和外圆锥,外圆锥之外的物体不会被聚光灯照亮,其次聚光灯边缘需要进行软化处理。
//聚光灯着色器代码
struct SpotLight {
vec3 position;
vec3 direction;
float cutOff;//聚光灯内圆锥余弦值
float outerCutOff;//聚光灯外圆锥余弦值
vec3 ambient;
vec3 diffuse;
vec3 specular;
float constant;
float linear;
float quadratic;
};
vec3 CalcSpotLight(SpotLight light, vec3 normal, vec3 fragPos, vec3 viewDir)
{
vec3 lightDir = normalize(light.position - fragPos);
// diffuse shading
float diff = max(dot(normal, lightDir), 0.0);
// specular shading
vec3 reflectDir = reflect(-lightDir, normal);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
// attenuation
float distance = length(light.position - fragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance + light.quadratic * (distance * distance));
// spotlight intensity
float theta = dot(lightDir, normalize(-light.direction));
float epsilon = light.cutOff - light.outerCutOff;
float intensity = clamp((theta - light.outerCutOff) / epsilon, 0.0, 1.0);
// combine results
vec3 ambient = light.ambient * vec3(texture(material.diffuse, TexCoords));
vec3 diffuse = light.diffuse * diff * vec3(texture(material.diffuse, TexCoords));
vec3 specular = light.specular * spec * vec3(texture(material.specular, TexCoords));
ambient *= attenuation * intensity;
diffuse *= attenuation * intensity;
specular *= attenuation * intensity;
return (ambient + diffuse + specular);
}
我们需要在cpu程序中给着色器的光进行赋值
//这是在一个渲染帧中 使用一个着色器程序对象 设置好他的着色器参数 进行渲染物体的代码
objShader.use();
objShader.setVec3("viewPos", myCamera.Position);//观察者位置
//给光结构体赋值
//平行光
objShader.setVec3("dirLight.direction", glm::vec3(-1.0f));//聚光灯方向
objShader.setVec3("dirLight.ambient", glm::vec3(0.1f));//环境光
objShader.setVec3("dirLight.diffuse", glm::vec3(0.8f));//漫反射光照
objShader.setVec3("dirLight.specular", glm::vec3(1.0f));//镜面光
//点光源
objShader.setVec3("pointLights[0].position", pointLightPositions[0]);
objShader.setVec3("pointLights[0].ambient", glm::vec3(0.1f));//环境光
objShader.setVec3("pointLights[0].diffuse", glm::vec3(0.8f));//漫反射光照
objShader.setVec3("pointLights[0].specular", glm::vec3(1.0f));//镜面光
objShader.setFloat("pointLights[0].constant", 1.0f);
objShader.setFloat("pointLights[0].linear", 0.09f);
objShader.setFloat("pointLights[0].quadratic", 0.032f);
objShader.setVec3("pointLights[1].position", pointLightPositions[1]);
objShader.setVec3("pointLights[1].ambient", glm::vec3(0.1f));//环境光
objShader.setVec3("pointLights[1].diffuse", glm::vec3(0.8f));//漫反射光照
objShader.setVec3("pointLights[1].specular", glm::vec3(1.0f));//镜面光
objShader.setFloat("pointLights[1].constant", 1.0f);
objShader.setFloat("pointLights[1].linear", 0.09f);
objShader.setFloat("pointLights[1].quadratic", 0.032f);
objShader.setVec3("pointLights[2].position", pointLightPositions[2]);
objShader.setVec3("pointLights[2].ambient", glm::vec3(0.1f));//环境光
objShader.setVec3("pointLights[2].diffuse", glm::vec3(0.8f));//漫反射光照
objShader.setVec3("pointLights[2].specular", glm::vec3(1.0f));//镜面光
objShader.setFloat("pointLights[2].constant", 1.0f);
objShader.setFloat("pointLights[2].linear", 0.09f);
objShader.setFloat("pointLights[2].quadratic", 0.032f);
objShader.setVec3("pointLights[3].position", pointLightPositions[3]);
objShader.setVec3("pointLights[3].ambient", glm::vec3(0.1f));//环境光
objShader.setVec3("pointLights[3].diffuse", glm::vec3(0.8f));//漫反射光照
objShader.setVec3("pointLights[3].specular", glm::vec3(1.0f));//镜面光
objShader.setFloat("pointLights[3].constant", 1.0f);
objShader.setFloat("pointLights[3].linear", 0.09f);
objShader.setFloat("pointLights[3].quadratic", 0.032f);
//聚光灯
objShader.setVec3("spotLight.position", myCamera.Position);//聚光灯光源位置
objShader.setVec3("spotLight.direction", myCamera.Front);//聚光灯方向
objShader.setFloat("spotLight.cutOff", glm::cos(glm::radians(12.5f)));//聚光灯内圆锥余弦值
objShader.setFloat("spotLight.outerCutOff", glm::cos(glm::radians(17.5f)));//聚光灯内圆锥余弦值
objShader.setVec3("spotLight.ambient", glm::vec3(0.1f));//环境光
objShader.setVec3("spotLight.diffuse", glm::vec3(0.8f));//漫反射光照
objShader.setVec3("spotLight.specular", glm::vec3(1.0f));//镜面光
objShader.setFloat("spotLight.constant", 1.0f);
objShader.setFloat("spotLight.linear", 0.09f);
objShader.setFloat("spotLight.quadratic", 0.032f);
//给材质结构体赋值
objShader.setFloat("material.shininess", 32.0f);
//每帧设置观察矩阵 每一帧因为我们用户的输入 会导致摄像机位置、角度发生变化 所以每帧都要重新生成LookAt矩阵
glm::mat4 view = myCamera.GetViewMatrix();//位置 目标 上向量
objShader.setMatrix4("view", view);
//每帧设置透视投影矩阵
glm::mat4 projection = glm::perspective(glm::radians(myCamera.Fov), 800.0f / 600.0f, 0.1f, 100.0f);
objShader.setMatrix4("projection", projection);
glBindVertexArray(cubeVAO);//绑定顶点数组对象
glm::mat4 model = glm::mat4(1.0f);
for (unsigned int i = 0; i < 10; i++)
{
model = glm::mat4(1.0f);
model = glm::translate(model, cubePositions[i]);
float angle = 20.0f * i;
model = glm::rotate(model, glm::radians(angle), glm::vec3(1.0f, 0.3f, 0.5f));
objShader.setMatrix4("model", model);
glDrawArrays(GL_TRIANGLES, 0, 36);
}