Merge branch 'blender-v2.93-release'
[blender.git] / source / blender / draw / engines / eevee / shaders / bsdf_common_lib.glsl
1
2 #pragma BLENDER_REQUIRE(common_math_lib.glsl)
3
4 vec3 diffuse_dominant_dir(vec3 bent_normal)
5 {
6   return bent_normal;
7 }
8
9 vec3 specular_dominant_dir(vec3 N, vec3 V, float roughness)
10 {
11   vec3 R = -reflect(V, N);
12   float smoothness = 1.0 - roughness;
13   float fac = smoothness * (sqrt(smoothness) + roughness);
14   return normalize(mix(N, R, fac));
15 }
16
17 float ior_from_f0(float f0)
18 {
19   float f = sqrt(f0);
20   return (-f - 1.0) / (f - 1.0);
21 }
22
23 /* Simplified form of F_eta(eta, 1.0). */
24 float f0_from_ior(float eta)
25 {
26   float A = (eta - 1.0) / (eta + 1.0);
27   return A * A;
28 }
29
30 vec3 refraction_dominant_dir(vec3 N, vec3 V, float roughness, float ior)
31 {
32   /* TODO: This a bad approximation. Better approximation should fit
33    * the refracted vector and roughness into the best prefiltered reflection
34    * lobe. */
35   /* Correct the IOR for ior < 1.0 to not see the abrupt delimitation or the TIR */
36   ior = (ior < 1.0) ? mix(ior, 1.0, roughness) : ior;
37   float eta = 1.0 / ior;
38
39   float NV = dot(N, -V);
40
41   /* Custom Refraction. */
42   float k = 1.0 - eta * eta * (1.0 - NV * NV);
43   k = max(0.0, k); /* Only this changes. */
44   vec3 R = eta * -V - (eta * NV + sqrt(k)) * N;
45
46   return R;
47 }
48
49 /* Fresnel monochromatic, perfect mirror */
50 float F_eta(float eta, float cos_theta)
51 {
52   /* compute fresnel reflectance without explicitly computing
53    * the refracted direction */
54   float c = abs(cos_theta);
55   float g = eta * eta - 1.0 + c * c;
56   if (g > 0.0) {
57     g = sqrt(g);
58     float A = (g - c) / (g + c);
59     float B = (c * (g + c) - 1.0) / (c * (g - c) + 1.0);
60     return 0.5 * A * A * (1.0 + B * B);
61   }
62   /* Total internal reflections. */
63   return 1.0;
64 }
65
66 /* Fresnel color blend base on fresnel factor */
67 vec3 F_color_blend(float eta, float fresnel, vec3 f0_color)
68 {
69   float f0 = f0_from_ior(eta);
70   float fac = saturate((fresnel - f0) / (1.0 - f0));
71   return mix(f0_color, vec3(1.0), fac);
72 }
73
74 /* Fresnel split-sum approximation. */
75 vec3 F_brdf_single_scatter(vec3 f0, vec3 f90, vec2 lut)
76 {
77   /* Unreal specular matching : if specular color is below 2% intensity,
78    * treat as shadowning */
79   return lut.y * f90 + lut.x * f0;
80 }
81
82 /* Multi-scattering brdf approximation from :
83  * "A Multiple-Scattering Microfacet Model for Real-Time Image-based Lighting"
84  * by Carmelo J. Fdez-Ag├╝era. */
85 vec3 F_brdf_multi_scatter(vec3 f0, vec3 f90, vec2 lut)
86 {
87   vec3 FssEss = lut.y * f90 + lut.x * f0;
88
89   float Ess = lut.x + lut.y;
90   float Ems = 1.0 - Ess;
91   vec3 Favg = f0 + (1.0 - f0) / 21.0;
92   vec3 Fms = FssEss * Favg / (1.0 - (1.0 - Ess) * Favg);
93   /* We don't do anything special for diffuse surfaces because the principle bsdf
94    * does not care about energy conservation of the specular layer for dielectrics. */
95   return FssEss + Fms * Ems;
96 }
97
98 /* GGX */
99 float D_ggx_opti(float NH, float a2)
100 {
101   float tmp = (NH * a2 - NH) * NH + 1.0;
102   return M_PI * tmp * tmp; /* Doing RCP and mul a2 at the end */
103 }
104
105 float G1_Smith_GGX_opti(float NX, float a2)
106 {
107   /* Using Brian Karis approach and refactoring by NX/NX
108    * this way the (2*NL)*(2*NV) in G = G1(V) * G1(L) gets canceled by the brdf denominator 4*NL*NV
109    * Rcp is done on the whole G later
110    * Note that this is not convenient for the transmission formula */
111   return NX + sqrt(NX * (NX - NX * a2) + a2);
112   /* return 2 / (1 + sqrt(1 + a2 * (1 - NX*NX) / (NX*NX) ) ); /* Reference function */
113 }
114
115 float bsdf_ggx(vec3 N, vec3 L, vec3 V, float roughness)
116 {
117   float a = roughness;
118   float a2 = a * a;
119
120   vec3 H = normalize(L + V);
121   float NH = max(dot(N, H), 1e-8);
122   float NL = max(dot(N, L), 1e-8);
123   float NV = max(dot(N, V), 1e-8);
124
125   float G = G1_Smith_GGX_opti(NV, a2) * G1_Smith_GGX_opti(NL, a2); /* Doing RCP at the end */
126   float D = D_ggx_opti(NH, a2);
127
128   /* Denominator is canceled by G1_Smith */
129   /* bsdf = D * G / (4.0 * NL * NV); /* Reference function */
130   return NL * a2 / (D * G); /* NL to Fit cycles Equation : line. 345 in bsdf_microfacet.h */
131 }
132
133 void accumulate_light(vec3 light, float fac, inout vec4 accum)
134 {
135   accum += vec4(light, 1.0) * min(fac, (1.0 - accum.a));
136 }
137
138 /* Same thing as Cycles without the comments to make it shorter. */
139 vec3 ensure_valid_reflection(vec3 Ng, vec3 I, vec3 N)
140 {
141   vec3 R = -reflect(I, N);
142
143   /* Reflection rays may always be at least as shallow as the incoming ray. */
144   float threshold = min(0.9 * dot(Ng, I), 0.025);
145   if (dot(Ng, R) >= threshold) {
146     return N;
147   }
148
149   float NdotNg = dot(N, Ng);
150   vec3 X = normalize(N - NdotNg * Ng);
151
152   float Ix = dot(I, X), Iz = dot(I, Ng);
153   float Ix2 = sqr(Ix), Iz2 = sqr(Iz);
154   float a = Ix2 + Iz2;
155
156   float b = sqrt(Ix2 * (a - sqr(threshold)));
157   float c = Iz * threshold + a;
158
159   float fac = 0.5 / a;
160   float N1_z2 = fac * (b + c), N2_z2 = fac * (-b + c);
161   bool valid1 = (N1_z2 > 1e-5) && (N1_z2 <= (1.0 + 1e-5));
162   bool valid2 = (N2_z2 > 1e-5) && (N2_z2 <= (1.0 + 1e-5));
163
164   vec2 N_new;
165   if (valid1 && valid2) {
166     /* If both are possible, do the expensive reflection-based check. */
167     vec2 N1 = vec2(sqrt(1.0 - N1_z2), sqrt(N1_z2));
168     vec2 N2 = vec2(sqrt(1.0 - N2_z2), sqrt(N2_z2));
169
170     float R1 = 2.0 * (N1.x * Ix + N1.y * Iz) * N1.y - Iz;
171     float R2 = 2.0 * (N2.x * Ix + N2.y * Iz) * N2.y - Iz;
172
173     valid1 = (R1 >= 1e-5);
174     valid2 = (R2 >= 1e-5);
175     if (valid1 && valid2) {
176       N_new = (R1 < R2) ? N1 : N2;
177     }
178     else {
179       N_new = (R1 > R2) ? N1 : N2;
180     }
181   }
182   else if (valid1 || valid2) {
183     float Nz2 = valid1 ? N1_z2 : N2_z2;
184     N_new = vec2(sqrt(1.0 - Nz2), sqrt(Nz2));
185   }
186   else {
187     return Ng;
188   }
189   return N_new.x * X + N_new.y * Ng;
190 }
191
192 /* ----------- Cone angle Approximation --------- */
193
194 /* Return a fitted cone angle given the input roughness */
195 float cone_cosine(float r)
196 {
197   /* Using phong gloss
198    * roughness = sqrt(2/(gloss+2)) */
199   float gloss = -2 + 2 / (r * r);
200   /* Drobot 2014 in GPUPro5 */
201   // return cos(2.0 * sqrt(2.0 / (gloss + 2)));
202   /* Uludag 2014 in GPUPro5 */
203   // return pow(0.244, 1 / (gloss + 1));
204   /* Jimenez 2016 in Practical Realtime Strategies for Accurate Indirect Occlusion*/
205   return exp2(-3.32193 * r * r);
206 }