-
Notifications
You must be signed in to change notification settings - Fork 231
/
ibl.glsl
210 lines (157 loc) · 8.57 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
uniform float u_EnvIntensity;
vec3 getDiffuseLight(vec3 n)
{
return texture(u_LambertianEnvSampler, u_EnvRotation * n).rgb * u_EnvIntensity;
}
vec4 getSpecularSample(vec3 reflection, float lod)
{
return textureLod(u_GGXEnvSampler, u_EnvRotation * reflection, lod) * u_EnvIntensity;
}
vec4 getSheenSample(vec3 reflection, float lod)
{
return textureLod(u_CharlieEnvSampler, u_EnvRotation * reflection, lod) * u_EnvIntensity;
}
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_IRIDESCENCE
vec3 getIBLRadianceGGXIridescence(vec3 n, vec3 v, float roughness, vec3 F0, vec3 iridescenceFresnel, float iridescenceFactor, 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 = mix(F0 + Fr * pow(1.0 - NdotV, 5.0), iridescenceFresnel, iridescenceFactor);
vec3 FssEss = k_S * f_ab.x + f_ab.y;
return specularWeight * specularLight * FssEss;
}
#endif
#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;
}
#ifdef MATERIAL_IRIDESCENCE
// specularWeight is introduced with KHR_materials_specular
vec3 getIBLRadianceLambertianIridescence(vec3 n, vec3 v, float roughness, vec3 diffuseColor, vec3 F0, vec3 iridescenceF0, float iridescenceFactor, 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);
// Use the maximum component of the iridescence Fresnel color
// Maximum is used instead of the RGB value to not get inverse colors for the diffuse BRDF
vec3 iridescenceF0Max = vec3(max(max(iridescenceF0.r, iridescenceF0.g), iridescenceF0.b));
// Blend between base F0 and iridescence F0
vec3 mixedF0 = mix(F0, iridescenceF0Max, iridescenceFactor);
// 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), mixedF0) - mixedF0;
vec3 k_S = mixedF0 + 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 * (mixedF0 + (1.0 - mixedF0) / 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;
}
#endif
#ifdef MATERIAL_ANISOTROPY
vec3 getIBLRadianceAnisotropy(vec3 n, vec3 v, float roughness, float anisotropy, vec3 anisotropyDirection, vec3 F0, float specularWeight)
{
float NdotV = clampedDot(n, v);
float tangentRoughness = mix(roughness, 1.0, anisotropy * anisotropy);
vec3 anisotropicTangent = cross(anisotropyDirection, v);
vec3 anisotropicNormal = cross(anisotropicTangent, anisotropyDirection);
float bendFactor = 1.0 - anisotropy * (1.0 - roughness);
float bendFactorPow4 = bendFactor * bendFactor * bendFactor * bendFactor;
vec3 bentNormal = normalize(mix(anisotropicNormal, n, bendFactorPow4));
float lod = roughness * float(u_MipCount - 1);
vec3 reflection = normalize(reflect(-v, bentNormal));
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;
}
#endif
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;
}