Blender V5.0
bsdf_microfacet.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved.
2 * SPDX-FileCopyrightText: 2011-2022 Blender Foundation
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 * Adapted code from Open Shading Language. */
7
8#pragma once
9
13
14#include "util/math_fast.h"
15
17
22
24 NONE = 0,
26 DIELECTRIC_TINT, /* used by the OSL MaterialX closures */
30};
31
38
43
46
49 /* Reflectivity at perpendicular (F0) and glancing (F90) angles. */
51 /* Negative exponent signals a special case where the real Fresnel is remapped to F0...F90. */
52 float exponent;
53};
54
57
58 /* Perpendicular reflectivity. */
60 /* Precomputed (1-cos)^6 factor for edge tint. */
62};
63
66
68
69 /* Used to account for missing energy due to the single-scattering microfacet model.
70 * This could be included in bsdf->weight as well, but there it would mess up the color
71 * channels.
72 * Note that this is currently only used by GGX. */
74
75 /* Fresnel model to apply, as well as the extra data for it.
76 * For NONE and DIELECTRIC, no extra storage is needed, so the pointer is nullptr for them. */
79
81};
82
83static_assert(sizeof(ShaderClosure) >= sizeof(MicrofacetBsdf), "MicrofacetBsdf is too large!");
84
85/* Beckmann VNDF importance sampling algorithm from:
86 * Importance Sampling Microfacet-Based BSDFs using the Distribution of Visible Normals.
87 * Eric Heitz and Eugene d'Eon, EGSR 2014.
88 * https://hal.inria.fr/hal-00996995v2/document */
89
91 const float alpha_x,
92 const float alpha_y,
93 const float2 rand)
94{
95 /* 1. stretch wi */
96 float3 wi_ = make_float3(alpha_x * wi.x, alpha_y * wi.y, wi.z);
97 wi_ = normalize(wi_);
98
99 /* 2. sample P22_{wi}(x_slope, y_slope, 1, 1) */
100 float2 slope;
101 float cos_phi_i = 1.0f;
102 float sin_phi_i = 0.0f;
103
104 if (wi_.z >= 0.99999f) {
105 /* Special case (normal incidence). */
106 const float r = sqrtf(-logf(rand.x));
107 const float phi = M_2PI_F * rand.y;
108 slope = polar_to_cartesian(r, phi);
109 }
110 else {
111 /* Precomputations. */
112 const float cos_theta_i = wi_.z;
113 const float sin_theta_i = sin_from_cos(cos_theta_i);
114 const float tan_theta_i = sin_theta_i / cos_theta_i;
115 const float cot_theta_i = 1.0f / tan_theta_i;
116 const float erf_a = fast_erff(cot_theta_i);
117 const float exp_a2 = expf(-cot_theta_i * cot_theta_i);
118 const float SQRT_PI_INV = 0.56418958354f;
119
120 const float invlen = 1.0f / sin_theta_i;
121 cos_phi_i = wi_.x * invlen;
122 sin_phi_i = wi_.y * invlen;
123
124 /* Based on paper from Wenzel Jakob
125 * An Improved Visible Normal Sampling Routine for the Beckmann Distribution
126 *
127 * http://www.mitsuba-renderer.org/~wenzel/files/visnormal.pdf
128 *
129 * Reformulation from OpenShadingLanguage which avoids using inverse
130 * trigonometric functions.
131 */
132
133 /* Sample slope X.
134 *
135 * Compute a coarse approximation using the approximation:
136 * `exp(-ierf(x)^2) ~= 1 - x * x`
137 * `solve y = 1 + b + K * (1 - b * b)`
138 */
139 const float K = tan_theta_i * SQRT_PI_INV;
140 const float y_approx = rand.x * (1.0f + erf_a + K * (1 - erf_a * erf_a));
141 const float y_exact = rand.x * (1.0f + erf_a + K * exp_a2);
142 const float b = K > 0 ? (0.5f - sqrtf(K * (K - y_approx + 1.0f) + 0.25f)) / K :
143 y_approx - 1.0f;
144
145 float inv_erf = fast_ierff(b);
146 float2 begin = make_float2(-1.0f, -y_exact);
147 float2 end = make_float2(erf_a, 1.0f + erf_a + K * exp_a2 - y_exact);
148 float2 current = make_float2(b, 1.0f + b + K * expf(-sqr(inv_erf)) - y_exact);
149
150 /* Find root in a monotonic interval using newton method, under given precision and maximal
151 * iterations. Falls back to bisection if newton step produces results outside of the valid
152 * interval. */
153 const float precision = 1e-6f;
154 const int max_iter = 3;
155 int iter = 0;
156 while (fabsf(current.y) > precision && iter++ < max_iter) {
157 if (signf(begin.y) == signf(current.y)) {
158 begin.x = current.x;
159 begin.y = current.y;
160 }
161 else {
162 end.x = current.x;
163 }
164 const float newton_x = current.x - current.y / (1.0f - inv_erf * tan_theta_i);
165 current.x = (newton_x >= begin.x && newton_x <= end.x) ? newton_x : 0.5f * (begin.x + end.x);
166 inv_erf = fast_ierff(current.x);
167 current.y = 1.0f + current.x + K * expf(-sqr(inv_erf)) - y_exact;
168 }
169
170 slope.x = inv_erf;
171 slope.y = fast_ierff(2.0f * rand.y - 1.0f);
172 }
173
174 /* 3. rotate */
175 slope = make_float2(cos_phi_i * slope.x - sin_phi_i * slope.y,
176 sin_phi_i * slope.x + cos_phi_i * slope.y);
177
178 /* 4. unstretch */
179 slope *= make_float2(alpha_x, alpha_y);
180
181 /* 5. compute normal */
182 return normalize(make_float3(-slope.x, -slope.y, 1.0f));
183}
184
185/* GGX VNDF importance sampling algorithm from:
186 * Sampling the GGX Distribution of Visible Normals.
187 * Eric Heitz, JCGT Vol. 7, No. 4, 2018.
188 * https://jcgt.org/published/0007/04/01/ */
190 const float alpha_x,
191 const float alpha_y,
192 const float2 rand)
193{
194 /* Section 3.2: Transforming the view direction to the hemisphere configuration. */
195 const float3 wi_ = normalize(make_float3(alpha_x * wi.x, alpha_y * wi.y, wi.z));
196
197 /* Section 4.1: Orthonormal basis. */
198 const float lensq = sqr(wi_.x) + sqr(wi_.y);
199 float3 T1;
200 float3 T2;
201 if (lensq > 1e-7f) {
202 T1 = make_float3(-wi_.y, wi_.x, 0.0f) * inversesqrtf(lensq);
203 T2 = cross(wi_, T1);
204 }
205 else {
206 /* Normal incidence, any basis is fine. */
207 T1 = make_float3(1.0f, 0.0f, 0.0f);
208 T2 = make_float3(0.0f, 1.0f, 0.0f);
209 }
210
211 /* Section 4.2: Parameterization of the projected area. */
212 float2 t = sample_uniform_disk(rand);
213 t.y = mix(safe_sqrtf(1.0f - sqr(t.x)), t.y, 0.5f * (1.0f + wi_.z));
214
215 /* Section 4.3: Reprojection onto hemisphere. */
216 const float3 H_ = to_global(disk_to_hemisphere(t), T1, T2, wi_);
217
218 /* Section 3.4: Transforming the normal back to the ellipsoid configuration. */
219 return normalize(make_float3(alpha_x * H_.x, alpha_y * H_.y, max(0.0f, H_.z)));
220}
221
222/* Computes the Fresnel reflectance and transmittance given the Microfacet BSDF and the cosine of
223 * the incoming angle `cos_theta_i`.
224 * Also returns the cosine of the angle between the normal and the refracted ray as `r_cos_theta_t`
225 * if provided. */
227 const ccl_private MicrofacetBsdf *bsdf,
228 const float cos_theta_i,
229 ccl_private float *r_cos_theta_t,
230 ccl_private Spectrum *r_reflectance,
231 ccl_private Spectrum *r_transmittance)
232{
233 /* Whether the closure has reflective or transmissive lobes. */
234 const bool has_reflection = !CLOSURE_IS_REFRACTION(bsdf->type);
235 const bool has_transmission = CLOSURE_IS_GLASS(bsdf->type) || !has_reflection;
236
237 if (bsdf->fresnel_type == MicrofacetFresnel::DIELECTRIC) {
238 const Spectrum F = make_spectrum(fresnel_dielectric(cos_theta_i, bsdf->ior, r_cos_theta_t));
239 *r_reflectance = F;
240 *r_transmittance = one_spectrum() - F;
241 }
242 else if (bsdf->fresnel_type == MicrofacetFresnel::DIELECTRIC_TINT) {
244 bsdf->fresnel;
245 const float F = fresnel_dielectric(cos_theta_i, bsdf->ior, r_cos_theta_t);
246 *r_reflectance = F * fresnel->reflection_tint;
247 *r_transmittance = (1.0f - F) * fresnel->transmission_tint;
248 }
249 else if (bsdf->fresnel_type == MicrofacetFresnel::CONDUCTOR) {
250 ccl_private FresnelConductor *fresnel = (ccl_private FresnelConductor *)bsdf->fresnel;
251
252 if (fresnel->thin_film.thickness > THINFILM_THICKNESS_CUTOFF) {
253 *r_reflectance = fresnel_iridescence<Spectrum>(
254 kg, 1.0f, fresnel->thin_film, fresnel->ior, nullptr, cos_theta_i, r_cos_theta_t);
255 }
256 else {
257 *r_reflectance = fresnel_conductor(cos_theta_i, fresnel->ior);
258 }
259
260 *r_transmittance = zero_spectrum();
261 }
262 else if (bsdf->fresnel_type == MicrofacetFresnel::F82_TINT) {
263 /* F82-Tint model, described in "Novel aspects of the Adobe Standard Material" by Kutz et al.
264 * Essentially, this is the usual Schlick Fresnel with an additional cosI*(1-cosI)^6
265 * term which modulates the reflectivity around acos(1/7) degrees (ca. 82°). */
266 ccl_private FresnelF82Tint *fresnel = (ccl_private FresnelF82Tint *)bsdf->fresnel;
267
268 if (fresnel->thin_film.thickness > THINFILM_THICKNESS_CUTOFF) {
269 /* Estimate n and k by reinterpreting F0 and F82 as r and g from "Artist Friendly Metallic
270 * Fresnel" by Ole Gulbrandsen. */
271 const Spectrum r = min(fresnel->f0, make_float3(0.999f));
272 const Spectrum g = fresnel_f82(1.0f / 7.0f, fresnel->f0, fresnel->b);
273
274 const Spectrum sqrt_r = sqrt(r);
275 const Spectrum n = mix((1.0f + sqrt_r) / (1.0f - sqrt_r), (1.0f - r) / (1.0f + r), g);
276 const Spectrum k = safe_sqrt((r * sqr(n + 1) - sqr(n - 1)) / (1.0f - r));
277
278 *r_reflectance = fresnel_iridescence<Spectrum>(
279 kg, 1.0f, fresnel->thin_film, {n, k}, &g, cos_theta_i, r_cos_theta_t);
280 }
281 else {
282 *r_reflectance = fresnel_f82(cos_theta_i, fresnel->f0, fresnel->b);
283 }
284
285 *r_transmittance = zero_spectrum();
286 }
287 else if (bsdf->fresnel_type == MicrofacetFresnel::GENERALIZED_SCHLICK) {
289 bsdf->fresnel;
290 Spectrum F;
291 if (fresnel->thin_film.thickness > THINFILM_THICKNESS_CUTOFF) {
292 /* Iridescence doesn't combine well with the general case. We only expose it through the
293 * Principled BSDF for now, so it's fine to not support custom exponents and F90. */
294 kernel_assert(fresnel->exponent < 0.0f);
295 kernel_assert(fresnel->f90 == one_spectrum());
297 kg, 1.0f, fresnel->thin_film, {bsdf->ior, 0.0f}, nullptr, cos_theta_i, r_cos_theta_t);
298 /* Apply F0 scaling (here per-channel, since iridescence produces colored output).
299 * Note that the usual approach (as used below) cannot be used here, since F may be below
300 * F0_real. Therefore, use a different approach: Scale the result by (F0 / F0_real), with
301 * the strength of the scaling depending on how close F is to F0_real.
302 * There isn't one single "correct" way to do this, it's just for artistic control anyways.
303 */
304 const float F0_real = F0_from_ior(bsdf->ior);
305 if (F0_real > 1e-5f && !isequal(F, one_spectrum())) {
307 const float s = saturatef(inverse_lerp(1.0f, F0_real, GET_SPECTRUM_CHANNEL(F, i)));
308 const float factor = GET_SPECTRUM_CHANNEL(fresnel->f0, i) / F0_real;
309 GET_SPECTRUM_CHANNEL(F, i) *= mix(1.0f, factor, s);
310 }
311 }
312 }
313 else if (fresnel->exponent < 0.0f) {
314 /* Special case: Use real Fresnel curve to determine the interpolation between F0 and F90.
315 * Used by Principled BSDF. */
316 const float F_real = fresnel_dielectric(cos_theta_i, bsdf->ior, r_cos_theta_t);
317 const float F0_real = F0_from_ior(bsdf->ior);
318 const float s = saturatef(inverse_lerp(F0_real, 1.0f, F_real));
319 F = mix(fresnel->f0, fresnel->f90, s);
320 }
321 else {
322 /* Regular case: Generalized Schlick term. */
323 const float cos_theta_t_sq = 1.0f - (1.0f - sqr(cos_theta_i)) / sqr(bsdf->ior);
324 if (cos_theta_t_sq <= 0.0f) {
325 /* Total internal reflection */
326 *r_reflectance = fresnel->reflection_tint * (float)has_reflection;
327 *r_transmittance = zero_spectrum();
328 return;
329 }
330 const float cos_theta_t = sqrtf(cos_theta_t_sq);
331 if (r_cos_theta_t) {
332 *r_cos_theta_t = cos_theta_t;
333 }
334
335 /* TODO(lukas): Is a special case for exponent==5 worth it? */
336 /* When going from a higher to a lower IOR, we must use the transmitted angle. */
337 const float fresnel_angle = ((bsdf->ior < 1.0f) ? cos_theta_t : cos_theta_i);
338 const float s = powf(1.0f - fresnel_angle, fresnel->exponent);
339 F = mix(fresnel->f0, fresnel->f90, s);
340 }
341 *r_reflectance = F * fresnel->reflection_tint;
342 *r_transmittance = (one_spectrum() - F) * fresnel->transmission_tint;
343 }
344 else {
345 kernel_assert(bsdf->fresnel_type == MicrofacetFresnel::NONE);
346 /* No Fresnel used, this is either purely reflective or purely refractive closure. */
347 *r_reflectance = *r_transmittance = one_spectrum();
348
349 /* Exclude total internal reflection. */
350 if (has_transmission && fresnel_dielectric(cos_theta_i, bsdf->ior, r_cos_theta_t) == 1.0f) {
351 *r_transmittance = zero_spectrum();
352 }
353 }
354
355 *r_reflectance *= (float)has_reflection;
356 *r_transmittance *= (float)has_transmission;
357}
358
361 const ccl_private ShaderData *sd,
362 const Spectrum Fss)
363{
364 const float mu = dot(sd->wi, bsdf->N);
365 const float rough = sqrtf(sqrtf(bsdf->alpha_x * bsdf->alpha_y));
366
367 float E;
368 float E_avg;
369 if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_ID) {
370 E = lookup_table_read_2D(kg, rough, mu, kernel_data.tables.ggx_E, 32, 32);
371 E_avg = lookup_table_read(kg, rough, kernel_data.tables.ggx_Eavg, 32);
372 }
373 else if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID) {
374 int ofs = kernel_data.tables.ggx_glass_E;
375 int avg_ofs = kernel_data.tables.ggx_glass_Eavg;
376 float ior = bsdf->ior;
377 if (ior < 1.0f) {
378 ior = 1.0f / ior;
379 ofs = kernel_data.tables.ggx_glass_inv_E;
380 avg_ofs = kernel_data.tables.ggx_glass_inv_Eavg;
381 }
382 /* TODO: Bias mu towards more precision for low values. */
383 const float z = sqrtf(fabsf((ior - 1.0f) / (ior + 1.0f)));
384 E = lookup_table_read_3D(kg, rough, mu, z, ofs, 16, 16, 16);
385 E_avg = lookup_table_read_2D(kg, rough, z, avg_ofs, 16, 16);
386 }
387 else {
388 kernel_assert(false);
389 E = 1.0f;
390 E_avg = 1.0f;
391 }
392
393 const float missing_factor = ((1.0f - E) / E);
394 bsdf->energy_scale = 1.0f + missing_factor;
395
396 /* Check if we need to account for extra darkening/saturation due to multi-bounce Fresnel. */
397 if (!isequal(Fss, one_spectrum())) {
398 /* Fms here is based on the appendix of "Revisiting Physically Based Shading at Imageworks"
399 * by Christopher Kulla and Alejandro Conty,
400 * with one Fss cancelled out since this is just a multiplier on top of
401 * the single-scattering BSDF, which already contains one bounce of Fresnel. */
402 const Spectrum Fms = Fss * E_avg / (one_spectrum() - Fss * (1.0f - E_avg));
403 /* Since we already include the energy compensation in bsdf->energy_scale,
404 * this term is what's needed to make the full BSDF * weight * energy_scale
405 * computation work out to the correct value. */
406 const Spectrum darkening = (one_spectrum() + Fms * missing_factor) / bsdf->energy_scale;
407 bsdf->weight *= darkening;
408 bsdf->sample_weight *= average(darkening);
409 }
410}
411
412/* This function estimates the albedo of the BSDF (NOT including the bsdf->weight) as caused by
413 * the applied Fresnel model for the given view direction.
414 * The base microfacet model is assumed to have an albedo of 1 (we have the energy preservation
415 * code for that), but e.g. a reflection-only closure with Fresnel applied can end up having
416 * a very low overall albedo.
417 * This is used to adjust the sample weight, as well as for the Diff/Gloss/Trans Color pass
418 * and the Denoising Albedo pass.
419 *
420 * TODO: The Schlick LUT seems to assume energy preservation, which is not true for GGX. if
421 * energy-preserving then transmission should just be `1 - reflection`. For dielectric we could
422 * probably split the LUT for multiGGX if smooth assumption is not good enough. */
424 const ccl_private ShaderData *sd,
425 const ccl_private MicrofacetBsdf *bsdf,
426 const bool eval_reflection,
427 const bool eval_transmission)
428{
429 const float cos_NI = dot(sd->wi, bsdf->N);
430 Spectrum reflectance;
431 Spectrum transmittance;
432 microfacet_fresnel(kg, bsdf, cos_NI, nullptr, &reflectance, &transmittance);
433
434 reflectance *= (float)eval_reflection;
435 transmittance *= (float)eval_transmission;
436
437 /* Use lookup tables for generalized Schlick reflection, otherwise assume smooth surface. */
438 if (is_zero(reflectance)) {
439 /* Reflectivity is either zero or not requested, so don't compute the more complex estimate. */
440 }
441 else if (bsdf->fresnel_type == MicrofacetFresnel::GENERALIZED_SCHLICK) {
443 bsdf->fresnel;
444
445 if (fresnel->thin_film.thickness > THINFILM_THICKNESS_CUTOFF) {
446 /* Precomputing LUTs for thin-film iridescence isn't viable, so fall back to the specular
447 * reflection approximation from the microfacet_fresnel call above in that case. */
448 }
449 else {
450 const float rough = sqrtf(sqrtf(bsdf->alpha_x * bsdf->alpha_y));
451 float s;
452 if (fresnel->exponent < 0.0f) {
453 const float z = sqrtf(fabsf((bsdf->ior - 1.0f) / (bsdf->ior + 1.0f)));
455 kg, rough, cos_NI, z, kernel_data.tables.ggx_gen_schlick_ior_s, 16, 16, 16);
456 }
457 else {
458 const float z = 1.0f / (0.2f * fresnel->exponent + 1.0f);
460 kg, rough, cos_NI, z, kernel_data.tables.ggx_gen_schlick_s, 16, 16, 16);
461 }
462 reflectance = mix(fresnel->f0, fresnel->f90, s) * fresnel->reflection_tint;
463 }
464 }
465 else if (bsdf->fresnel_type == MicrofacetFresnel::F82_TINT) {
466 ccl_private FresnelF82Tint *fresnel = (ccl_private FresnelF82Tint *)bsdf->fresnel;
467
468 if (fresnel->thin_film.thickness > THINFILM_THICKNESS_CUTOFF) {
469 /* Precomputing LUTs for thin-film iridescence isn't viable, so fall back to the specular
470 * reflection approximation from the microfacet_fresnel call above in that case. */
471 }
472 else {
473 const float rough = sqrtf(sqrtf(bsdf->alpha_x * bsdf->alpha_y));
474 const float s = lookup_table_read_3D(
475 kg, rough, cos_NI, 0.5f, kernel_data.tables.ggx_gen_schlick_s, 16, 16, 16);
476 /* TODO: Precompute B factor term and account for it here. */
477 reflectance = mix(fresnel->f0, one_spectrum(), s);
478 }
479 }
480 else if ((bsdf->fresnel_type == MicrofacetFresnel::DIELECTRIC ||
481 bsdf->fresnel_type == MicrofacetFresnel::DIELECTRIC_TINT) &&
482 bsdf->ior > 1.0f)
483 {
484 /* We can re-use the ggx_gen_schlick_ior_s table here, since it's already precomputed for our
485 * exponent<0 corner case where we use the real dielectric Fresnel. */
486 const float rough = sqrtf(sqrtf(bsdf->alpha_x * bsdf->alpha_y));
487 const float z = sqrtf(fabsf((bsdf->ior - 1.0f) / (bsdf->ior + 1.0f)));
488 const float s = lookup_table_read_3D(
489 kg, rough, cos_NI, z, kernel_data.tables.ggx_gen_schlick_ior_s, 16, 16, 16);
490 reflectance = make_spectrum(mix(F0_from_ior(bsdf->ior), 1.0f, s));
491 if (bsdf->fresnel_type == MicrofacetFresnel::DIELECTRIC_TINT) {
493 bsdf->fresnel;
494 reflectance *= fresnel->reflection_tint;
495 }
496 }
497
498 return reflectance + transmittance;
499}
500
501/* Smith shadowing-masking term, here in the non-separable form.
502 * For details, see:
503 * Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs.
504 * Eric Heitz, JCGT Vol. 3, No. 2, 2014.
505 * https://jcgt.org/published/0003/02/03/ */
506template<MicrofacetType m_type>
507ccl_device_inline float bsdf_lambda_from_sqr_alpha_tan_n(const float sqr_alpha_tan_n)
508{
510 /* Equation 72. */
511 return 0.5f * (sqrtf(1.0f + sqr_alpha_tan_n) - 1.0f);
512 }
514 /* Approximation from below Equation 69. */
515 if (sqr_alpha_tan_n < 0.39f) {
516 /* Equivalent to a >= 1.6f, but also handles sqr_alpha_tan_n == 0.0f cleanly. */
517 return 0.0f;
518 }
519
520 const float a = inversesqrtf(sqr_alpha_tan_n);
521 return ((0.396f * a - 1.259f) * a + 1.0f) / ((2.181f * a + 3.535f) * a);
522}
523
524template<MicrofacetType m_type>
525ccl_device_inline float bsdf_lambda(const float alpha2, const float cos_N)
526{
527 return bsdf_lambda_from_sqr_alpha_tan_n<m_type>(alpha2 * fmaxf(1.0f / sqr(cos_N) - 1.0f, 0.0f));
528}
529
530template<MicrofacetType m_type>
531ccl_device_inline float bsdf_aniso_lambda(const float alpha_x, const float alpha_y, const float3 V)
532{
533 const float sqr_alpha_tan_n = (sqr(alpha_x * V.x) + sqr(alpha_y * V.y)) / sqr(V.z);
534 return bsdf_lambda_from_sqr_alpha_tan_n<m_type>(sqr_alpha_tan_n);
535}
536
537/* Mono-directional shadowing-masking term. */
538template<MicrofacetType m_type>
539ccl_device_inline float bsdf_G(const float alpha2, const float cos_N)
540{
541 return 1.0f / (1.0f + bsdf_lambda<m_type>(alpha2, cos_N));
542}
543
544/* Combined shadowing-masking term. */
545template<MicrofacetType m_type>
546ccl_device_inline float bsdf_G(const float alpha2, const float cos_NI, const float cos_NO)
547{
548 return 1.0f / (1.0f + bsdf_lambda<m_type>(alpha2, cos_NI) + bsdf_lambda<m_type>(alpha2, cos_NO));
549}
550
551/* Normal distribution function. */
552template<MicrofacetType m_type>
553ccl_device_inline float bsdf_D(const float alpha2, const float cos_NH)
554{
555 const float cos_NH2 = min(sqr(cos_NH), 1.0f);
556 const float one_minus_cos_NH2 = 1.0f - cos_NH2;
557
559 return 1.0f / (expf(one_minus_cos_NH2 / (cos_NH2 * alpha2)) * M_PI_F * alpha2 * sqr(cos_NH2));
560 }
562 return alpha2 / (M_PI_F * sqr(one_minus_cos_NH2 + alpha2 * cos_NH2));
563}
564
565template<MicrofacetType m_type>
566ccl_device_inline float bsdf_aniso_D(const float alpha_x, const float alpha_y, float3 H)
567{
568 H /= make_float3(alpha_x, alpha_y, 1.0f);
569
570 const float cos_NH2 = sqr(H.z);
571 const float alpha2 = alpha_x * alpha_y;
572
574 return expf(-(sqr(H.x) + sqr(H.y)) / cos_NH2) / (M_PI_F * alpha2 * sqr(cos_NH2));
575 }
577 return M_1_PI_F / (alpha2 * sqr(len_squared(H)));
578}
579
580/* Do not set `SD_BSDF_HAS_EVAL` flag if the squared roughness is below a certain threshold. */
582{
583 return (bsdf->alpha_x * bsdf->alpha_y > BSDF_ROUGHNESS_SQ_THRESH) ? SD_BSDF_HAS_EVAL : 0;
584}
585
586template<MicrofacetType m_type>
588 const ccl_private ShaderClosure *sc,
589 const float3 wi,
590 const float3 wo,
591 ccl_private float *pdf)
592{
593 const ccl_private MicrofacetBsdf *bsdf = (const ccl_private MicrofacetBsdf *)sc;
594
595 /* Whether the closure has reflective or transmissive lobes. */
596 const bool has_reflection = !CLOSURE_IS_REFRACTION(bsdf->type);
597 const bool has_transmission = CLOSURE_IS_GLASS(bsdf->type) || !has_reflection;
598
599 const float3 N = bsdf->N;
600 const float cos_NI = dot(N, wi);
601 const float cos_NO = dot(N, wo);
602
603 const float alpha_x = bsdf->alpha_x;
604 const float alpha_y = bsdf->alpha_y;
605
606 const bool is_transmission = (cos_NO < 0.0f);
607
608 /* Check whether the pair of directions is valid for evaluation:
609 * - Incoming direction has to be in the upper hemisphere (Cycles convention)
610 * - Specular cases can't be evaluated, only sampled.
611 * - Purely reflective closures can't have refraction.
612 * - Purely refractive closures can't have reflection.
613 */
614 if ((cos_NI <= 0) || !bsdf_microfacet_eval_flag(bsdf) ||
615 (is_transmission && !has_transmission) || (!is_transmission && !has_reflection))
616 {
617 return zero_spectrum();
618 }
619
620 /* Compute half vector. */
621 /* TODO: deal with the case when `bsdf->ior` is close to one. */
622 /* TODO: check if the refraction configuration is valid. See `btdf_ggx()` in
623 * `eevee_bxdf_lib.glsl`. */
624 float3 H = is_transmission ? -(bsdf->ior * wo + wi) : (wi + wo);
625 const float inv_len_H = safe_divide(1.0f, len(H));
626 H *= inv_len_H;
627
628 /* Compute Fresnel coefficients. */
629 const float cos_HI = dot(H, wi);
630 Spectrum reflectance;
631 Spectrum transmittance;
632 microfacet_fresnel(kg, bsdf, cos_HI, nullptr, &reflectance, &transmittance);
633
634 if (is_zero(reflectance) && is_zero(transmittance)) {
635 return zero_spectrum();
636 }
637
638 const float cos_NH = dot(N, H);
639 float D;
640 float lambdaI;
641 float lambdaO;
642
643 /* NOTE: we could add support for anisotropic transmission, although it will make dispersion
644 * harder to compute. */
645 if (alpha_x == alpha_y || is_transmission) { /* Isotropic. */
646 const float alpha2 = alpha_x * alpha_y;
647 D = bsdf_D<m_type>(alpha2, cos_NH);
648 lambdaI = bsdf_lambda<m_type>(alpha2, cos_NI);
649 lambdaO = bsdf_lambda<m_type>(alpha2, cos_NO);
650 }
651 else { /* Anisotropic. */
652 float3 X;
653 float3 Y;
654 make_orthonormals_tangent(N, bsdf->T, &X, &Y);
655
656 const float3 local_H = make_float3(dot(X, H), dot(Y, H), cos_NH);
657 const float3 local_I = make_float3(dot(X, wi), dot(Y, wi), cos_NI);
658 const float3 local_O = make_float3(dot(X, wo), dot(Y, wo), cos_NO);
659
660 D = bsdf_aniso_D<m_type>(alpha_x, alpha_y, local_H);
661
662 lambdaI = bsdf_aniso_lambda<m_type>(alpha_x, alpha_y, local_I);
663 lambdaO = bsdf_aniso_lambda<m_type>(alpha_x, alpha_y, local_O);
664 }
665
666 const float common = D / cos_NI *
667 (is_transmission ? sqr(bsdf->ior * inv_len_H) * fabsf(cos_HI * dot(H, wo)) :
668 0.25f);
669
670 const float pdf_reflect = average(reflectance) / average(reflectance + transmittance);
671 const float lobe_pdf = is_transmission ? 1.0f - pdf_reflect : pdf_reflect;
672
673 *pdf = common * lobe_pdf / (1.0f + lambdaI);
674 return (is_transmission ? transmittance : reflectance) * common / (1.0f + lambdaO + lambdaI);
675}
676
677template<MicrofacetType m_type>
679 const ccl_private ShaderClosure *sc,
680 const float3 Ng,
681 const float3 wi,
682 const float3 rand,
683 ccl_private Spectrum *eval,
685 ccl_private float *pdf,
686 ccl_private float2 *sampled_roughness,
687 ccl_private float *eta)
688{
689 const ccl_private MicrofacetBsdf *bsdf = (const ccl_private MicrofacetBsdf *)sc;
690
691 const float3 N = bsdf->N;
692 const float cos_NI = dot(N, wi);
693 if (cos_NI <= 0) {
694 /* Incident angle from the lower hemisphere is invalid. */
695 return LABEL_NONE;
696 }
697
698 const float m_eta = bsdf->ior;
699 const float m_inv_eta = safe_divide(1.0f, bsdf->ior);
700 const float alpha_x = bsdf->alpha_x;
701 const float alpha_y = bsdf->alpha_y;
702 bool m_singular = !bsdf_microfacet_eval_flag(bsdf);
703
704 /* Half vector. */
705 float3 H;
706 /* Needed for anisotropic microfacets later. */
707 float3 local_H;
708 float3 local_I;
709 if (m_singular) {
710 H = N;
711 }
712 else {
713 float3 X;
714 float3 Y;
715 if (alpha_x == alpha_y) {
716 make_orthonormals(N, &X, &Y);
717 }
718 else {
719 make_orthonormals_tangent(N, bsdf->T, &X, &Y);
720 }
721
722 /* Importance sampling with distribution of visible normals. Vectors are transformed to local
723 * space before and after sampling. */
724 local_I = make_float3(dot(X, wi), dot(Y, wi), cos_NI);
726 local_H = microfacet_ggx_sample_vndf(local_I, alpha_x, alpha_y, make_float2(rand));
727 }
728 else {
729 /* m_type == MicrofacetType::BECKMANN */
730 local_H = microfacet_beckmann_sample_vndf(local_I, alpha_x, alpha_y, make_float2(rand));
731 }
732
733 H = to_global(local_H, X, Y, N);
734 }
735 const float cos_HI = dot(H, wi);
736
737 /* The angle between the half vector and the refracted ray. Not used when sampling reflection. */
738 float cos_HO;
739 /* Compute Fresnel coefficients. */
740 Spectrum reflectance;
741 Spectrum transmittance;
742 microfacet_fresnel(kg, bsdf, cos_HI, &cos_HO, &reflectance, &transmittance);
743
744 if (is_zero(reflectance) && is_zero(transmittance)) {
745 return LABEL_NONE;
746 }
747
748 /* Decide between refraction and reflection based on the energy. */
749 const float pdf_reflect = average(reflectance) / average(reflectance + transmittance);
750 const bool do_refract = (rand.z >= pdf_reflect);
751
752 /* Compute actual reflected or refracted direction. */
753 *wo = do_refract ? refract_angle(wi, H, cos_HO, m_inv_eta) : 2.0f * cos_HI * H - wi;
754
755 /* Ensure that the sampled direction lies in the correct hemisphere.
756 * Note that the check against Ng is only performed in the sampling code, not the evaluation.
757 * This is technically inconsistent, but required in order to avoid shadow terminator artifacts
758 * on smooth geometry (which we'd get if we checked Ng in evaluation) while ensuring that
759 * sampling doesn't return supposed reflection rays going into the geometry and vice versa.
760 * The same is done for other closures as well. */
761 const float cos_NO = dot(N, *wo);
762 const float cos_NgO = dot(Ng, *wo);
763 if ((cos_NgO < 0) != do_refract || (cos_NO < 0) != do_refract) {
764 return LABEL_NONE;
765 }
766
767 if (do_refract) {
768 *eval = transmittance;
769 *pdf = 1.0f - pdf_reflect;
770 /* If the IOR is close enough to 1.0, just treat the interaction as specular. */
771 m_singular = m_singular || (fabsf(m_eta - 1.0f) < 1e-4f);
772 }
773 else {
774 *eval = reflectance;
775 *pdf = pdf_reflect;
776 }
777
778 if (m_singular) {
779 /* Some high number for MIS. */
780 *pdf *= 1e6f;
781 *eval *= 1e6f;
782 }
783 else {
784 float D;
785 float lambdaI;
786 float lambdaO;
787
788 /* TODO: add support for anisotropic transmission. */
789 if (alpha_x == alpha_y || do_refract) { /* Isotropic. */
790 const float alpha2 = alpha_x * alpha_y;
791 const float cos_NH = local_H.z;
792 const float cos_NO = dot(N, *wo);
793
794 D = bsdf_D<m_type>(alpha2, cos_NH);
795 lambdaO = bsdf_lambda<m_type>(alpha2, cos_NO);
796 lambdaI = bsdf_lambda<m_type>(alpha2, cos_NI);
797 }
798 else { /* Anisotropic. */
799 const float3 local_O = 2.0f * cos_HI * local_H - local_I;
800
801 D = bsdf_aniso_D<m_type>(alpha_x, alpha_y, local_H);
802
803 lambdaO = bsdf_aniso_lambda<m_type>(alpha_x, alpha_y, local_O);
804 lambdaI = bsdf_aniso_lambda<m_type>(alpha_x, alpha_y, local_I);
805 }
806
807 const float common = D / cos_NI *
808 (do_refract ? fabsf(cos_HI * cos_HO) / sqr(cos_HO + cos_HI * m_inv_eta) :
809 0.25f);
810
811 *pdf *= common / (1.0f + lambdaI);
812 *eval *= common / (1.0f + lambdaI + lambdaO);
813 }
814
815 *sampled_roughness = make_float2(alpha_x, alpha_y);
816 *eta = do_refract ? m_eta : 1.0f;
817
818 return (do_refract ? LABEL_TRANSMIT : LABEL_REFLECT) |
819 (m_singular ? LABEL_SINGULAR : LABEL_GLOSSY);
820}
821
822/* Fresnel term setup functions. These get called after the distribution-specific setup functions
823 * like bsdf_microfacet_ggx_setup. */
824
827 const ccl_private ShaderData *sd,
829 const bool preserve_energy)
830{
831 bsdf->fresnel_type = MicrofacetFresnel::CONDUCTOR;
832 bsdf->fresnel = fresnel;
833 bsdf->sample_weight *= average(bsdf_microfacet_estimate_albedo(kg, sd, bsdf, true, true));
834
835 if (preserve_energy) {
836 microfacet_ggx_preserve_energy(kg, bsdf, sd, fresnel_conductor_Fss(fresnel->ior));
837 }
838}
839
841 KernelGlobals kg,
843 const ccl_private ShaderData *sd,
845 const bool preserve_energy)
846{
847 bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC_TINT;
848 bsdf->fresnel = fresnel;
849 bsdf->sample_weight *= average(bsdf_microfacet_estimate_albedo(kg, sd, bsdf, true, true));
850
851 if (preserve_energy) {
852 /* Assume that the transmissive tint makes up most of the overall color. */
853 Spectrum Fss = fresnel->transmission_tint;
854 if (is_zero(fresnel->transmission_tint)) {
855 /* For purely reflective closures, use the reflection component. */
856 Fss = fresnel_dielectric_Fss(bsdf->ior) * fresnel->reflection_tint;
857 }
858 microfacet_ggx_preserve_energy(kg, bsdf, sd, Fss);
859 }
860}
861
863 KernelGlobals kg,
865 const ccl_private ShaderData *sd,
867 const bool preserve_energy)
868{
869 fresnel->f0 = saturate(fresnel->f0);
870 bsdf->fresnel_type = MicrofacetFresnel::GENERALIZED_SCHLICK;
871 bsdf->fresnel = fresnel;
872 bsdf->sample_weight *= average(bsdf_microfacet_estimate_albedo(kg, sd, bsdf, true, true));
873
874 if (preserve_energy) {
875 Spectrum Fss = one_spectrum();
876 /* Multi-bounce Fresnel is only supported for reflective lobes here. */
877 if (is_zero(fresnel->transmission_tint)) {
878 float s;
879 if (fresnel->exponent < 0.0f) {
880 const float F0 = F0_from_ior(bsdf->ior);
881 const float Fss = fresnel_dielectric_Fss(bsdf->ior);
882 s = saturatef(inverse_lerp(F0, 1.0f, Fss));
883 }
884 else {
885 /* Integral of 2*cosI * (1 - cosI)^exponent over 0...1. */
886 s = 2.0f / ((fresnel->exponent + 3.0f) * fresnel->exponent + 2.0f);
887 }
888 /* Due to the linearity of the generalized model, this ends up working. */
889 Fss = fresnel->reflection_tint * mix(fresnel->f0, fresnel->f90, s);
890 }
891 else {
892 /* For transmissive BSDFs, assume that the transmissive tint makes up most of the overall
893 * color. */
894 Fss = fresnel->transmission_tint;
895 }
896
897 microfacet_ggx_preserve_energy(kg, bsdf, sd, Fss);
898 }
899}
900
903 const ccl_private ShaderData *sd,
905 const Spectrum f82_tint,
906 const bool preserve_energy)
907{
908 if (isequal(f82_tint, one_spectrum())) {
909 fresnel->b = zero_spectrum();
910 }
911 else {
912 fresnel->b = fresnel_f82tint_B(fresnel->f0, f82_tint);
913 }
914
915 bsdf->fresnel_type = MicrofacetFresnel::F82_TINT;
916 bsdf->fresnel = fresnel;
917 bsdf->sample_weight *= average(bsdf_microfacet_estimate_albedo(kg, sd, bsdf, true, true));
918
919 if (preserve_energy) {
920 microfacet_ggx_preserve_energy(kg, bsdf, sd, fresnel_f82_Fss(fresnel->f0, fresnel->b));
921 }
922}
923
926 const ccl_private ShaderData *sd,
927 const Spectrum color)
928{
929 /* Constant Fresnel is a special case - the color is already baked into the closure's
930 * weight, so we just need to perform the energy preservation. */
931 kernel_assert(bsdf->fresnel_type == MicrofacetFresnel::NONE ||
932 bsdf->fresnel_type == MicrofacetFresnel::DIELECTRIC);
933
934 microfacet_ggx_preserve_energy(kg, bsdf, sd, color);
935}
936
939 const ccl_private ShaderData *sd)
940{
941 bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC;
942 bsdf->sample_weight *= average(bsdf_microfacet_estimate_albedo(kg, sd, bsdf, true, true));
943
944 const float Fss = fresnel_dielectric_Fss(bsdf->ior);
946}
947
948/* GGX microfacet with Smith shadow-masking from:
949 *
950 * Microfacet Models for Refraction through Rough Surfaces
951 * B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007
952 *
953 * Anisotropic from:
954 *
955 * Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs
956 * E. Heitz, Research Report 2014
957 *
958 * Anisotropy is only supported for reflection currently, but adding it for
959 * transmission is just a matter of copying code from reflection if needed. */
960
962{
963 bsdf->alpha_x = saturatef(bsdf->alpha_x);
964 bsdf->alpha_y = saturatef(bsdf->alpha_y);
965
966 bsdf->fresnel_type = MicrofacetFresnel::NONE;
967 bsdf->energy_scale = 1.0f;
969
970 return SD_BSDF | bsdf_microfacet_eval_flag(bsdf);
971}
972
974{
975 bsdf->alpha_x = saturatef(bsdf->alpha_x);
976 bsdf->alpha_y = bsdf->alpha_x;
977
978 bsdf->fresnel_type = MicrofacetFresnel::NONE;
979 bsdf->energy_scale = 1.0f;
981
983}
984
986{
987 bsdf->alpha_x = saturatef(bsdf->alpha_x);
988 bsdf->alpha_y = bsdf->alpha_x;
989
990 bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC;
991 bsdf->energy_scale = 1.0f;
993
995}
996
997ccl_device void bsdf_microfacet_blur(ccl_private ShaderClosure *sc, const float roughness)
998{
1000
1001 bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x);
1002 bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y);
1003}
1004
1006 const ccl_private ShaderClosure *sc,
1007 const float3 wi,
1008 const float3 wo,
1009 ccl_private float *pdf)
1010{
1011 const ccl_private MicrofacetBsdf *bsdf = (const ccl_private MicrofacetBsdf *)sc;
1012 return bsdf->energy_scale * bsdf_microfacet_eval<MicrofacetType::GGX>(kg, sc, wi, wo, pdf);
1013}
1014
1016 const ccl_private ShaderClosure *sc,
1017 const float3 Ng,
1018 const float3 wi,
1019 const float3 rand,
1020 ccl_private Spectrum *eval,
1021 ccl_private float3 *wo,
1022 ccl_private float *pdf,
1023 ccl_private float2 *sampled_roughness,
1024 ccl_private float *eta)
1025{
1026
1028 kg, sc, Ng, wi, rand, eval, wo, pdf, sampled_roughness, eta);
1029 *eval *= ((const ccl_private MicrofacetBsdf *)sc)->energy_scale;
1030 return label;
1031}
1032
1033/* Beckmann microfacet with Smith shadow-masking from:
1034 *
1035 * Microfacet Models for Refraction through Rough Surfaces
1036 * B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007 */
1037
1039{
1040 bsdf->alpha_x = saturatef(bsdf->alpha_x);
1041 bsdf->alpha_y = saturatef(bsdf->alpha_y);
1042
1043 bsdf->fresnel_type = MicrofacetFresnel::NONE;
1045
1046 return SD_BSDF | bsdf_microfacet_eval_flag(bsdf);
1047}
1048
1050{
1051 bsdf->alpha_x = saturatef(bsdf->alpha_x);
1052 bsdf->alpha_y = bsdf->alpha_x;
1053
1054 bsdf->fresnel_type = MicrofacetFresnel::NONE;
1056
1058}
1059
1061{
1062 bsdf->alpha_x = saturatef(bsdf->alpha_x);
1063 bsdf->alpha_y = bsdf->alpha_x;
1064
1065 bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC;
1067
1069}
1070
1072 const ccl_private ShaderClosure *sc,
1073 const float3 wi,
1074 const float3 wo,
1075 ccl_private float *pdf)
1076{
1077 return bsdf_microfacet_eval<MicrofacetType::BECKMANN>(kg, sc, wi, wo, pdf);
1078}
1079
1081 const ccl_private ShaderClosure *sc,
1082 const float3 Ng,
1083 const float3 wi,
1084 const float3 rand,
1085 ccl_private Spectrum *eval,
1086 ccl_private float3 *wo,
1087 ccl_private float *pdf,
1088 ccl_private float2 *sampled_roughness,
1089 ccl_private float *eta)
1090{
1092 kg, sc, Ng, wi, rand, eval, wo, pdf, sampled_roughness, eta);
1093}
1094
#define D
MINLINE float signf(float f)
MINLINE float safe_sqrtf(float a)
MINLINE float safe_divide(float a, float b)
#define K(key)
#define X
#define Y
iter begin(iter)
ccl_device_forceinline float3 microfacet_beckmann_sample_vndf(const float3 wi, const float alpha_x, const float alpha_y, const float2 rand)
ccl_device void bsdf_microfacet_setup_fresnel_f82_tint(KernelGlobals kg, ccl_private MicrofacetBsdf *bsdf, const ccl_private ShaderData *sd, ccl_private FresnelF82Tint *fresnel, const Spectrum f82_tint, const bool preserve_energy)
ccl_device Spectrum bsdf_microfacet_ggx_eval(KernelGlobals kg, const ccl_private ShaderClosure *sc, const float3 wi, const float3 wo, ccl_private float *pdf)
ccl_device_inline float bsdf_lambda_from_sqr_alpha_tan_n(const float sqr_alpha_tan_n)
ccl_device int bsdf_microfacet_sample(KernelGlobals kg, const ccl_private ShaderClosure *sc, const float3 Ng, const float3 wi, const float3 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf, ccl_private float2 *sampled_roughness, ccl_private float *eta)
ccl_device_forceinline float3 microfacet_ggx_sample_vndf(const float3 wi, const float alpha_x, const float alpha_y, const float2 rand)
ccl_device Spectrum bsdf_microfacet_eval(KernelGlobals kg, const ccl_private ShaderClosure *sc, const float3 wi, const float3 wo, ccl_private float *pdf)
ccl_device Spectrum bsdf_microfacet_estimate_albedo(KernelGlobals kg, const ccl_private ShaderData *sd, const ccl_private MicrofacetBsdf *bsdf, const bool eval_reflection, const bool eval_transmission)
ccl_device int bsdf_microfacet_beckmann_glass_setup(ccl_private MicrofacetBsdf *bsdf)
ccl_device int bsdf_microfacet_beckmann_setup(ccl_private MicrofacetBsdf *bsdf)
ccl_device_forceinline int bsdf_microfacet_eval_flag(const ccl_private MicrofacetBsdf *bsdf)
ccl_device void bsdf_microfacet_setup_fresnel_constant(KernelGlobals kg, ccl_private MicrofacetBsdf *bsdf, const ccl_private ShaderData *sd, const Spectrum color)
ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals kg, const ccl_private ShaderClosure *sc, const float3 Ng, const float3 wi, const float3 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf, ccl_private float2 *sampled_roughness, ccl_private float *eta)
MicrofacetType
@ GGX
@ BECKMANN
ccl_device void bsdf_microfacet_setup_fresnel_generalized_schlick(KernelGlobals kg, ccl_private MicrofacetBsdf *bsdf, const ccl_private ShaderData *sd, ccl_private FresnelGeneralizedSchlick *fresnel, const bool preserve_energy)
ccl_device_inline float bsdf_D(const float alpha2, const float cos_NH)
ccl_device_inline float bsdf_lambda(const float alpha2, const float cos_N)
ccl_device Spectrum bsdf_microfacet_beckmann_eval(KernelGlobals kg, const ccl_private ShaderClosure *sc, const float3 wi, const float3 wo, ccl_private float *pdf)
ccl_device void bsdf_microfacet_setup_fresnel_dielectric(KernelGlobals kg, ccl_private MicrofacetBsdf *bsdf, const ccl_private ShaderData *sd)
ccl_device_inline float bsdf_G(const float alpha2, const float cos_N)
ccl_device void bsdf_microfacet_setup_fresnel_conductor(KernelGlobals kg, ccl_private MicrofacetBsdf *bsdf, const ccl_private ShaderData *sd, ccl_private FresnelConductor *fresnel, const bool preserve_energy)
ccl_device_inline void microfacet_ggx_preserve_energy(KernelGlobals kg, ccl_private MicrofacetBsdf *bsdf, const ccl_private ShaderData *sd, const Spectrum Fss)
ccl_device void bsdf_microfacet_setup_fresnel_dielectric_tint(KernelGlobals kg, ccl_private MicrofacetBsdf *bsdf, const ccl_private ShaderData *sd, ccl_private FresnelDielectricTint *fresnel, const bool preserve_energy)
ccl_device_inline float bsdf_aniso_D(const float alpha_x, const float alpha_y, float3 H)
ccl_device_inline float bsdf_aniso_lambda(const float alpha_x, const float alpha_y, const float3 V)
ccl_device int bsdf_microfacet_beckmann_refraction_setup(ccl_private MicrofacetBsdf *bsdf)
MicrofacetFresnel
@ CONDUCTOR
@ DIELECTRIC_TINT
@ GENERALIZED_SCHLICK
@ DIELECTRIC
@ NONE
@ F82_TINT
ccl_device int bsdf_microfacet_ggx_glass_setup(ccl_private MicrofacetBsdf *bsdf)
ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals kg, const ccl_private ShaderClosure *sc, const float3 Ng, const float3 wi, const float3 rand, ccl_private Spectrum *eval, ccl_private float3 *wo, ccl_private float *pdf, ccl_private float2 *sampled_roughness, ccl_private float *eta)
ccl_device int bsdf_microfacet_ggx_setup(ccl_private MicrofacetBsdf *bsdf)
ccl_device_forceinline void microfacet_fresnel(KernelGlobals kg, const ccl_private MicrofacetBsdf *bsdf, const float cos_theta_i, ccl_private float *r_cos_theta_t, ccl_private Spectrum *r_reflectance, ccl_private Spectrum *r_transmittance)
ccl_device void bsdf_microfacet_blur(ccl_private ShaderClosure *sc, const float roughness)
ccl_device int bsdf_microfacet_ggx_refraction_setup(ccl_private MicrofacetBsdf *bsdf)
ccl_device Spectrum fresnel_conductor(const float cosi, const complex< Spectrum > ior)
Definition bsdf_util.h:194
ccl_device Spectrum fresnel_iridescence(KernelGlobals kg, const float ambient_ior, const FresnelThinFilm thin_film, const complex< SpectrumOrFloat > substrate_ior, ccl_private const Spectrum *F82, const float cos_theta_1, ccl_private float *r_cos_theta_3)
Definition bsdf_util.h:484
ccl_device_inline Spectrum fresnel_conductor_Fss(const complex< Spectrum > ior)
Definition bsdf_util.h:241
ccl_device float F0_from_ior(const float ior)
Definition bsdf_util.h:256
ccl_device_inline Spectrum fresnel_f82_Fss(const Spectrum F0, const Spectrum B)
Definition bsdf_util.h:202
ccl_device_inline float fresnel_dielectric_Fss(const float eta)
Definition bsdf_util.h:130
ccl_device_forceinline float fresnel_dielectric(const float cos_theta_i, const float eta, ccl_private float *r_cos_theta_t)
Definition bsdf_util.h:93
ccl_device_inline float3 refract_angle(const float3 incident, const float3 normal, const float cos_theta_t, const float inv_eta)
Definition bsdf_util.h:102
ccl_device_inline Spectrum fresnel_f82(const float cosi, const Spectrum F0, const Spectrum B)
Definition bsdf_util.h:232
ccl_device_inline Spectrum fresnel_f82tint_B(const Spectrum F0, const Spectrum tint)
Definition bsdf_util.h:208
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
nullptr float
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
ccl_device_inline float3 disk_to_hemisphere(const float2 p)
ccl_device_inline T to_global(const float2 p, const T X, const T Y)
ccl_device_inline float2 polar_to_cartesian(const float r, const float phi)
#define kernel_assert(cond)
#define CLOSURE_IS_GLASS(type)
#define kernel_data
#define THINFILM_THICKNESS_CUTOFF
#define ccl_device_forceinline
#define one_spectrum
#define zero_spectrum
#define make_spectrum(f)
#define ccl_private
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define M_1_PI_F
#define FOREACH_SPECTRUM_CHANNEL(counter)
#define CLOSURE_IS_REFRACTION(type)
#define GET_SPECTRUM_CHANNEL(v, i)
#define BSDF_ROUGHNESS_SQ_THRESH
#define logf(x)
#define expf(x)
#define powf(x, y)
#define CCL_NAMESPACE_END
#define saturatef(x)
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define common
VecBase< float, D > normalize(VecOp< float, D >) RET
#define sqrt
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
@ CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID
@ CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID
@ CLOSURE_BSDF_MICROFACET_GGX_ID
@ CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID
@ CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID
@ CLOSURE_BSDF_MICROFACET_BECKMANN_ID
@ SD_BSDF_HAS_EVAL
@ SD_BSDF
@ SD_BSDF_HAS_TRANSMISSION
@ LABEL_TRANSMIT
@ LABEL_NONE
@ LABEL_SINGULAR
@ LABEL_GLOSSY
@ LABEL_REFLECT
ccl_device float lookup_table_read_2D(KernelGlobals kg, const float x, float y, const int offset, const int xsize, const int ysize)
ccl_device float lookup_table_read_3D(KernelGlobals kg, const float x, float y, float z, const int offset, const int xsize, const int ysize, const int zsize)
CCL_NAMESPACE_BEGIN ccl_device float lookup_table_read(KernelGlobals kg, float x, const int offset, const int size)
ccl_device_inline float inversesqrtf(const float f)
Definition math_base.h:529
ccl_device_inline float sin_from_cos(const float c)
Definition math_base.h:609
ccl_device_inline float inverse_lerp(const float a, const float b, const float x)
Definition math_base.h:507
ccl_device_inline float fast_erff(const float x)
Definition math_fast.h:568
ccl_device_inline float fast_ierff(const float x)
Definition math_fast.h:603
ccl_device_inline float len_squared(const float2 a)
ccl_device_inline bool is_zero(const float2 a)
ccl_device_inline bool isequal(const float2 a, const float2 b)
ccl_device_inline void make_orthonormals(const float3 N, ccl_private float3 *a, ccl_private float3 *b)
#define N
#define F
#define T2
Definition md5.cpp:21
#define T1
Definition md5.cpp:20
#define H(x, y, z)
float average(point a)
Definition node_math.h:144
float safe_sqrt(float a)
Definition node_math.h:81
#define mix
#define sqr
#define fabsf
#define sqrtf
#define ccl_device
#define M_2PI_F
#define fmaxf
#define make_float2
#define M_PI_F
CCL_NAMESPACE_BEGIN ccl_device float2 sample_uniform_disk(const float2 rand)
ccl_device void make_orthonormals_tangent(const float3 N, const float3 T, ccl_private float3 *a, ccl_private float3 *b)
#define saturate(a)
Definition smaa.cc:315
#define min(a, b)
Definition sort.cc:36
complex< Spectrum > ior
FresnelThinFilm thin_film
FresnelThinFilm thin_film
FresnelThinFilm thin_film
ccl_private void * fresnel
float x
float y
float z
Definition sky_math.h:136
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
float3 Spectrum
uint len
CCL_NAMESPACE_BEGIN struct Window V