OpenGL Lighting
文章目录
- OpenGL Lighting
- 一、 冯氏光照模型(Phong Lighting Model)
- 环境光(Ambient lighting)
- 漫反射光照(Diffuse lighting)
- 漫反射光照(Specular Lighting)
- 二、 材质(Materials)
- 光照贴图(Lighting maps)
- 漫反射贴图和镜面光贴图
- 法线贴图/位移贴图/反射贴图
- 三、投光物(Light casters)
- 平行光(Direct Light)
- 点光源 (Point Light)
- 聚光等(Spot Light)
- 四、多光源(Multiple lights)
一、 冯氏光照模型(Phong Lighting Model)
Phong模型由三种反射光组成,分别是环境光、漫反射光、镜面反射光。
环境光(Ambient lighting)
简单来说就是不可能黑暗的很纯粹,在减少资源开销的情况下,我们使用一个简单的很小的常量环境因子乘以光照颜色。
void main()
{
float ambientStrength = 0.1;
vec3 ambient = ambientStrength * lightColor;
vec3 result = ambient * objectColor;
FragColor = vec4(result, 1.0);
}
- 代码中可以看到就是在片元着色器中使用 常量环境因子 * 光照 * 物体颜色 来当做环境光
漫反射光照(Diffuse lighting)
简而言之就是,物体表面不同的点,反射的光强并不一定是一样的。在Phong模型里,光线的入射角和该点的法线越近光强越强。
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(light.position - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
- 点积和叉积的常用作用
- 点积:求两向量夹角(接近程度);投影
- 叉积:判断两个向量的做优;判断一个点是否在里在外;通过两个向量确定一个坐标系
入射方向是光源指向片元,而不是片元指向光源
点乘是两个向量的长度与它们夹角余弦的积,所以dot参数顺序不影响
漫反射光照(Specular Lighting)
同上,反射后的光强随着观察者的观察角度而变化
观察者的观察角度和反射向量越近则光强越强
vec3 viewDir = normalize(viewPos - FragPos);
vec3 reflectDir = reflect(-lightDir, norm);
float spec = pow(max(dot(viewDir, reflectDir), 0.0), material.shininess);
vec3 specular = light.specular * (spec * material.specular);
- 注意reflect的取反,reflect函数是利用点积来实现的
- 32次幂,次数越高,光斑越小越集中
二、 材质(Materials)
长话短说,就是物体的自身属性会对光产生不同的反应。
- ambient(环境光)
- diffuse(漫反射)
- specular(高光)
- shininess(反光度)
主要开始在shader用结构体存储数据
光照贴图(Lighting maps)
我们可以不要把贴图当做一张图,而是一种数据存储方式
漫反射贴图和镜面光贴图
简而言之就是贴图存储了上述的漫反射参数,在片元着色器里对其进行采样赋值。
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));
FragColor = vec4(ambient + diffuse + specular, 1.0);
法线贴图/位移贴图/反射贴图
- 法线贴图:改变法线实现凹凸效果
- 位移贴图:改变顶点实现凹凸效果
- 反射贴图:改变法线
用Unity表示效果
三、投光物(Light casters)
其实就是光源
平行光(Direct Light)
- 无限远
- 方向相同
vec3 lightDir = normalize(-light.direction);
定义一个光线方向向量而不是位置向量来模拟一个定向光
点光源 (Point Light)
球形加光强衰减
- 重点是衰减函数,知道就行,不予赘述。
- 注意一点,所有光照有关的都是设置被照的物体的shader上
float distance = length(light.position - FragPos);
float attenuation = 1.0 / (light.constant + light.linear * distance +
light.quadratic * (distance * distance));
聚光等(Spot Light)
类似锥形,手电。
- 判断是否在聚光灯照射内
- 平滑/软化边缘
四、多光源(Multiple lights)
void main()
{
// 属性
vec3 norm = normalize(Normal);
vec3 viewDir = normalize(viewPos - FragPos);
// 第一阶段:定向光照
vec3 result = CalcDirLight(dirLight, norm, viewDir);
// 第二阶段:点光源
for(int i = 0; i < NR_POINT_LIGHTS; i++)
result += CalcPointLight(pointLights[i], norm, FragPos, viewDir);
// 第三阶段:聚光
result += CalcSpotLight(spotLight, norm, FragPos, viewDir);
FragColor = vec4(result, 1.0);
}
其实就是分装不同的类型,然后逐一叠加。
但是此处并未考虑前向或者延迟渲染。