引言

本篇我们来复现一下opengl的blinn-phong模型、shadow map技术、法线贴图、HDR等内容。这篇的难度略大,有许多复杂的公式和晦涩的算法要钻研。

Part1. Blinn-Phong光照模型

Phong模型是个很高效的光照模型,但是存在一个比较明显的问题,那就是当物体反光度很低时,会导致大片(粗糙的)高光区域,所以后来就又引申出来一个新的光照模型——Blinn-Phong模型来解决这个问题,直接上公式:

$$L_{out} = L_{light} * (\rho_d * dot(n,l) + \rho_s*dot(N,H)^n)$$

$$H = \frac{l + v}{|| l + v ||}$$

所以代码只需简单修改:

for(int i = 0; i < 6; i++){
        if(dl[i].color == vec3(0,0,0)) continue;
        vec3 lightDir = normalize(-dl[i].dir);
        vec3 h = (lightDir + viewDir) / length(lightDir + viewDir);
        float cosine = max(dot(norm, lightDir), 0.0);
        vec3 reflectDir = reflect(-lightDir, norm);
        float cosine2 = pow(max(dot(norm, h), 0.0), material.shininess_n);
        FragColor += vec4(dl[i].color * (vec3(rho_d) * cosine + rho_s * cosine2), 0.0);
    }
    for(int i = 0; i < 6; i++){
        if(pl[i].color == vec3(0,0,0)) continue;
        vec3 lightDir = normalize(pl[i].pos - f_FragPos);
        vec3 h = (lightDir + viewDir) / length(lightDir + viewDir);
        float distance = length(pl[i].pos - f_FragPos);
        float cosine = max(dot(norm, lightDir), 0.0);
        vec3 reflectDir = reflect(-lightDir, norm);
        float cosine2 = pow(max(dot(norm, h), 0.0), material.shininess_n);
        vec3 pl_color = pl[i].color / (pl[i].constant + pl[i].linear * distance + pl[i].quadratic * distance * distance);
        FragColor += vec4(pl_color * (vec3(rho_d) * cosine + rho_s * cosine2), 0.0);
    }

现在看效果发现挺不明显的,可能因为缺少墙体、地板,所以光线整体效果体现不出来。所以我重新做了一份场景来演示blinn-phong的效果:

Part2. Gamma矫正

直接套用公式:

$$rgb_{gamma} = {rgb_{linear}} ^ {\frac{1}{2.2}}$$

Gamma矫正应该属于后处理阶段,因此我们将矫正行为放在PostProcessShader中进行:

#version 330 core
out vec4 FragColor;

in vec2 TexCoords;

uniform sampler2D screenTexture;

void main()
{ 
    vec3 colors = vec3(texture(screenTexture, TexCoords));
    //这里对colors进行后处理
    FragColor.rgb = pow(colors,vec3(1/2.2));
    FragColor.a = 1.0;
}

得到效果: