Learn OpenGL 笔记6.1 Advanced Lighting(高级照明)

之前我们简要介绍了 Phong 照明模型,为我们的场景带来了基本的真实感。但有一些细节,我们将在本章中重点关注。

基础知识:

1.Blinn-Phong

以前模型的弊端:

Phong 照明是一种很好且非常有效的照明近似方法,但它的镜面反射在某些条件下会分解,特别是当光泽度低导致大(粗糙)镜面区域时。 下图显示了当我们在平面纹理平面上使用 1.0 的镜面反射光泽指数时会发生:

发生这种情况的原因是视图和反射向量之间的角度没有超过 90 度。 如果角度大于 90 度,则生成的点积变为负值,这导致镜面反射指数为 0.0。

    //镜面高光 = 强度 * 镜面高光参数 * 光的颜色
    vec3 specular = specularStrength * spec * lightColor;  

而其中的spec又等于:viewDir和reflectDir的点积 = |a||b|cos0,所以当图中的光射向里的一面,反射出的光,反射向量,与我们的眼睛向量view的夹角,就大于了90度了。导致cos0 < 0了,没光强了。

    // specular
    float specularStrength = 0.5;
    vec3 viewDir = normalize(viewPos - FragPos);
    vec3 reflectDir = reflect(-lightDir, norm);  
    float spec = pow(max(dot(viewDir, reflectDir), 0.0), 32);

Blinn-Phong 着色模型的优势:

1977 年,James F. Blinn 引入了 Blinn-Phong 着色模型,作为我们迄今为止使用的 Phong 着色的扩展。 Blinn-Phong 模型在很大程度上相似,但与镜面反射模型略有不同,因此克服了我们的问题。 我们不依赖于反射向量,而是使用所谓的halfway vector中间向量,它是一个单位向量,正好位于视图方向和光方向的中间。 这个中间向量与表面的法向量对齐得越近,镜面反射的贡献就越高。

 

 

当视图方向与(现在是假想的)反射向量完美对齐时,中间向量与法线向量完美对齐。 视线方向越接近原始反射方向,镜面高光越强。

无论观察者从哪个方向看,中间向量和表面法线之间的角度都不会超过 90 度(当然,除非光线远低于表面)。 结果与 Phong 反射略有不同,但通常在视觉上更合理,尤其是在镜面反射指数较低的情况下。 Blinn-Phong 着色模型也是早期 OpenGL 固定函数管道中使用的精确着色模型。

获得中间向量很容易,我们将光的方向向量和视图向量相加,并对结果进行归一化: 

L:光的向量    V:视图向量(眼睛向量)

 

 Blinn-Phong 的GLSL代码:

vec3 lightDir   = normalize(lightPos - FragPos);
vec3 viewDir    = normalize(viewPos - FragPos);
vec3 halfwayDir = normalize(lightDir + viewDir);

然后镜面反射项的实际计算变成了表面法线中间向量之间的点积,以获得它们之间的余弦角,我们再次提炼出一个specular shininess exponent镜面反射光泽指数

float spec = pow(max(dot(normal, halfwayDir), 0.0), shininess);
vec3 specular = lightColor * spec;

 

Phong 和 Blinn-Phong 着色之间的另一个细微差别是中间向量和表面法线之间的角度(blinn-phong)通常小于视图和反射向量之间的角度(phong)。 因此,要获得类似于 Phong 着色的视觉效果,必须将镜面反射光泽指数设置得更高一些。 一般的经验法则是将其设置在 Phong 光泽指数的 2 到 4 倍之间。

下面是 Phong 指数设置为 8.0 和 Blinn-Phong 分量设置为 32.0 的两种镜面反射模型之间的比较:

 

 二者切换:

void main()
{
    [...]
    float spec = 0.0;
    if(blinn)
    {
        vec3 halfwayDir = normalize(lightDir + viewDir);  
        spec = pow(max(dot(normal, halfwayDir), 0.0), 16.0);
    }
    else
    {
        vec3 reflectDir = reflect(-lightDir, normal);
        spec = pow(max(dot(viewDir, reflectDir), 0.0), 8.0);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值