polyadvent

A game engine from scratch in C
git clone git://jb55.com/polyadvent
Log | Files | Refs | README

pbr.glsl (2765B)


      1 
      2 float dist_ggx(vec3 N, vec3 H, float roughness)
      3 {
      4     float a      = roughness * roughness;
      5     float NdotH  = max(dot(N, H), 0.0);
      6     float NdotH2 = NdotH*NdotH;
      7 
      8     float num    = a;
      9     float denom  = (NdotH2 * (a - 1.0) + 1.0);
     10     denom        = PI * denom * denom;
     11 
     12     return num / denom;
     13 }
     14 
     15 
     16 float geom_schlick_ggx(float NdotV, float roughness)
     17 {
     18     float r = (roughness + 1.0);
     19     float k = (r*r) / 8.0;
     20 
     21     float num   = NdotV;
     22     float denom = NdotV * (1.0 - k) + k;
     23 
     24     return num / denom;
     25 }
     26 
     27 float geom_smith(vec3 N, vec3 V, vec3 L, float roughness)
     28 {
     29     float NdotV = max(dot(N, V), 0.0);
     30     float NdotL = max(dot(N, L), 0.0);
     31     float ggx1 = geom_schlick_ggx(NdotV, roughness);
     32     float ggx2 = geom_schlick_ggx(NdotL, roughness);
     33 
     34     return ggx1 * ggx2;
     35 }
     36 
     37 vec3 fresnel_schlick(float cos_theta, vec3 F0)
     38 {
     39     return F0 + (1.0 - F0) * pow(1.0 - cos_theta, 5.0);
     40 }
     41 
     42 vec3 pbr(vec3 albedo, vec3 V, vec3 normal) {
     43     const float ao = 15.0;
     44     const float metallic = 0.6;
     45     const float exposure = 0.05;
     46     const float roughness = 0.6;
     47     vec3 radiance = sun_color * light_intensity * 2.5;
     48     // radiance += texture(skybox, vec3(0.0, 0.0, 1.0)).rgb;
     49     vec3 N = normalize(normal);
     50     vec3 L = normalize(light_dir);
     51     vec3 H = normalize(V + L);
     52     // non-metallic is always 0.04
     53     vec3 F0 = vec3(0.04);
     54     // while we do vary F0 based on the metalness of a surface by linearly
     55     // interpolating between the original F0 and the albedo value given the
     56     // metallic property
     57     F0 = mix(F0, albedo, metallic);
     58     float HdotV     = max(0.0, dot(H, V));
     59     vec3  F         = fresnel_schlick(HdotV, F0);
     60     float NDF       = dist_ggx(N, H, roughness);
     61     float G         = geom_smith(N, V, L, roughness);
     62 
     63     float NdotL = max(0.0, dot(N, L));
     64 
     65     // Cook-Torrance BRDF
     66     vec3 numerator    = NDF * G * F;
     67     float denominator = 4.0 * max(0.0, dot(N, V)) * NdotL;
     68     vec3 specular     = numerator / max(denominator, 0.001);
     69 
     70     // kS = energy of light that gets reflected
     71     // kD = remaining energy that gets refracted
     72     vec3 kS = F;
     73     vec3 kD = vec3(1.0) - kS;
     74     kD *= 1.0 - metallic;
     75 
     76     // because metallic surfaces don't refract light and thus have no diffuse
     77     // reflections we enforce this property by nullifying kD if the surface is
     78     // metallic
     79 
     80     // Lo = outgoing radiance
     81     // the result of the reflectance equation's integral ∫ over Ω
     82 
     83     vec3 Lo = (kD * albedo / PI + specular) * radiance * NdotL;
     84 
     85     vec3 ambient = vec3(0.03) * albedo * ao;
     86     vec3 color   = ambient + Lo;
     87     // color = uncharted_tonemap(color);
     88 
     89     // color = color / (vec3(1.0) - color * exposure);
     90     // final = final / (vec3(1.0) + color);
     91     // color = color / (vec3(1.0) + color);
     92 
     93     return color;
     94 }