【OpenGL】五、光照

OpenGL Lighting


一、 冯氏光照模型(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;
  1. 点积和叉积的常用作用
    1. 点积:求两向量夹角(接近程度);投影
    2. 叉积:判断两个向量的做优;判断一个点是否在里在外;通过两个向量确定一个坐标系
      入射方向是光源指向片元,而不是片元指向光源
      点乘是两个向量的长度与它们夹角余弦的积,所以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);
}

其实就是分装不同的类型,然后逐一叠加。
但是此处并未考虑前向或者延迟渲染。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值