/
ibl.glsl
118 lines (88 loc) · 4.55 KB
/
ibl.glsl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
vec3 getDiffuseLight(vec3 n)
{
return texture(u_LambertianEnvSampler, u_EnvRotation * n).rgb;
}
vec4 getSpecularSample(vec3 reflection, float lod)
{
return textureLod(u_GGXEnvSampler, u_EnvRotation * reflection, lod);
}
vec4 getSheenSample(vec3 reflection, float lod)
{
return textureLod(u_CharlieEnvSampler, u_EnvRotation * reflection, lod);
}
vec3 getIBLRadianceGGX(vec3 n, vec3 v, float roughness, vec3 F0, float specularWeight)
{
float NdotV = clampedDot(n, v);
float lod = roughness * float(u_MipCount - 1);
vec3 reflection = normalize(reflect(-v, n));
vec2 brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 f_ab = texture(u_GGXLUT, brdfSamplePoint).rg;
vec4 specularSample = getSpecularSample(reflection, lod);
vec3 specularLight = specularSample.rgb;
// see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
// Roughness dependent fresnel, from Fdez-Aguera
vec3 Fr = max(vec3(1.0 - roughness), F0) - F0;
vec3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0);
vec3 FssEss = k_S * f_ab.x + f_ab.y;
return specularWeight * specularLight * FssEss;
}
#ifdef MATERIAL_TRANSMISSION
vec3 getTransmissionSample(vec2 fragCoord, float roughness, float ior)
{
float framebufferLod = log2(float(u_TransmissionFramebufferSize.x)) * applyIorToRoughness(roughness, ior);
vec3 transmittedLight = textureLod(u_TransmissionFramebufferSampler, fragCoord.xy, framebufferLod).rgb;
return transmittedLight;
}
#endif
#ifdef MATERIAL_TRANSMISSION
vec3 getIBLVolumeRefraction(vec3 n, vec3 v, float perceptualRoughness, vec3 baseColor, vec3 f0, vec3 f90,
vec3 position, mat4 modelMatrix, mat4 viewMatrix, mat4 projMatrix, float ior, float thickness, vec3 attenuationColor, float attenuationDistance)
{
vec3 transmissionRay = getVolumeTransmissionRay(n, v, thickness, ior, modelMatrix);
vec3 refractedRayExit = position + transmissionRay;
// Project refracted vector on the framebuffer, while mapping to normalized device coordinates.
vec4 ndcPos = projMatrix * viewMatrix * vec4(refractedRayExit, 1.0);
vec2 refractionCoords = ndcPos.xy / ndcPos.w;
refractionCoords += 1.0;
refractionCoords /= 2.0;
// Sample framebuffer to get pixel the refracted ray hits.
vec3 transmittedLight = getTransmissionSample(refractionCoords, perceptualRoughness, ior);
vec3 attenuatedColor = applyVolumeAttenuation(transmittedLight, length(transmissionRay), attenuationColor, attenuationDistance);
// Sample GGX LUT to get the specular component.
float NdotV = clampedDot(n, v);
vec2 brdfSamplePoint = clamp(vec2(NdotV, perceptualRoughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 brdf = texture(u_GGXLUT, brdfSamplePoint).rg;
vec3 specularColor = f0 * brdf.x + f90 * brdf.y;
return (1.0 - specularColor) * attenuatedColor * baseColor;
}
#endif
// specularWeight is introduced with KHR_materials_specular
vec3 getIBLRadianceLambertian(vec3 n, vec3 v, float roughness, vec3 diffuseColor, vec3 F0, float specularWeight)
{
float NdotV = clampedDot(n, v);
vec2 brdfSamplePoint = clamp(vec2(NdotV, roughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
vec2 f_ab = texture(u_GGXLUT, brdfSamplePoint).rg;
vec3 irradiance = getDiffuseLight(n);
// see https://bruop.github.io/ibl/#single_scattering_results at Single Scattering Results
// Roughness dependent fresnel, from Fdez-Aguera
vec3 Fr = max(vec3(1.0 - roughness), F0) - F0;
vec3 k_S = F0 + Fr * pow(1.0 - NdotV, 5.0);
vec3 FssEss = specularWeight * k_S * f_ab.x + f_ab.y; // <--- GGX / specular light contribution (scale it down if the specularWeight is low)
// Multiple scattering, from Fdez-Aguera
float Ems = (1.0 - (f_ab.x + f_ab.y));
vec3 F_avg = specularWeight * (F0 + (1.0 - F0) / 21.0);
vec3 FmsEms = Ems * FssEss * F_avg / (1.0 - F_avg * Ems);
vec3 k_D = diffuseColor * (1.0 - FssEss + FmsEms); // we use +FmsEms as indicated by the formula in the blog post (might be a typo in the implementation)
return (FmsEms + k_D) * irradiance;
}
vec3 getIBLRadianceCharlie(vec3 n, vec3 v, float sheenRoughness, vec3 sheenColor)
{
float NdotV = clampedDot(n, v);
float lod = sheenRoughness * float(u_MipCount - 1);
vec3 reflection = normalize(reflect(-v, n));
vec2 brdfSamplePoint = clamp(vec2(NdotV, sheenRoughness), vec2(0.0, 0.0), vec2(1.0, 1.0));
float brdf = texture(u_CharlieLUT, brdfSamplePoint).b;
vec4 sheenSample = getSheenSample(reflection, lod);
vec3 sheenLight = sheenSample.rgb;
return sheenLight * sheenColor * brdf;
}