diff options
36 files changed, 4534 insertions, 2547 deletions
diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt index 1c7a861ea93..b8523d917a7 100644 --- a/intern/cycles/app/CMakeLists.txt +++ b/intern/cycles/app/CMakeLists.txt @@ -62,6 +62,7 @@ include_directories(SYSTEM ${INC_SYS}) if(WITH_CYCLES_STANDALONE) set(SRC cycles_standalone.cpp + cycles_precompute.cpp cycles_xml.cpp cycles_xml.h oiio_output_driver.cpp diff --git a/intern/cycles/app/cycles_precompute.cpp b/intern/cycles/app/cycles_precompute.cpp new file mode 100644 index 00000000000..6f9d9601b1e --- /dev/null +++ b/intern/cycles/app/cycles_precompute.cpp @@ -0,0 +1,400 @@ +#include "util/math.h" +#include "util/string.h" +#include "util/system.h" + +#include "util/hash.h" +#include "util/task.h" + +#include "kernel/device/cpu/compat.h" +#include "kernel/device/cpu/globals.h" + +#include "kernel/sample/lcg.h" +#include "kernel/sample/mapping.h" + +#include "kernel/closure/bsdf_microfacet.h" +#include "kernel/closure/bsdf_microfacet_glass.h" +#include "kernel/closure/bsdf_principled_sheen.h" + +#include <iostream> + +CCL_NAMESPACE_BEGIN + +/* From PBRT: core/montecarlo.h */ +inline float VanDerCorput(uint32_t n, uint32_t scramble) +{ + n = (n << 16) | (n >> 16); + n = ((n & 0x00ff00ff) << 8) | ((n & 0xff00ff00) >> 8); + n = ((n & 0x0f0f0f0f) << 4) | ((n & 0xf0f0f0f0) >> 4); + n = ((n & 0x33333333) << 2) | ((n & 0xcccccccc) >> 2); + n = ((n & 0x55555555) << 1) | ((n & 0xaaaaaaaa) >> 1); + n ^= scramble; + return ((n >> 8) & 0xffffff) / float(1 << 24); +} +inline float Sobol2(uint32_t n, uint32_t scramble) +{ + for (uint32_t v = 1 << 31; n != 0; n >>= 1, v ^= v >> 1) + if (n & 0x1) + scramble ^= v; + return ((scramble >> 8) & 0xffffff) / float(1 << 24); +} + +static float precompute_sheen_E(float rough, float mu, float u1, float u2) +{ + PrincipledSheenBsdf bsdf; + bsdf.weight = one_float3(); + bsdf.type = CLOSURE_BSDF_PRINCIPLED_SHEEN_V2_ID; + bsdf.sample_weight = 1.0f; + bsdf.N = make_float3(0.0f, 0.0f, 1.0f); + bsdf.roughness = sqr(rough); + + float3 eval, omega_in, domega_in_dx, domega_in_dy; + float pdf = 0.0f; + bsdf_principled_sheen_sample((ShaderClosure *)&bsdf, + make_float3(0.0f, 0.0f, 1.0f), + make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu), + zero_float3(), + zero_float3(), + u1, + u2, + &eval, + &omega_in, + &domega_in_dx, + &domega_in_dy, + &pdf); + if (pdf != 0.0f) { + return clamp(average(eval) / pdf, 0.0f, 1e5f); + } + return 0.0f; +} + +static float precompute_clearcoat_E(float rough, float mu, float u1, float u2) +{ + MicrofacetBsdf bsdf; + bsdf.weight = one_float3(); + bsdf.type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_V2_ID; + bsdf.sample_weight = 1.0f; + bsdf.N = make_float3(0.0f, 0.0f, 1.0f); + bsdf.alpha_x = bsdf.alpha_y = sqr(rough); + bsdf.ior = 1.5f; + bsdf.extra = nullptr; + bsdf.T = make_float3(1.0f, 0.0f, 0.0f); + + /* Account for the albedo scaling that the closure performs. + * Dependency warning - this relies on the ggx_E and ggx_E_avg lookup tables! */ + float E = microfacet_ggx_E(mu, rough), E_avg = microfacet_ggx_E_avg(rough); + float Fss = dielectric_fresnel_Fss(1.5f); + float Fms = Fss * E_avg / (1.0f - Fss * (1.0f - E_avg)); + float albedo_scale = 1.0f + Fms * ((1.0f - E) / E); + + float3 eval, omega_in, domega_in_dx, domega_in_dy; + float pdf = 0.0f; + bsdf_microfacet_ggx_sample((ShaderClosure *)&bsdf, + make_float3(0.0f, 0.0f, 1.0f), + make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu), + zero_float3(), + zero_float3(), + u1, + u2, + &eval, + &omega_in, + &domega_in_dx, + &domega_in_dy, + &pdf); + if (pdf != 0.0f) { + /* Encode relative to macrosurface Fresnel, saves resolution. + * TODO: Worth the extra evaluation? */ + return albedo_scale * (average(eval) / pdf) / fresnel_dielectric_cos(mu, 1.5f); + } + return 0.0f; +} + +static float precompute_ggx_E(float rough, float mu, float u1, float u2) +{ + MicrofacetBsdf bsdf; + bsdf.weight = one_float3(); + bsdf.type = CLOSURE_BSDF_MICROFACET_GGX_ID; + bsdf.sample_weight = 1.0f; + bsdf.N = make_float3(0.0f, 0.0f, 1.0f); + bsdf.alpha_x = bsdf.alpha_y = sqr(rough); + bsdf.ior = 1.0f; + bsdf.extra = nullptr; + bsdf.T = make_float3(1.0f, 0.0f, 0.0f); + + float3 eval, omega_in, domega_in_dx, domega_in_dy; + float pdf = 0.0f; + bsdf_microfacet_ggx_sample((ShaderClosure *)&bsdf, + make_float3(0.0f, 0.0f, 1.0f), + make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu), + zero_float3(), + zero_float3(), + u1, + u2, + &eval, + &omega_in, + &domega_in_dx, + &domega_in_dy, + &pdf); + if (pdf != 0.0f) { + return average(eval) / pdf; + } + return 0.0f; +} + +static float precompute_ggx_refract_E(float rough, float mu, float eta, float u1, float u2) +{ + MicrofacetBsdf bsdf; + bsdf.weight = one_float3(); + bsdf.type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; + bsdf.sample_weight = 1.0f; + bsdf.N = make_float3(0.0f, 0.0f, 1.0f); + bsdf.alpha_x = bsdf.alpha_y = sqr(rough); + bsdf.ior = eta; + bsdf.extra = nullptr; + bsdf.T = make_float3(1.0f, 0.0f, 0.0f); + + float3 eval, omega_in, domega_in_dx, domega_in_dy; + float pdf = 0.0f; + bsdf_microfacet_ggx_sample((ShaderClosure *)&bsdf, + make_float3(0.0f, 0.0f, 1.0f), + make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu), + zero_float3(), + zero_float3(), + u1, + u2, + &eval, + &omega_in, + &domega_in_dx, + &domega_in_dy, + &pdf); + if (pdf != 0.0f) { + return average(eval) / pdf; + } + return 0.0f; +} + +static float precompute_ggx_glass_E(float rough, float mu, float eta, float u1, float u2) +{ + MicrofacetBsdf bsdf; + bsdf.weight = one_float3(); + bsdf.type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + bsdf.sample_weight = 1.0f; + bsdf.N = make_float3(0.0f, 0.0f, 1.0f); + bsdf.alpha_x = bsdf.alpha_y = sqr(rough); + bsdf.ior = eta; + bsdf.extra = nullptr; + bsdf.T = make_float3(1.0f, 0.0f, 0.0f); + + float3 eval, omega_in, domega_in_dx, domega_in_dy; + float pdf = 0.0f; + bsdf_microfacet_ggx_glass_sample((ShaderClosure *)&bsdf, + make_float3(0.0f, 0.0f, 1.0f), + make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu), + zero_float3(), + zero_float3(), + u1, + u2, + &eval, + &omega_in, + &domega_in_dx, + &domega_in_dy, + &pdf); + if (pdf != 0.0f) { + return average(eval) / pdf; + } + return 0.0f; +} + +static float precompute_ggx_dielectric_E(float rough, float mu, float eta, float u1, float u2) +{ + { + /* Reparametrize based on macrosurface fresnel to get more resolution into areas where + * the Fresnel curve is rapidly changing. Particularly important for eta<1 due to the TIR edge. + * However, in the eta<1 case, the entire TIR area would be compressed down to a point, which + * is an issue since there are changes in that range at higher roughnesses. + * Therefore, the remapping is blended with the identity function for a compromise. + */ + float F0 = fresnel_dielectric_cos(1.0f, eta); + auto get_remap = [eta, F0](float x) { + return mix(x, inverse_lerp(1.0f, F0, fresnel_dielectric_cos(x, eta)), 0.5f); + }; + + float remap_target = mu; + float start = 0.0f, end = 1.0f; + while (end - start > 1e-7f) { + mu = (end + start) * 0.5f; + if (get_remap(mu) > remap_target) { + end = mu; + } + else { + start = mu; + } + } + } + + MicrofacetExtrav2 extra; + MicrofacetBsdf bsdf; + bsdf.weight = one_float3(); + bsdf.type = CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_V2_ID; + bsdf.sample_weight = 1.0f; + bsdf.N = make_float3(0.0f, 0.0f, 1.0f); + bsdf.alpha_x = bsdf.alpha_y = sqr(rough); + bsdf.ior = eta; + bsdf.extra = (MicrofacetExtra *)&extra; + bsdf.T = make_float3(1.0f, 0.0f, 0.0f); + extra.metallic = extra.metal_base = extra.metal_edge_factor = zero_float3(); + + /* Dependency warning - this relies on the ggx_E and ggx_E_avg lookup tables! */ + float E = microfacet_ggx_E(mu, rough), E_avg = microfacet_ggx_E_avg(rough); + float Fss = dielectric_fresnel_Fss(eta); + float Fms = Fss * E_avg / (1.0f - Fss * (1.0f - E_avg)); + extra.dielectric = 1.0f + Fms * ((1.0f - E) / E); + + float3 eval, omega_in, domega_in_dx, domega_in_dy; + float pdf = 0.0f; + bsdf_microfacet_ggx_sample((ShaderClosure *)&bsdf, + make_float3(0.0f, 0.0f, 1.0f), + make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu), + zero_float3(), + zero_float3(), + u1, + u2, + &eval, + &omega_in, + &domega_in_dx, + &domega_in_dy, + &pdf); + if (pdf != 0.0f) { + return average(eval) / pdf; + } + return 0.0f; +} + +struct PrecomputeTerm { + int dim, samples, res; + std::function<float(float, float, float, float, float)> evaluation; +}; + +bool cycles_precompute(std::string name); +bool cycles_precompute(std::string name) +{ + std::map<string, PrecomputeTerm> precompute_terms; + precompute_terms["sheen_E"] = { + 2, 1 << 23, 32, [](float rough, float mu, float ior, float u1, float u2) { + return precompute_sheen_E(rough, mu, u1, u2); + }}; + precompute_terms["clearcoat_E"] = { + 2, 1 << 23, 16, [](float rough, float mu, float ior, float u1, float u2) { + return precompute_clearcoat_E(rough, mu, u1, u2); + }}; + precompute_terms["ggx_E"] = { + 2, 1 << 23, 32, [](float rough, float mu, float ior, float u1, float u2) { + return precompute_ggx_E(rough, mu, u1, u2); + }}; + precompute_terms["ggx_E_avg"] = { + 1, 1 << 23, 32, [](float rough, float mu, float ior, float u1, float u2) { + return 2.0f * mu * precompute_ggx_E(rough, mu, u1, u2); + }}; + precompute_terms["ggx_glass_E"] = { + 3, 1 << 20, 16, [](float rough, float mu, float ior, float u1, float u2) { + return precompute_ggx_glass_E(rough, mu, ior, u1, u2); + }}; + precompute_terms["ggx_glass_inv_E"] = { + 3, 1 << 20, 16, [](float rough, float mu, float ior, float u1, float u2) { + return precompute_ggx_glass_E(rough, mu, 1.0f / ior, u1, u2); + }}; + precompute_terms["ggx_refract_E"] = { + 3, 1 << 20, 16, [](float rough, float mu, float ior, float u1, float u2) { + return precompute_ggx_refract_E(rough, mu, ior, u1, u2); + }}; + precompute_terms["ggx_refract_inv_E"] = { + 3, 1 << 20, 16, [](float rough, float mu, float ior, float u1, float u2) { + return precompute_ggx_refract_E(rough, mu, 1.0f / ior, u1, u2); + }}; + precompute_terms["ggx_dielectric_E"] = { + 3, 1 << 20, 16, [](float rough, float mu, float ior, float u1, float u2) { + return precompute_ggx_dielectric_E(rough, mu, ior, u1, u2); + }}; + // TODO: Consider more X resolution for this table. + precompute_terms["ggx_dielectric_inv_E"] = { + 3, 1 << 20, 16, [](float rough, float mu, float ior, float u1, float u2) { + return precompute_ggx_dielectric_E(rough, mu, 1.0f / ior, u1, u2); + }}; + + if (precompute_terms.count(name) == 0) { + return false; + } + + const PrecomputeTerm &term = precompute_terms[name]; + + const int samples = term.samples; + const int res = term.res; + const int nz = (term.dim > 2) ? res : 1, ny = res, nx = (term.dim > 1) ? res : 1; + + if (nz > 1) { + std::cout << "static const float table_" << name << "[" << nz << "][" << ny << "][" << nx + << "] = {" << std::endl; + } + for (int z = 0; z < nz; z++) { + float *data = new float[nx * ny]; + parallel_for(0, ny, [&](int64_t y) { + for (int x = 0; x < nx; x++) { + uint rng = hash_uint2(x, y); + uint scramble1 = lcg_step_uint(&rng), scramble2 = lcg_step_uint(&rng); + double sum = 0.0; + for (int i = 0; i < samples; i++) { + float rough = 1.0f - (float(y) + lcg_step_float(&rng)) / float(ny); + float mu = (float(x) + lcg_step_float(&rng)) / float(nx); + float ior = (float(z) + lcg_step_float(&rng)) / float(nz); + /* Encode IOR remapped as sqrt(0.5*(IOR-1)) for more resolution at the start, where most + * of the changes happen (also places the most common range around 1.5 in the center) */ + ior = 1.0f + 2.0f * sqr(ior); + float u1 = VanDerCorput(i, scramble1); + float u2 = Sobol2(i, scramble2); + + float value = term.evaluation(rough, mu, ior, u1, u2); + if (isnan(value)) { + value = 0.0f; + } + sum += (double)value; + } + data[y * nx + x] = float(sum / double(samples)); + } + }); + + string filename = name; + if (nz > 1) { + filename += string_printf("_%02d", z); + std::cout << " {" << std::endl; + } + else { + std::cout << "static const float table_" << name << "[" << ny << "][" << nx << "] = {" + << std::endl; + } + + for (int y = 0; y < ny; y++) { + std::cout << " {"; + for (int x = 0; x < nx; x++) { + std::cout << data[y * nx + x] << ((x + 1 == nx) ? "f" : "f, "); + } + std::cout << ((y + 1 == ny) ? "}" : "},") << std::endl; + } + if (nz > 1) { + std::cout << ((z + 1 == nz) ? " }" : " },") << std::endl; + } + else { + std::cout << "};" << std::endl; + } + + FILE *f = fopen((filename + ".pfm").c_str(), "w"); + fprintf(f, "Pf\n%d %d\n-1.0\n", nx, ny); + fwrite(data, sizeof(float), nx * ny, f); + fclose(f); + } + if (nz > 1) { + std::cout << "};" << std::endl; + } + + return true; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp index 8b40adc8d92..6184b4ad445 100644 --- a/intern/cycles/app/cycles_standalone.cpp +++ b/intern/cycles/app/cycles_standalone.cpp @@ -37,6 +37,8 @@ CCL_NAMESPACE_BEGIN +bool cycles_precompute(std::string name); + struct Options { Session *session; Scene *scene; @@ -536,6 +538,10 @@ int main(int argc, const char **argv) path_init(); options_parse(argc, argv); + if (cycles_precompute(options.filepath)) { + return 0; + } + #ifdef WITH_CYCLES_STANDALONE_GUI if (options.session_params.background) { #endif diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp index dbc49df7f22..d749686d449 100644 --- a/intern/cycles/blender/shader.cpp +++ b/intern/cycles/blender/shader.cpp @@ -662,6 +662,9 @@ static ShaderNode *add_node(Scene *scene, principled->set_distribution(CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); break; case BL::ShaderNodeBsdfPrincipled::distribution_MULTI_GGX: + principled->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); + break; + case BL::ShaderNodeBsdfPrincipled::distribution_V2: principled->set_distribution(CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); break; } diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 81c5f593974..e7a94f00ffb 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -103,8 +103,9 @@ set(SRC_KERNEL_CLOSURE_HEADERS closure/bsdf_diffuse.h closure/bsdf_diffuse_ramp.h closure/bsdf_microfacet.h - closure/bsdf_microfacet_multi.h - closure/bsdf_microfacet_multi_impl.h + closure/bsdf_microfacet_beckmann.h + closure/bsdf_microfacet_glass.h + closure/bsdf_microfacet_util.h closure/bsdf_oren_nayar.h closure/bsdf_phong_ramp.h closure/bsdf_reflection.h @@ -133,6 +134,7 @@ set(SRC_KERNEL_SVM_HEADERS svm/camera.h svm/clamp.h svm/closure.h + svm/closure_principled.h svm/convert.h svm/checker.h svm/color_util.h @@ -547,7 +549,8 @@ endif() # HIP module -if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP) +# TODO: Re-enable HIP and figure out compiler crash +if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP AND FALSE) # build for each arch set(hip_sources device/hip/kernel.cpp ${SRC_KERNEL_HEADERS} diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index 71af68aa80e..fbda52d74c4 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -10,7 +10,8 @@ #include "kernel/closure/bsdf_phong_ramp.h" #include "kernel/closure/bsdf_diffuse_ramp.h" #include "kernel/closure/bsdf_microfacet.h" -#include "kernel/closure/bsdf_microfacet_multi.h" +#include "kernel/closure/bsdf_microfacet_beckmann.h" +#include "kernel/closure/bsdf_microfacet_glass.h" #include "kernel/closure/bsdf_reflection.h" #include "kernel/closure/bsdf_refraction.h" #include "kernel/closure/bsdf_transparent.h" @@ -168,40 +169,17 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg, break; case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID: + case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_V2_ID: case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: + case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_V2_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: label = bsdf_microfacet_ggx_sample( - kg, sc, Ng, sd->I, randu, randv, eval, omega_in, pdf, sampled_roughness, eta); - break; - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID: - label = bsdf_microfacet_multi_ggx_sample(kg, - sc, - Ng, - sd->I, - randu, - randv, - eval, - omega_in, - pdf, - &sd->lcg_state, - sampled_roughness, - eta); + sc, Ng, sd->I, randu, randv, eval, omega_in, pdf, sampled_roughness, eta); break; case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID: - label = bsdf_microfacet_multi_ggx_glass_sample(kg, - sc, - Ng, - sd->I, - randu, - randv, - eval, - omega_in, - pdf, - &sd->lcg_state, - sampled_roughness, - eta); + label = bsdf_microfacet_ggx_glass_sample( + sc, Ng, sd->I, randu, randv, eval, omega_in, pdf, sampled_roughness, eta); break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -249,6 +227,7 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg, *eta = 1.0f; break; case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID: + case CLOSURE_BSDF_PRINCIPLED_SHEEN_V2_ID: label = bsdf_principled_sheen_sample(sc, Ng, sd->I, randu, randv, eval, omega_in, pdf); *sampled_roughness = one_float2(); *eta = 1.0f; @@ -343,7 +322,9 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg, break; case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID: + case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_V2_ID: case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: + case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_V2_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: { ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; *roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y); @@ -351,13 +332,6 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg, *eta = refractive ? 1.0f / bsdf->ior : bsdf->ior; break; } - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID: { - ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; - *roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y); - *eta = bsdf->ior; - break; - } case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID: { ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; @@ -411,6 +385,7 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg, *eta = 1.0f; break; case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID: + case CLOSURE_BSDF_PRINCIPLED_SHEEN_V2_ID: *roughness = one_float2(); *eta = 1.0f; break; @@ -462,9 +437,9 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg, break; case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID: + case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_V2_ID: case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID: + case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_V2_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: { ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; label = (bsdf->alpha_x * bsdf->alpha_y <= 1e-7f) ? LABEL_REFLECT | LABEL_SINGULAR : @@ -511,6 +486,7 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg, label = LABEL_REFLECT | LABEL_DIFFUSE; break; case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID: + case CLOSURE_BSDF_PRINCIPLED_SHEEN_V2_ID: label = LABEL_REFLECT | LABEL_DIFFUSE; break; #endif @@ -576,17 +552,15 @@ ccl_device_inline break; case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID: + case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_V2_ID: case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: + case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_V2_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: eval = bsdf_microfacet_ggx_eval(sc, sd->I, omega_in, pdf); break; - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID: - eval = bsdf_microfacet_multi_ggx_eval(sc, sd->I, omega_in, pdf, &sd->lcg_state); - break; case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID: - eval = bsdf_microfacet_multi_ggx_glass_eval(sc, sd->I, omega_in, pdf, &sd->lcg_state); + eval = bsdf_microfacet_ggx_glass_eval(sc, sd->I, omega_in, pdf); break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -617,6 +591,7 @@ ccl_device_inline eval = bsdf_principled_diffuse_eval(sc, sd->I, omega_in, pdf); break; case CLOSURE_BSDF_PRINCIPLED_SHEEN_ID: + case CLOSURE_BSDF_PRINCIPLED_SHEEN_V2_ID: eval = bsdf_principled_sheen_eval(sc, sd->I, omega_in, pdf); break; #endif @@ -652,16 +627,14 @@ ccl_device void bsdf_blur(KernelGlobals kg, ccl_private ShaderClosure *sc, float /* TODO: do we want to blur volume closures? */ #if defined(__SVM__) || defined(__OSL__) switch (sc->type) { - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID: - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID: - bsdf_microfacet_multi_ggx_blur(sc, roughness); - break; case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID: + case CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_V2_ID: case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: + case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_V2_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID: bsdf_microfacet_ggx_blur(sc, roughness); break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: diff --git a/intern/cycles/kernel/closure/bsdf_hair_principled.h b/intern/cycles/kernel/closure/bsdf_hair_principled.h index 857b3fbf3a6..f5651d82aae 100644 --- a/intern/cycles/kernel/closure/bsdf_hair_principled.h +++ b/intern/cycles/kernel/closure/bsdf_hair_principled.h @@ -7,6 +7,7 @@ # include <fenv.h> #endif +#include "kernel/sample/lcg.h" #include "kernel/util/color.h" CCL_NAMESPACE_BEGIN diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index 4eb7cd5df22..e0b513b69f1 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -8,20 +8,27 @@ #pragma once -#include "kernel/closure/bsdf_util.h" - -#include "kernel/sample/pattern.h" - -#include "kernel/util/lookup_table.h" +#include "kernel/closure/bsdf_microfacet_util.h" CCL_NAMESPACE_BEGIN typedef struct MicrofacetExtra { Spectrum color, cspec0; Spectrum fresnel_color; - float clearcoat; } MicrofacetExtra; +typedef struct MicrofacetExtrav2 { + /* Metallic fresnel control */ + Spectrum metal_base, metal_edge_factor; + Spectrum metallic; + float dielectric; +} MicrofacetExtrav2; + +// TODO probably remove this for the final code +static_assert(sizeof(MicrofacetExtra) <= sizeof(ShaderClosure), "Try to shrink MicrofacetExtra!"); +static_assert(sizeof(MicrofacetExtrav2) <= sizeof(ShaderClosure), + "Try to shrink MicrofacetExtra!"); + typedef struct MicrofacetBsdf { SHADER_CLOSURE_BASE; @@ -32,200 +39,6 @@ typedef struct MicrofacetBsdf { static_assert(sizeof(ShaderClosure) >= sizeof(MicrofacetBsdf), "MicrofacetBsdf is too large!"); -/* Beckmann and GGX microfacet importance sampling. */ - -ccl_device_inline void microfacet_beckmann_sample_slopes(KernelGlobals kg, - const float cos_theta_i, - const float sin_theta_i, - float randu, - float randv, - ccl_private float *slope_x, - ccl_private float *slope_y, - ccl_private float *G1i) -{ - /* special case (normal incidence) */ - if (cos_theta_i >= 0.99999f) { - const float r = sqrtf(-logf(randu)); - const float phi = M_2PI_F * randv; - *slope_x = r * cosf(phi); - *slope_y = r * sinf(phi); - *G1i = 1.0f; - return; - } - - /* precomputations */ - const float tan_theta_i = sin_theta_i / cos_theta_i; - const float inv_a = tan_theta_i; - const float cot_theta_i = 1.0f / tan_theta_i; - const float erf_a = fast_erff(cot_theta_i); - const float exp_a2 = expf(-cot_theta_i * cot_theta_i); - const float SQRT_PI_INV = 0.56418958354f; - const float Lambda = 0.5f * (erf_a - 1.0f) + (0.5f * SQRT_PI_INV) * (exp_a2 * inv_a); - const float G1 = 1.0f / (1.0f + Lambda); /* masking */ - - *G1i = G1; - -#if defined(__KERNEL_GPU__) - /* Based on paper from Wenzel Jakob - * An Improved Visible Normal Sampling Routine for the Beckmann Distribution - * - * http://www.mitsuba-renderer.org/~wenzel/files/visnormal.pdf - * - * Reformulation from OpenShadingLanguage which avoids using inverse - * trigonometric functions. - */ - - /* Sample slope X. - * - * Compute a coarse approximation using the approximation: - * exp(-ierf(x)^2) ~= 1 - x * x - * solve y = 1 + b + K * (1 - b * b) - */ - float K = tan_theta_i * SQRT_PI_INV; - float y_approx = randu * (1.0f + erf_a + K * (1 - erf_a * erf_a)); - float y_exact = randu * (1.0f + erf_a + K * exp_a2); - float b = K > 0 ? (0.5f - sqrtf(K * (K - y_approx + 1.0f) + 0.25f)) / K : y_approx - 1.0f; - - /* Perform newton step to refine toward the true root. */ - float inv_erf = fast_ierff(b); - float value = 1.0f + b + K * expf(-inv_erf * inv_erf) - y_exact; - /* Check if we are close enough already, - * this also avoids NaNs as we get close to the root. - */ - if (fabsf(value) > 1e-6f) { - b -= value / (1.0f - inv_erf * tan_theta_i); /* newton step 1. */ - inv_erf = fast_ierff(b); - value = 1.0f + b + K * expf(-inv_erf * inv_erf) - y_exact; - b -= value / (1.0f - inv_erf * tan_theta_i); /* newton step 2. */ - /* Compute the slope from the refined value. */ - *slope_x = fast_ierff(b); - } - else { - /* We are close enough already. */ - *slope_x = inv_erf; - } - *slope_y = fast_ierff(2.0f * randv - 1.0f); -#else - /* Use precomputed table on CPU, it gives better performance. */ - int beckmann_table_offset = kernel_data.tables.beckmann_offset; - - *slope_x = lookup_table_read_2D( - kg, randu, cos_theta_i, beckmann_table_offset, BECKMANN_TABLE_SIZE, BECKMANN_TABLE_SIZE); - *slope_y = fast_ierff(2.0f * randv - 1.0f); -#endif -} - -/* GGX microfacet importance sampling from: - * - * Importance Sampling Microfacet-Based BSDFs using the Distribution of Visible Normals. - * E. Heitz and E. d'Eon, EGSR 2014 - */ - -ccl_device_inline void microfacet_ggx_sample_slopes(const float cos_theta_i, - const float sin_theta_i, - float randu, - float randv, - ccl_private float *slope_x, - ccl_private float *slope_y, - ccl_private float *G1i) -{ - /* special case (normal incidence) */ - if (cos_theta_i >= 0.99999f) { - const float r = sqrtf(randu / (1.0f - randu)); - const float phi = M_2PI_F * randv; - *slope_x = r * cosf(phi); - *slope_y = r * sinf(phi); - *G1i = 1.0f; - - return; - } - - /* precomputations */ - const float tan_theta_i = sin_theta_i / cos_theta_i; - const float G1_inv = 0.5f * (1.0f + safe_sqrtf(1.0f + tan_theta_i * tan_theta_i)); - - *G1i = 1.0f / G1_inv; - - /* sample slope_x */ - const float A = 2.0f * randu * G1_inv - 1.0f; - const float AA = A * A; - const float tmp = 1.0f / (AA - 1.0f); - const float B = tan_theta_i; - const float BB = B * B; - const float D = safe_sqrtf(BB * (tmp * tmp) - (AA - BB) * tmp); - const float slope_x_1 = B * tmp - D; - const float slope_x_2 = B * tmp + D; - *slope_x = (A < 0.0f || slope_x_2 * tan_theta_i > 1.0f) ? slope_x_1 : slope_x_2; - - /* sample slope_y */ - float S; - - if (randv > 0.5f) { - S = 1.0f; - randv = 2.0f * (randv - 0.5f); - } - else { - S = -1.0f; - randv = 2.0f * (0.5f - randv); - } - - const float z = (randv * (randv * (randv * 0.27385f - 0.73369f) + 0.46341f)) / - (randv * (randv * (randv * 0.093073f + 0.309420f) - 1.000000f) + 0.597999f); - *slope_y = S * z * safe_sqrtf(1.0f + (*slope_x) * (*slope_x)); -} - -ccl_device_forceinline float3 microfacet_sample_stretched(KernelGlobals kg, - const float3 omega_i, - const float alpha_x, - const float alpha_y, - const float randu, - const float randv, - bool beckmann, - ccl_private float *G1i) -{ - /* 1. stretch omega_i */ - float3 omega_i_ = make_float3(alpha_x * omega_i.x, alpha_y * omega_i.y, omega_i.z); - omega_i_ = normalize(omega_i_); - - /* get polar coordinates of omega_i_ */ - float costheta_ = 1.0f; - float sintheta_ = 0.0f; - float cosphi_ = 1.0f; - float sinphi_ = 0.0f; - - if (omega_i_.z < 0.99999f) { - costheta_ = omega_i_.z; - sintheta_ = safe_sqrtf(1.0f - costheta_ * costheta_); - - float invlen = 1.0f / sintheta_; - cosphi_ = omega_i_.x * invlen; - sinphi_ = omega_i_.y * invlen; - } - - /* 2. sample P22_{omega_i}(x_slope, y_slope, 1, 1) */ - float slope_x, slope_y; - - if (beckmann) { - microfacet_beckmann_sample_slopes( - kg, costheta_, sintheta_, randu, randv, &slope_x, &slope_y, G1i); - } - else { - microfacet_ggx_sample_slopes(costheta_, sintheta_, randu, randv, &slope_x, &slope_y, G1i); - } - - /* 3. rotate */ - float tmp = cosphi_ * slope_x - sinphi_ * slope_y; - slope_y = sinphi_ * slope_x + cosphi_ * slope_y; - slope_x = tmp; - - /* 4. unstretch */ - slope_x = alpha_x * slope_x; - slope_y = alpha_y * slope_y; - - /* 5. compute normal */ - return normalize(make_float3(-slope_x, -slope_y, 1.0f)); -} - /* Calculate the reflection color * * If fresnel is used, the color is an interpolation of the F0 color and white @@ -237,55 +50,77 @@ ccl_device_forceinline Spectrum reflection_color(ccl_private const MicrofacetBsd float3 L, float3 H) { - Spectrum F = one_spectrum(); - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID || - bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID); - if (use_fresnel) { - float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); - - F = interpolate_fresnel_color(L, H, bsdf->ior, F0, bsdf->extra->cspec0); + if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID) { + return interpolate_fresnel_color(L, H, bsdf->ior, bsdf->extra->cspec0); + } + else if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { + return interpolate_fresnel_color(L, H, bsdf->ior, make_spectrum(0.04f)); + } + else if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_V2_ID) { + float f = fresnel_dielectric_cos(dot(H, L), bsdf->ior); + return make_spectrum(f); + } + else if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_V2_ID) { + MicrofacetExtrav2 *extra = (MicrofacetExtrav2 *)bsdf->extra; + float cosHL = dot(H, L); + /* Metallic Fresnel: Kinda Schlick-Fresnel-like with configurable F0 and F90 + * as well as falloff control. F90=white and falloff=0.2 gives classic Schlick Fresnel. + * Metallic factor and albedo scaling is baked into the F0 and F90 parameters. */ + Spectrum metallic = extra->metallic * + fresnel_metallic(extra->metal_base, extra->metal_edge_factor, cosHL); + /* Dielectric Fresnel, just basic IOR control. */ + float dielectric = extra->dielectric * fresnel_dielectric_cos(cosHL, bsdf->ior); + + return metallic + make_spectrum(dielectric); + } + else { + return one_spectrum(); } - - return F; -} - -ccl_device_forceinline float D_GTR1(float NdotH, float alpha) -{ - if (alpha >= 1.0f) - return M_1_PI_F; - float alpha2 = alpha * alpha; - float t = 1.0f + (alpha2 - 1.0f) * NdotH * NdotH; - return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t); } ccl_device_forceinline void bsdf_microfacet_fresnel_color(ccl_private const ShaderData *sd, ccl_private MicrofacetBsdf *bsdf) { - kernel_assert(CLOSURE_IS_BSDF_MICROFACET_FRESNEL(bsdf->type)); + Spectrum average_fresnel = reflection_color(bsdf, sd->I, bsdf->N); + bsdf->sample_weight *= average(average_fresnel); - float F0 = fresnel_dielectric_cos(1.0f, bsdf->ior); - bsdf->extra->fresnel_color = interpolate_fresnel_color( - sd->I, bsdf->N, bsdf->ior, F0, bsdf->extra->cspec0); - - if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { - bsdf->extra->fresnel_color *= 0.25f * bsdf->extra->clearcoat; + if (bsdf->extra) { + bsdf->extra->fresnel_color = average_fresnel; } +} - bsdf->sample_weight *= average(bsdf->extra->fresnel_color); +ccl_device_inline Spectrum microfacet_ggx_albedo_scaling(KernelGlobals kg, + ccl_private const MicrofacetBsdf *bsdf, + ccl_private const ShaderData *sd, + const Spectrum Fss) +{ + float mu = dot(sd->I, bsdf->N); + float rough = sqrtf(sqrtf(bsdf->alpha_x * bsdf->alpha_y)); + float E = microfacet_ggx_E(kg, mu, rough); + + float E_avg = microfacet_ggx_E_avg(kg, rough); + /* Fms here is based on the appendix of + * https://blog.selfshadow.com/publications/s2017-shading-course/imageworks/s2017_pbs_imageworks_slides_v2.pdf, + * with one Fss cancelled out since this is just a multiplier on top of + * the single-scattering BSDF, which already contains one bounce of Fresnel. */ + Spectrum Fms = Fss * E_avg / (one_spectrum() - Fss * (1.0f - E_avg)); + + return one_spectrum() + Fms * ((1.0f - E) / E); + /* TODO: Ensure that increase in weight does not mess up glossy color, albedo etc. passes */ } -/* GGX microfacet with Smith shadow-masking from: - * - * Microfacet Models for Refraction through Rough Surfaces - * B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007 - * - * Anisotropic from: - * - * Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs - * E. Heitz, Research Report 2014 - * - * Anisotropy is only supported for reflection currently, but adding it for - * transmission is just a matter of copying code from reflection if needed. */ +ccl_device_inline float microfacet_ggx_albedo_scaling_float(KernelGlobals kg, + ccl_private const MicrofacetBsdf *bsdf, + ccl_private const ShaderData *sd, + const float Fss) +{ + // TOOD: Deduplicate somehow? + float mu = dot(sd->I, bsdf->N); + float rough = sqrtf(sqrtf(bsdf->alpha_x * bsdf->alpha_y)); + float E = microfacet_ggx_E(kg, mu, rough), E_avg = microfacet_ggx_E_avg(kg, rough); + float Fms = Fss * E_avg / (1.0f - Fss * (1.0f - E_avg)); + return 1.0f + Fms * ((1.0f - E) / E); +} ccl_device int bsdf_microfacet_ggx_setup(ccl_private MicrofacetBsdf *bsdf) { @@ -299,11 +134,12 @@ ccl_device int bsdf_microfacet_ggx_setup(ccl_private MicrofacetBsdf *bsdf) return SD_BSDF | SD_BSDF_HAS_EVAL; } -/* Required to maintain OSL interface. */ -ccl_device int bsdf_microfacet_ggx_isotropic_setup(ccl_private MicrofacetBsdf *bsdf) +ccl_device int bsdf_microfacet_multi_ggx_setup(KernelGlobals kg, + ccl_private MicrofacetBsdf *bsdf, + ccl_private const ShaderData *sd, + const Spectrum color) { - bsdf->alpha_y = bsdf->alpha_x; - + bsdf->weight *= microfacet_ggx_albedo_scaling(kg, bsdf, sd, saturate(color)); return bsdf_microfacet_ggx_setup(bsdf); } @@ -322,11 +158,55 @@ ccl_device int bsdf_microfacet_ggx_fresnel_setup(ccl_private MicrofacetBsdf *bsd return SD_BSDF | SD_BSDF_HAS_EVAL; } +ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(KernelGlobals kg, + ccl_private MicrofacetBsdf *bsdf, + ccl_private const ShaderData *sd) +{ + Spectrum Fss = schlick_fresnel_Fss(bsdf->extra->cspec0); + bsdf->weight *= microfacet_ggx_albedo_scaling(kg, bsdf, sd, Fss); + return bsdf_microfacet_ggx_fresnel_setup(bsdf, sd); +} + +ccl_device int bsdf_microfacet_ggx_fresnel_v2_setup(KernelGlobals kg, + ccl_private MicrofacetBsdf *bsdf, + ccl_private const ShaderData *sd, + float metallic, + float dielectric) +{ + bsdf->alpha_x = saturatef(bsdf->alpha_x); + bsdf->alpha_y = saturatef(bsdf->alpha_y); + + MicrofacetExtrav2 *extra = (MicrofacetExtrav2 *)bsdf->extra; + + if (metallic > 0.0f) { + Spectrum metal_Fss = fresnel_metallic_Fss(extra->metal_base, extra->metal_edge_factor); + extra->metallic = metallic * microfacet_ggx_albedo_scaling(kg, bsdf, sd, metal_Fss); + } + else { + extra->metallic = zero_spectrum(); + extra->metal_base = zero_spectrum(); + extra->metal_edge_factor = zero_spectrum(); + } + + if (dielectric > 0.0f) { + float dielectric_Fss = dielectric_fresnel_Fss(bsdf->ior); + extra->dielectric = dielectric * + microfacet_ggx_albedo_scaling_float(kg, bsdf, sd, dielectric_Fss); + } + else { + extra->dielectric = 0.0f; + } + + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_V2_ID; + + // bsdf_microfacet_fresnel_color(sd, bsdf); // TODO + + return SD_BSDF | SD_BSDF_HAS_EVAL; +} + ccl_device int bsdf_microfacet_ggx_clearcoat_setup(ccl_private MicrofacetBsdf *bsdf, ccl_private const ShaderData *sd) { - bsdf->extra->cspec0 = saturate(bsdf->extra->cspec0); - bsdf->alpha_x = saturatef(bsdf->alpha_x); bsdf->alpha_y = bsdf->alpha_x; @@ -337,6 +217,23 @@ ccl_device int bsdf_microfacet_ggx_clearcoat_setup(ccl_private MicrofacetBsdf *b return SD_BSDF | SD_BSDF_HAS_EVAL; } +ccl_device int bsdf_microfacet_ggx_clearcoat_v2_setup(KernelGlobals kg, + ccl_private MicrofacetBsdf *bsdf, + ccl_private const ShaderData *sd) +{ + bsdf->alpha_x = saturatef(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; + + bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_V2_ID; + + float Fss = dielectric_fresnel_Fss(bsdf->ior); + bsdf->weight *= microfacet_ggx_albedo_scaling_float(kg, bsdf, sd, Fss); + + bsdf_microfacet_fresnel_color(sd, bsdf); + + return SD_BSDF | SD_BSDF_HAS_EVAL; +} + ccl_device int bsdf_microfacet_ggx_refraction_setup(ccl_private MicrofacetBsdf *bsdf) { bsdf->extra = NULL; @@ -367,99 +264,77 @@ ccl_device Spectrum bsdf_microfacet_ggx_eval_reflect(ccl_private const Microface const float cosNO, const float cosNI) { + float alpha2 = alpha_x * alpha_y; if (!(cosNI > 0 && cosNO > 0)) { *pdf = 0.0f; return zero_spectrum(); } - /* get half vector */ + /* Ensure that both direction are in the upper hemisphere */ + if (cosNI <= 0 || cosNO <= 0) { + *pdf = 0.0f; + return zero_spectrum(); + } + + /* Compute half vector */ float3 m = normalize(omega_in + I); - float alpha2 = alpha_x * alpha_y; - float D, G1o, G1i; + float D, lambdaO, lambdaI; if (alpha_x == alpha_y) { - /* isotropic - * eq. 20: (F*G*D)/(4*in*on) - * eq. 33: first we calculate D(m) */ - float cosThetaM = dot(N, m); - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + /* Isotropic case */ if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { /* use GTR1 for clearcoat */ - D = D_GTR1(cosThetaM, bsdf->alpha_x); + D = microfacet_GTR1_D(dot(N, m), alpha2); /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */ alpha2 = 0.0625f; } else { /* use GTR2 otherwise */ - D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + D = microfacet_ggx_D(dot(N, m), alpha2); } - /* eq. 34: now calculate G1(i,m) and G1(o,m) */ - G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); - G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + lambdaO = microfacet_ggx_lambda(cosNO, alpha2); + lambdaI = microfacet_ggx_lambda(cosNI, alpha2); } else { - /* anisotropic */ + /* Anisotropic case */ float3 X, Y, Z = N; make_orthonormals_tangent(Z, bsdf->T, &X, &Y); - /* distribution */ + /* Transform vectors into local coordinate space */ float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); - float slope_x = -local_m.x / (local_m.z * alpha_x); - float slope_y = -local_m.y / (local_m.z * alpha_y); - float slope_len = 1 + slope_x * slope_x + slope_y * slope_y; - - float cosThetaM = local_m.z; - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - - D = 1 / ((slope_len * slope_len) * M_PI_F * alpha2 * cosThetaM4); - - /* G1(i,m) and G1(o,m) */ - float tanThetaO2 = (1 - cosNO * cosNO) / (cosNO * cosNO); - float cosPhiO = dot(I, X); - float sinPhiO = dot(I, Y); - - float alphaO2 = (cosPhiO * cosPhiO) * (alpha_x * alpha_x) + - (sinPhiO * sinPhiO) * (alpha_y * alpha_y); - alphaO2 /= cosPhiO * cosPhiO + sinPhiO * sinPhiO; - - G1o = 2 / (1 + safe_sqrtf(1 + alphaO2 * tanThetaO2)); - - float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); - float cosPhiI = dot(omega_in, X); - float sinPhiI = dot(omega_in, Y); - - float alphaI2 = (cosPhiI * cosPhiI) * (alpha_x * alpha_x) + - (sinPhiI * sinPhiI) * (alpha_y * alpha_y); - alphaI2 /= cosPhiI * cosPhiI + sinPhiI * sinPhiI; + float3 local_O = make_float3(dot(X, I), dot(Y, I), cosNO); + float3 local_I = make_float3(dot(X, omega_in), dot(Y, omega_in), cosNI); - G1i = 2 / (1 + safe_sqrtf(1 + alphaI2 * tanThetaI2)); + D = microfacet_ggx_D_aniso(local_m, alpha_x, alpha_y); + lambdaO = microfacet_ggx_lambda_aniso(local_O, alpha_x, alpha_y); + lambdaI = microfacet_ggx_lambda_aniso(local_I, alpha_x, alpha_y); } - float G = G1o * G1i; + /* The full BSDF is (see e.g. eq. 20 in Walter et al. 2007): + * f(i, o) = F(i, m) * G(i, o) * D(m) / (4*cosNI*cosNO). + * + * Here, F is the fresnel reflection term, G is the masking-shadowing term, + * D is the microfacet distribution and cosNI/cosNO are cosines of angles. + * + * For G, this implementation uses the non-separable form of the Smith + * masking-shadowing term, so G is defined in terms of a function Lambda: + * G(i, o) = 1 / (1 + Lambda(i) + Lambda(o)). + * + * In Cycles, BSDF evaluation actually returns f(i, o)*cosNI, so one term + * in the BSDFs denominator cancels out. + * + * The PDF of VNDF sampling is D(m) * G1(o) / (4*cosNO), where G1(o) is + * 1 / (1 + Lambda(o)). + */ - /* eq. 20 */ + /* Evaluate BSDF */ float common = D * 0.25f / cosNO; - Spectrum F = reflection_color(bsdf, omega_in, m); - if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { - F *= 0.25f * bsdf->extra->clearcoat; - } - - Spectrum out = F * G * common; - - /* eq. 2 in distribution of visible normals sampling - * `pm = Dw = G1o * dot(m, I) * D / dot(N, I);` */ - - /* eq. 38 - but see also: - * eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf - * `pdf = pm * 0.25 / dot(m, I);` */ - *pdf = G1o * common; + Spectrum out = F * common / (1 + lambdaO + lambdaI); + *pdf = common / (1 + lambdaO); return out; } @@ -474,44 +349,29 @@ ccl_device Spectrum bsdf_microfacet_ggx_eval_transmit(ccl_private const Microfac const float cosNO, const float cosNI) { + float alpha2 = alpha_x * alpha_y; if (cosNO <= 0 || cosNI >= 0) { *pdf = 0.0f; - return zero_spectrum(); /* vectors on same side -- not possible */ + return zero_spectrum(); } - /* compute half-vector of the refraction (eq. 16) */ + + /* Compute half vector */ float m_eta = bsdf->ior; float3 ht = -(m_eta * omega_in + I); - float3 Ht = normalize(ht); - float cosHO = dot(Ht, I); - float cosHI = dot(Ht, omega_in); - - float D, G1o, G1i; - - /* eq. 33: first we calculate D(m) with m=Ht: */ - float alpha2 = alpha_x * alpha_y; - float cosThetaM = dot(N, Ht); - float cosThetaM2 = cosThetaM * cosThetaM; - float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); + float3 m = normalize(ht); + float cosMO = dot(m, I); + float cosMI = dot(m, omega_in); - /* eq. 34: now calculate G1(i,m) and G1(o,m) */ - G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); - G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); + /* Evaluate microfacet model */ + float D = microfacet_ggx_D(dot(N, m), alpha2); + float lambdaO = microfacet_ggx_lambda(cosNO, alpha2); + float lambdaI = microfacet_ggx_lambda(cosNI, alpha2); - float G = G1o * G1i; - - /* probability */ + /* Evaluate BSDF */ float Ht2 = dot(ht, ht); - - /* eq. 2 in distribution of visible normals sampling - * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ - - /* out = fabsf(cosHI * cosHO) * (m_eta * m_eta) * G * D / (cosNO * Ht2) - * pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2 */ - float common = D * (m_eta * m_eta) / (cosNO * Ht2); - float out = G * fabsf(cosHI * cosHO) * common; - *pdf = G1o * fabsf(cosHO * cosHI) * common; + float common = fabsf(cosMI * cosMO) * D * sqr(m_eta) / (cosNO * Ht2); + float out = common / (1 + lambdaO + lambdaI); + *pdf = common / (1 + lambdaO); return make_spectrum(out); } @@ -540,8 +400,7 @@ ccl_device Spectrum bsdf_microfacet_ggx_eval(ccl_private const ShaderClosure *sc bsdf, N, I, omega_in, pdf, alpha_x, alpha_y, cosNO, cosNI); } -ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals kg, - ccl_private const ShaderClosure *sc, +ccl_device int bsdf_microfacet_ggx_sample(ccl_private const ShaderClosure *sc, float3 Ng, float3 I, float randu, @@ -555,585 +414,135 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals kg, ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; float alpha_x = bsdf->alpha_x; float alpha_y = bsdf->alpha_y; + float alpha2 = alpha_x * alpha_y; bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; *sampled_roughness = make_float2(alpha_x, alpha_y); *eta = m_refractive ? 1.0f / bsdf->ior : bsdf->ior; float3 N = bsdf->N; - int label; + /* Ensure that the view direction is in the upper hemisphere. */ float cosNO = dot(N, I); - if (cosNO > 0) { - float3 X, Y, Z = N; - - if (alpha_x == alpha_y) - make_orthonormals(Z, &X, &Y); - else - make_orthonormals_tangent(Z, bsdf->T, &X, &Y); - - /* importance sampling with distribution of visible normals. vectors are - * transformed to local space before and after */ - float3 local_I = make_float3(dot(X, I), dot(Y, I), cosNO); - float3 local_m; - float G1o; - - local_m = microfacet_sample_stretched( - kg, local_I, alpha_x, alpha_y, randu, randv, false, &G1o); - - float3 m = X * local_m.x + Y * local_m.y + Z * local_m.z; - float cosThetaM = local_m.z; - - /* reflection or refraction? */ - if (!m_refractive) { - float cosMO = dot(m, I); - label = LABEL_REFLECT | LABEL_GLOSSY; - - if (cosMO > 0) { - /* eq. 39 - compute actual reflected direction */ - *omega_in = 2 * cosMO * m - I; - - if (dot(Ng, *omega_in) > 0) { - if (alpha_x * alpha_y <= 1e-7f) { - /* some high number for MIS */ - *pdf = 1e6f; - *eval = make_spectrum(1e6f); - - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID || - bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID); - - /* if fresnel is used, calculate the color with reflection_color(...) */ - if (use_fresnel) { - *eval *= reflection_color(bsdf, *omega_in, m); - } - - label = LABEL_REFLECT | LABEL_SINGULAR; - } - else { - /* microfacet normal is visible to this ray */ - /* eq. 33 */ - float alpha2 = alpha_x * alpha_y; - float D, G1i; - - if (alpha_x == alpha_y) { - /* isotropic */ - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - float tanThetaM2 = 1 / (cosThetaM2)-1; - - /* eval BRDF*cosNI */ - float cosNI = dot(N, *omega_in); - - if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { - /* use GTR1 for clearcoat */ - D = D_GTR1(cosThetaM, bsdf->alpha_x); - - /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */ - alpha2 = 0.0625f; - - /* recalculate G1o */ - G1o = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO))); - } - else { - /* use GTR2 otherwise */ - D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); - } - - /* eq. 34: now calculate G1(i,m) */ - G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); - } - else { - /* anisotropic distribution */ - float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); - float slope_x = -local_m.x / (local_m.z * alpha_x); - float slope_y = -local_m.y / (local_m.z * alpha_y); - float slope_len = 1 + slope_x * slope_x + slope_y * slope_y; - - float cosThetaM = local_m.z; - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - - D = 1 / ((slope_len * slope_len) * M_PI_F * alpha2 * cosThetaM4); - - /* calculate G1(i,m) */ - float cosNI = dot(N, *omega_in); - - float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); - float cosPhiI = dot(*omega_in, X); - float sinPhiI = dot(*omega_in, Y); - - float alphaI2 = (cosPhiI * cosPhiI) * (alpha_x * alpha_x) + - (sinPhiI * sinPhiI) * (alpha_y * alpha_y); - alphaI2 /= cosPhiI * cosPhiI + sinPhiI * sinPhiI; - - G1i = 2 / (1 + safe_sqrtf(1 + alphaI2 * tanThetaI2)); - } - - /* see eval function for derivation */ - float common = (G1o * D) * 0.25f / cosNO; - *pdf = common; - - Spectrum F = reflection_color(bsdf, *omega_in, m); - - *eval = G1i * common * F; - } - - if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { - *eval *= 0.25f * bsdf->extra->clearcoat; - } - } - else { - *eval = zero_spectrum(); - *pdf = 0.0f; - } - } - } - else { - label = LABEL_TRANSMIT | LABEL_GLOSSY; - - /* CAUTION: the i and o variables are inverted relative to the paper - * eq. 39 - compute actual refractive direction */ - float3 R, T; - float m_eta = bsdf->ior, fresnel; - bool inside; - - fresnel = fresnel_dielectric(m_eta, m, I, &R, &T, &inside); - - if (!inside && fresnel != 1.0f) { - *omega_in = T; - - if (alpha_x * alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { - /* some high number for MIS */ - *pdf = 1e6f; - *eval = make_spectrum(1e6f); - label = LABEL_TRANSMIT | LABEL_SINGULAR; - } - else { - /* eq. 33 */ - float alpha2 = alpha_x * alpha_y; - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - float tanThetaM2 = 1 / (cosThetaM2)-1; - float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2)); - - /* eval BRDF*cosNI */ - float cosNI = dot(N, *omega_in); - - /* eq. 34: now calculate G1(i,m) */ - float G1i = 2 / (1 + safe_sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI))); - - /* eq. 21 */ - float cosHI = dot(m, *omega_in); - float cosHO = dot(m, I); - float Ht2 = m_eta * cosHI + cosHO; - Ht2 *= Ht2; - - /* see eval function for derivation */ - float common = (G1o * D) * (m_eta * m_eta) / (cosNO * Ht2); - float out = G1i * fabsf(cosHI * cosHO) * common; - *pdf = cosHO * fabsf(cosHI) * common; - - *eval = make_spectrum(out); - } - } - else { - *eval = zero_spectrum(); - *pdf = 0.0f; - } - } - } - else { - label = (m_refractive) ? LABEL_TRANSMIT | LABEL_GLOSSY : LABEL_REFLECT | LABEL_GLOSSY; - } - return label; -} - -/* Beckmann microfacet with Smith shadow-masking from: - * - * Microfacet Models for Refraction through Rough Surfaces - * B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007 */ - -ccl_device int bsdf_microfacet_beckmann_setup(ccl_private MicrofacetBsdf *bsdf) -{ - bsdf->alpha_x = saturatef(bsdf->alpha_x); - bsdf->alpha_y = saturatef(bsdf->alpha_y); - - bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID; - return SD_BSDF | SD_BSDF_HAS_EVAL; -} - -/* Required to maintain OSL interface. */ -ccl_device int bsdf_microfacet_beckmann_isotropic_setup(ccl_private MicrofacetBsdf *bsdf) -{ - bsdf->alpha_y = bsdf->alpha_x; - - return bsdf_microfacet_beckmann_setup(bsdf); -} - -ccl_device int bsdf_microfacet_beckmann_refraction_setup(ccl_private MicrofacetBsdf *bsdf) -{ - bsdf->alpha_x = saturatef(bsdf->alpha_x); - bsdf->alpha_y = bsdf->alpha_x; - - bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - return SD_BSDF | SD_BSDF_HAS_EVAL; -} - -ccl_device void bsdf_microfacet_beckmann_blur(ccl_private ShaderClosure *sc, float roughness) -{ - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc; - - bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); - bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); -} - -ccl_device_inline float bsdf_beckmann_G1(float alpha, float cos_n) -{ - cos_n *= cos_n; - float invA = alpha * safe_sqrtf((1.0f - cos_n) / cos_n); - if (invA < 0.625f) { - return 1.0f; - } - - float a = 1.0f / invA; - return ((2.181f * a + 3.535f) * a) / ((2.577f * a + 2.276f) * a + 1.0f); -} - -ccl_device_inline float bsdf_beckmann_aniso_G1( - float alpha_x, float alpha_y, float cos_n, float cos_phi, float sin_phi) -{ - cos_n *= cos_n; - sin_phi *= sin_phi; - cos_phi *= cos_phi; - alpha_x *= alpha_x; - alpha_y *= alpha_y; - - float alphaO2 = (cos_phi * alpha_x + sin_phi * alpha_y) / (cos_phi + sin_phi); - float invA = safe_sqrtf(alphaO2 * (1 - cos_n) / cos_n); - if (invA < 0.625f) { - return 1.0f; - } - - float a = 1.0f / invA; - return ((2.181f * a + 3.535f) * a) / ((2.577f * a + 2.276f) * a + 1.0f); -} - -ccl_device Spectrum bsdf_microfacet_beckmann_eval_reflect(ccl_private const MicrofacetBsdf *bsdf, - const float3 N, - const float3 I, - const float3 omega_in, - ccl_private float *pdf, - const float alpha_x, - const float alpha_y, - const float cosNO, - const float cosNI) -{ - if (!(cosNO > 0 && cosNI > 0)) { + if (cosNO <= 0) { *pdf = 0.0f; - return zero_spectrum(); + return LABEL_NONE; } - /* get half vector */ - float3 m = normalize(omega_in + I); - - float alpha2 = alpha_x * alpha_y; - float D, G1o, G1i; - - if (alpha_x == alpha_y) { - /* isotropic - * eq. 20: (F*G*D)/(4*in*on) - * eq. 25: first we calculate D(m) */ - float cosThetaM = dot(N, m); - float cosThetaM2 = cosThetaM * cosThetaM; - float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); - - /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ - G1o = bsdf_beckmann_G1(alpha_x, cosNO); - G1i = bsdf_beckmann_G1(alpha_x, cosNI); - } - else { - /* anisotropic */ - float3 X, Y, Z = N; + /* Form local coordinate frame */ + float3 X, Y, Z = N; + if (alpha_x == alpha_y) + make_orthonormals(Z, &X, &Y); + else make_orthonormals_tangent(Z, bsdf->T, &X, &Y); - /* distribution */ - float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); - float slope_x = -local_m.x / (local_m.z * alpha_x); - float slope_y = -local_m.y / (local_m.z * alpha_y); + /* Sample distribution of visible normals to find the microfacet normal. + * Sampling happens in the local frame. */ + float3 local_O = make_float3(dot(X, I), dot(Y, I), cosNO); + float3 local_m = microfacet_ggx_sample_vndf(local_O, alpha_x, alpha_y, randu, randv); + float3 m = X * local_m.x + Y * local_m.y + Z * local_m.z; + float cosThetaM = local_m.z; + + /* Reflection or refraction? */ + if (!m_refractive) { + /* Compute reflected direction and ensure that it is in the upper hemisphere. + * Also check if the microfacet is masked (in that case, we'd hit it from the backside). */ + float cosMO = dot(m, I); + *omega_in = 2 * cosMO * m - I; + if (cosMO <= 0 || dot(Ng, *omega_in) <= 0) { + *pdf = 0.0f; + return LABEL_NONE; + } - float cosThetaM = local_m.z; - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; + Spectrum F = reflection_color(bsdf, *omega_in, m); + if (alpha2 <= 1e-7f) { + /* Specular case, just return some high number for MIS */ + *pdf = 1e6f; + *eval = make_spectrum(1e6f) * F; + return LABEL_REFLECT | LABEL_SINGULAR; + } - D = expf(-slope_x * slope_x - slope_y * slope_y) / (M_PI_F * alpha2 * cosThetaM4); + /* Evaluate microfacet model. */ + float D, lambdaO, lambdaI; + if (alpha_x == alpha_y) { + /* Isotropic case */ - /* G1(i,m) and G1(o,m) */ - G1o = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNO, dot(I, X), dot(I, Y)); - G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNI, dot(omega_in, X), dot(omega_in, Y)); - } + if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) { + /* use GTR1 for clearcoat */ + D = microfacet_GTR1_D(cosThetaM, alpha2); - float G = G1o * G1i; + /* the alpha value for clearcoat is a fixed 0.25 => alpha2 = 0.25 * 0.25 */ + alpha2 = 0.0625f; - /* eq. 20 */ - float common = D * 0.25f / cosNO; - float out = G * common; + /* recalculate lambdaO */ + lambdaO = microfacet_ggx_lambda(cosNO, alpha2); + } + else { + /* use GTR2 otherwise */ + D = microfacet_ggx_D(cosThetaM, alpha2); + } - /* eq. 2 in distribution of visible normals sampling - * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ + float cosNI = dot(N, *omega_in); + lambdaO = microfacet_ggx_lambda(cosNO, alpha2); + lambdaI = microfacet_ggx_lambda(cosNI, alpha2); + } + else { + /* Anisotropic case */ + D = microfacet_ggx_D_aniso(local_m, alpha_x, alpha_y); - /* eq. 38 - but see also: - * eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf - * pdf = pm * 0.25 / dot(m, I); */ - *pdf = G1o * common; + float3 local_I = make_float3(dot(X, *omega_in), dot(Y, *omega_in), dot(N, *omega_in)); + lambdaO = microfacet_ggx_lambda_aniso(local_O, alpha_x, alpha_y); + lambdaI = microfacet_ggx_lambda_aniso(local_I, alpha_x, alpha_y); + } - return make_spectrum(out); -} + /* See bsdf_microfacet_ggx_eval_reflect for derivation. */ + float common = D * 0.25f / cosNO; + *pdf = common / (1 + lambdaO); + *eval = common * F / (1 + lambdaO + lambdaI); -ccl_device Spectrum bsdf_microfacet_beckmann_eval_transmit(ccl_private const MicrofacetBsdf *bsdf, - const float3 N, - const float3 I, - const float3 omega_in, - ccl_private float *pdf, - const float alpha_x, - const float alpha_y, - const float cosNO, - const float cosNI) -{ - if (cosNO <= 0 || cosNI >= 0) { - *pdf = 0.0f; - return zero_spectrum(); + return LABEL_REFLECT | LABEL_GLOSSY; } + else { + /* Compute refracted direction */ + float3 R, T; + float m_eta = bsdf->ior, fresnel; + bool inside; - const float m_eta = bsdf->ior; - /* compute half-vector of the refraction (eq. 16) */ - float3 ht = -(m_eta * omega_in + I); - float3 Ht = normalize(ht); - float cosHO = dot(Ht, I); - float cosHI = dot(Ht, omega_in); - - /* eq. 25: first we calculate D(m) with m=Ht: */ - float alpha2 = alpha_x * alpha_y; - float cosThetaM = min(dot(N, Ht), 1.0f); - float cosThetaM2 = cosThetaM * cosThetaM; - float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); - - /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ - float G1o = bsdf_beckmann_G1(alpha_x, cosNO); - float G1i = bsdf_beckmann_G1(alpha_x, cosNI); - float G = G1o * G1i; - - /* probability */ - float Ht2 = dot(ht, ht); - - /* eq. 2 in distribution of visible normals sampling - * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ - - /* out = fabsf(cosHI * cosHO) * (m_eta * m_eta) * G * D / (cosNO * Ht2) - * pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2 */ - float common = D * (m_eta * m_eta) / (cosNO * Ht2); - float out = G * fabsf(cosHI * cosHO) * common; - *pdf = G1o * fabsf(cosHO * cosHI) * common; - - return make_spectrum(out); -} + fresnel = fresnel_dielectric(m_eta, m, I, &R, &T, &inside); -ccl_device Spectrum bsdf_microfacet_beckmann_eval(ccl_private const ShaderClosure *sc, - const float3 I, - const float3 omega_in, - ccl_private float *pdf) -{ - ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; - const float alpha_x = bsdf->alpha_x; - const float alpha_y = bsdf->alpha_y; - const bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - const float3 N = bsdf->N; - const float cosNO = dot(N, I); - const float cosNI = dot(N, omega_in); + /* Ensure that the microfacet is nor masked and that we don't encounter TIR */ + if (inside || fresnel == 1.0f) { + *pdf = 0.0f; + return LABEL_NONE; + } - if (((cosNI < 0.0f) != m_refractive) || alpha_x * alpha_y <= 1e-7f) { - *pdf = 0.0f; - return zero_spectrum(); - } + *omega_in = T; - return (cosNI < 0.0f) ? bsdf_microfacet_beckmann_eval_transmit( - bsdf, N, I, omega_in, pdf, alpha_x, alpha_y, cosNO, cosNI) : - bsdf_microfacet_beckmann_eval_reflect( - bsdf, N, I, omega_in, pdf, alpha_x, alpha_y, cosNO, cosNI); -} + if (alpha2 <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { + /* some high number for MIS */ + *pdf = 1e6f; + *eval = make_spectrum(1e6f); + return LABEL_TRANSMIT | LABEL_SINGULAR; + } -ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals kg, - ccl_private const ShaderClosure *sc, - float3 Ng, - float3 I, - float randu, - float randv, - ccl_private Spectrum *eval, - ccl_private float3 *omega_in, - ccl_private float *pdf, - ccl_private float2 *sampled_roughness, - ccl_private float *eta) -{ - ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; - float alpha_x = bsdf->alpha_x; - float alpha_y = bsdf->alpha_y; - bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; - float3 N = bsdf->N; - int label; + /* Evaluate microfacet model */ + float D = microfacet_ggx_D(cosThetaM, alpha2); + float cosNI = dot(N, *omega_in); + float lambdaO = microfacet_ggx_lambda(cosNO, alpha2); + float lambdaI = microfacet_ggx_lambda(cosNI, alpha2); - *sampled_roughness = make_float2(alpha_x, alpha_y); - *eta = m_refractive ? 1.0f / bsdf->ior : bsdf->ior; + /* Evaluate BSDF */ + float cosMI = dot(m, *omega_in); + float cosMO = dot(m, I); + float Ht2 = sqr(m_eta * cosMI + cosMO); + float common = fabsf(cosMI * cosMO) * D * sqr(m_eta) / (cosNO * Ht2); + float out = common / (1 + lambdaO + lambdaI); + *pdf = common / (1 + lambdaO); - float cosNO = dot(N, I); - if (cosNO > 0) { - float3 X, Y, Z = N; + *eval = make_spectrum(out); - if (alpha_x == alpha_y) - make_orthonormals(Z, &X, &Y); - else - make_orthonormals_tangent(Z, bsdf->T, &X, &Y); - - /* importance sampling with distribution of visible normals. vectors are - * transformed to local space before and after */ - float3 local_I = make_float3(dot(X, I), dot(Y, I), cosNO); - float3 local_m; - float G1o; - - local_m = microfacet_sample_stretched(kg, local_I, alpha_x, alpha_x, randu, randv, true, &G1o); - - float3 m = X * local_m.x + Y * local_m.y + Z * local_m.z; - float cosThetaM = local_m.z; - - /* reflection or refraction? */ - if (!m_refractive) { - label = LABEL_REFLECT | LABEL_GLOSSY; - float cosMO = dot(m, I); - - if (cosMO > 0) { - /* eq. 39 - compute actual reflected direction */ - *omega_in = 2 * cosMO * m - I; - - if (dot(Ng, *omega_in) > 0) { - if (alpha_x * alpha_y <= 1e-7f) { - /* some high number for MIS */ - *pdf = 1e6f; - *eval = make_spectrum(1e6f); - label = LABEL_REFLECT | LABEL_SINGULAR; - } - else { - /* microfacet normal is visible to this ray - * eq. 25 */ - float alpha2 = alpha_x * alpha_y; - float D, G1i; - - if (alpha_x == alpha_y) { - /* Isotropic distribution. */ - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - float tanThetaM2 = 1 / (cosThetaM2)-1; - D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); - - /* eval BRDF*cosNI */ - float cosNI = dot(N, *omega_in); - - /* eq. 26, 27: now calculate G1(i,m) */ - G1i = bsdf_beckmann_G1(alpha_x, cosNI); - } - else { - /* anisotropic distribution */ - float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); - float slope_x = -local_m.x / (local_m.z * alpha_x); - float slope_y = -local_m.y / (local_m.z * alpha_y); - - float cosThetaM = local_m.z; - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - - D = expf(-slope_x * slope_x - slope_y * slope_y) / (M_PI_F * alpha2 * cosThetaM4); - - /* G1(i,m) */ - G1i = bsdf_beckmann_aniso_G1( - alpha_x, alpha_y, dot(*omega_in, N), dot(*omega_in, X), dot(*omega_in, Y)); - } - - float G = G1o * G1i; - - /* see eval function for derivation */ - float common = D * 0.25f / cosNO; - float out = G * common; - *pdf = G1o * common; - - *eval = make_spectrum(out); - } - } - else { - *eval = zero_spectrum(); - *pdf = 0.0f; - } - } - } - else { - label = LABEL_TRANSMIT | LABEL_GLOSSY; - - /* CAUTION: the i and o variables are inverted relative to the paper - * eq. 39 - compute actual refractive direction */ - float3 R, T; - float m_eta = bsdf->ior, fresnel; - bool inside; - - fresnel = fresnel_dielectric(m_eta, m, I, &R, &T, &inside); - - if (!inside && fresnel != 1.0f) { - *omega_in = T; - - if (alpha_x * alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { - /* some high number for MIS */ - *pdf = 1e6f; - *eval = make_spectrum(1e6f); - label = LABEL_TRANSMIT | LABEL_SINGULAR; - } - else { - /* eq. 33 */ - float alpha2 = alpha_x * alpha_y; - float cosThetaM2 = cosThetaM * cosThetaM; - float cosThetaM4 = cosThetaM2 * cosThetaM2; - float tanThetaM2 = 1 / (cosThetaM2)-1; - float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); - - /* eval BRDF*cosNI */ - float cosNI = dot(N, *omega_in); - - /* eq. 26, 27: now calculate G1(i,m) */ - float G1i = bsdf_beckmann_G1(alpha_x, cosNI); - float G = G1o * G1i; - - /* eq. 21 */ - float cosHI = dot(m, *omega_in); - float cosHO = dot(m, I); - float Ht2 = m_eta * cosHI + cosHO; - Ht2 *= Ht2; - - /* see eval function for derivation */ - float common = D * (m_eta * m_eta) / (cosNO * Ht2); - float out = G * fabsf(cosHI * cosHO) * common; - *pdf = G1o * cosHO * fabsf(cosHI) * common; - - *eval = make_spectrum(out); - } - } - else { - *eval = zero_spectrum(); - *pdf = 0.0f; - } - } - } - else { - label = (m_refractive) ? LABEL_TRANSMIT | LABEL_GLOSSY : LABEL_REFLECT | LABEL_GLOSSY; + return LABEL_TRANSMIT | LABEL_GLOSSY; } - return label; } CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_beckmann.h b/intern/cycles/kernel/closure/bsdf_microfacet_beckmann.h new file mode 100644 index 00000000000..4fabbcfc1eb --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_microfacet_beckmann.h @@ -0,0 +1,527 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * + * Adapted from Open Shading Language + * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. + * All Rights Reserved. + * + * Modifications Copyright 2011-2022 Blender Foundation. */ + +#pragma once + +#include "kernel/closure/bsdf_util.h" + +#include "kernel/util/lookup_table.h" + +CCL_NAMESPACE_BEGIN + +/* Beckmann microfacet with Smith shadow-masking from: + * + * Microfacet Models for Refraction through Rough Surfaces + * B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007 + * + * Microfacet importance sampling from: + * Importance Sampling Microfacet-Based BSDFs using the Distribution of Visible Normals. + * E. Heitz and E. d'Eon, EGSR 2014 + */ + +ccl_device_inline void microfacet_beckmann_sample_slopes(KernelGlobals kg, + const float cos_theta_i, + const float sin_theta_i, + float randu, + float randv, + ccl_private float *slope_x, + ccl_private float *slope_y, + ccl_private float *G1i) +{ + /* special case (normal incidence) */ + if (cos_theta_i >= 0.99999f) { + const float r = sqrtf(-logf(randu)); + const float phi = M_2PI_F * randv; + *slope_x = r * cosf(phi); + *slope_y = r * sinf(phi); + *G1i = 1.0f; + return; + } + + /* precomputations */ + const float tan_theta_i = sin_theta_i / cos_theta_i; + const float inv_a = tan_theta_i; + const float cot_theta_i = 1.0f / tan_theta_i; + const float erf_a = fast_erff(cot_theta_i); + const float exp_a2 = expf(-cot_theta_i * cot_theta_i); + const float SQRT_PI_INV = 0.56418958354f; + const float Lambda = 0.5f * (erf_a - 1.0f) + (0.5f * SQRT_PI_INV) * (exp_a2 * inv_a); + const float G1 = 1.0f / (1.0f + Lambda); /* masking */ + + *G1i = G1; + +#if defined(__KERNEL_GPU__) + /* Based on paper from Wenzel Jakob + * An Improved Visible Normal Sampling Routine for the Beckmann Distribution + * + * http://www.mitsuba-renderer.org/~wenzel/files/visnormal.pdf + * + * Reformulation from OpenShadingLanguage which avoids using inverse + * trigonometric functions. + */ + + /* Sample slope X. + * + * Compute a coarse approximation using the approximation: + * exp(-ierf(x)^2) ~= 1 - x * x + * solve y = 1 + b + K * (1 - b * b) + */ + float K = tan_theta_i * SQRT_PI_INV; + float y_approx = randu * (1.0f + erf_a + K * (1 - erf_a * erf_a)); + float y_exact = randu * (1.0f + erf_a + K * exp_a2); + float b = K > 0 ? (0.5f - sqrtf(K * (K - y_approx + 1.0f) + 0.25f)) / K : y_approx - 1.0f; + + /* Perform newton step to refine toward the true root. */ + float inv_erf = fast_ierff(b); + float value = 1.0f + b + K * expf(-inv_erf * inv_erf) - y_exact; + /* Check if we are close enough already, + * this also avoids NaNs as we get close to the root. + */ + if (fabsf(value) > 1e-6f) { + b -= value / (1.0f - inv_erf * tan_theta_i); /* newton step 1. */ + inv_erf = fast_ierff(b); + value = 1.0f + b + K * expf(-inv_erf * inv_erf) - y_exact; + b -= value / (1.0f - inv_erf * tan_theta_i); /* newton step 2. */ + /* Compute the slope from the refined value. */ + *slope_x = fast_ierff(b); + } + else { + /* We are close enough already. */ + *slope_x = inv_erf; + } + *slope_y = fast_ierff(2.0f * randv - 1.0f); +#else + /* Use precomputed table on CPU, it gives better performance. */ + int beckmann_table_offset = kernel_data.tables.beckmann_offset; + + *slope_x = lookup_table_read_2D( + kg, randu, cos_theta_i, beckmann_table_offset, BECKMANN_TABLE_SIZE, BECKMANN_TABLE_SIZE); + *slope_y = fast_ierff(2.0f * randv - 1.0f); +#endif +} + +ccl_device_forceinline float3 microfacet_sample_stretched(KernelGlobals kg, + const float3 omega_i, + const float alpha_x, + const float alpha_y, + const float randu, + const float randv, + ccl_private float *G1i) +{ + /* 1. stretch omega_i */ + float3 omega_i_ = make_float3(alpha_x * omega_i.x, alpha_y * omega_i.y, omega_i.z); + omega_i_ = normalize(omega_i_); + + /* get polar coordinates of omega_i_ */ + float costheta_ = 1.0f; + float sintheta_ = 0.0f; + float cosphi_ = 1.0f; + float sinphi_ = 0.0f; + + if (omega_i_.z < 0.99999f) { + costheta_ = omega_i_.z; + sintheta_ = safe_sqrtf(1.0f - costheta_ * costheta_); + + float invlen = 1.0f / sintheta_; + cosphi_ = omega_i_.x * invlen; + sinphi_ = omega_i_.y * invlen; + } + + /* 2. sample P22_{omega_i}(x_slope, y_slope, 1, 1) */ + float slope_x, slope_y; + microfacet_beckmann_sample_slopes( + kg, costheta_, sintheta_, randu, randv, &slope_x, &slope_y, G1i); + + /* 3. rotate */ + float tmp = cosphi_ * slope_x - sinphi_ * slope_y; + slope_y = sinphi_ * slope_x + cosphi_ * slope_y; + slope_x = tmp; + + /* 4. unstretch */ + slope_x = alpha_x * slope_x; + slope_y = alpha_y * slope_y; + + /* 5. compute normal */ + return normalize(make_float3(-slope_x, -slope_y, 1.0f)); +} + +ccl_device int bsdf_microfacet_beckmann_setup(ccl_private MicrofacetBsdf *bsdf) +{ + bsdf->alpha_x = saturatef(bsdf->alpha_x); + bsdf->alpha_y = saturatef(bsdf->alpha_y); + + bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_ID; + return SD_BSDF | SD_BSDF_HAS_EVAL; +} + +ccl_device int bsdf_microfacet_beckmann_refraction_setup(ccl_private MicrofacetBsdf *bsdf) +{ + bsdf->alpha_x = saturatef(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; + + bsdf->type = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + return SD_BSDF | SD_BSDF_HAS_EVAL; +} + +ccl_device void bsdf_microfacet_beckmann_blur(ccl_private ShaderClosure *sc, float roughness) +{ + ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc; + + bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); + bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); +} + +ccl_device_inline float bsdf_beckmann_G1(float alpha, float cos_n) +{ + cos_n *= cos_n; + float invA = alpha * safe_sqrtf((1.0f - cos_n) / cos_n); + if (invA < 0.625f) { + return 1.0f; + } + + float a = 1.0f / invA; + return ((2.181f * a + 3.535f) * a) / ((2.577f * a + 2.276f) * a + 1.0f); +} + +ccl_device_inline float bsdf_beckmann_aniso_G1( + float alpha_x, float alpha_y, float cos_n, float cos_phi, float sin_phi) +{ + cos_n *= cos_n; + sin_phi *= sin_phi; + cos_phi *= cos_phi; + alpha_x *= alpha_x; + alpha_y *= alpha_y; + + float alphaO2 = (cos_phi * alpha_x + sin_phi * alpha_y) / (cos_phi + sin_phi); + float invA = safe_sqrtf(alphaO2 * (1 - cos_n) / cos_n); + if (invA < 0.625f) { + return 1.0f; + } + + float a = 1.0f / invA; + return ((2.181f * a + 3.535f) * a) / ((2.577f * a + 2.276f) * a + 1.0f); +} + +ccl_device Spectrum bsdf_microfacet_beckmann_eval_reflect(ccl_private const MicrofacetBsdf *bsdf, + const float3 N, + const float3 I, + const float3 omega_in, + ccl_private float *pdf, + const float alpha_x, + const float alpha_y, + const float cosNO, + const float cosNI) +{ + if (!(cosNO > 0 && cosNI > 0)) { + *pdf = 0.0f; + return zero_spectrum(); + } + + /* get half vector */ + float3 m = normalize(omega_in + I); + + float alpha2 = alpha_x * alpha_y; + float D, G1o, G1i; + + if (alpha_x == alpha_y) { + /* isotropic + * eq. 20: (F*G*D)/(4*in*on) + * eq. 25: first we calculate D(m) */ + float cosThetaM = dot(N, m); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + + /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ + G1o = bsdf_beckmann_G1(alpha_x, cosNO); + G1i = bsdf_beckmann_G1(alpha_x, cosNI); + } + else { + /* anisotropic */ + float3 X, Y, Z = N; + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); + + /* distribution */ + float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); + float slope_x = -local_m.x / (local_m.z * alpha_x); + float slope_y = -local_m.y / (local_m.z * alpha_y); + + float cosThetaM = local_m.z; + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + + D = expf(-slope_x * slope_x - slope_y * slope_y) / (M_PI_F * alpha2 * cosThetaM4); + + /* G1(i,m) and G1(o,m) */ + G1o = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNO, dot(I, X), dot(I, Y)); + G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNI, dot(omega_in, X), dot(omega_in, Y)); + } + + float G = G1o * G1i; + + /* eq. 20 */ + float common = D * 0.25f / cosNO; + float out = G * common; + + /* eq. 2 in distribution of visible normals sampling + * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ + + /* eq. 38 - but see also: + * eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf + * pdf = pm * 0.25 / dot(m, I); */ + *pdf = G1o * common; + + return make_spectrum(out); +} + +ccl_device Spectrum bsdf_microfacet_beckmann_eval_transmit(ccl_private const MicrofacetBsdf *bsdf, + const float3 N, + const float3 I, + const float3 omega_in, + ccl_private float *pdf, + const float alpha_x, + const float alpha_y, + const float cosNO, + const float cosNI) +{ + const float m_eta = bsdf->ior; + if (cosNO <= 0 || cosNI >= 0) { + *pdf = 0.0f; + return zero_spectrum(); + } + /* compute half-vector of the refraction (eq. 16) */ + float3 ht = -(m_eta * omega_in + I); + float3 Ht = normalize(ht); + float cosHO = dot(Ht, I); + float cosHI = dot(Ht, omega_in); + + /* eq. 25: first we calculate D(m) with m=Ht: */ + float alpha2 = alpha_x * alpha_y; + float cosThetaM = min(dot(N, Ht), 1.0f); + float cosThetaM2 = cosThetaM * cosThetaM; + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + + /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ + float G1o = bsdf_beckmann_G1(alpha_x, cosNO); + float G1i = bsdf_beckmann_G1(alpha_x, cosNI); + float G = G1o * G1i; + + /* probability */ + float Ht2 = dot(ht, ht); + + /* eq. 2 in distribution of visible normals sampling + * pm = Dw = G1o * dot(m, I) * D / dot(N, I); */ + + /* out = fabsf(cosHI * cosHO) * (m_eta * m_eta) * G * D / (cosNO * Ht2) + * pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2 */ + float common = D * (m_eta * m_eta) / (cosNO * Ht2); + float out = G * fabsf(cosHI * cosHO) * common; + *pdf = G1o * fabsf(cosHO * cosHI) * common; + + return make_spectrum(out); +} + +ccl_device Spectrum bsdf_microfacet_beckmann_eval(ccl_private const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + ccl_private float *pdf) +{ + ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; + const float alpha_x = bsdf->alpha_x; + const float alpha_y = bsdf->alpha_y; + const bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + const float3 N = bsdf->N; + const float cosNO = dot(N, I); + const float cosNI = dot(N, omega_in); + + if (((cosNI < 0.0f) != m_refractive) || alpha_x * alpha_y <= 1e-7f) { + *pdf = 0.0f; + return zero_spectrum(); + } + + return (cosNI < 0.0f) ? bsdf_microfacet_beckmann_eval_transmit( + bsdf, N, I, omega_in, pdf, alpha_x, alpha_y, cosNO, cosNI) : + bsdf_microfacet_beckmann_eval_reflect( + bsdf, N, I, omega_in, pdf, alpha_x, alpha_y, cosNO, cosNI); +} + +ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals kg, + ccl_private const ShaderClosure *sc, + float3 Ng, + float3 I, + float randu, + float randv, + ccl_private Spectrum *eval, + ccl_private float3 *omega_in, + ccl_private float *pdf, + ccl_private float2 *sampled_roughness, + ccl_private float *eta) +{ + ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + bool m_refractive = bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; + float3 N = bsdf->N; + int label; + + *sampled_roughness = make_float2(alpha_x, alpha_y); + *eta = m_refractive ? 1.0f / bsdf->ior : bsdf->ior; + + float cosNO = dot(N, I); + if (cosNO > 0) { + float3 X, Y, Z = N; + + if (alpha_x == alpha_y) + make_orthonormals(Z, &X, &Y); + else + make_orthonormals_tangent(Z, bsdf->T, &X, &Y); + + /* importance sampling with distribution of visible normals. vectors are + * transformed to local space before and after */ + float3 local_I = make_float3(dot(X, I), dot(Y, I), cosNO); + float3 local_m; + float G1o; + + local_m = microfacet_sample_stretched(kg, local_I, alpha_x, alpha_x, randu, randv, &G1o); + + float3 m = X * local_m.x + Y * local_m.y + Z * local_m.z; + float cosThetaM = local_m.z; + + /* reflection or refraction? */ + if (!m_refractive) { + label = LABEL_REFLECT | LABEL_GLOSSY; + float cosMO = dot(m, I); + + if (cosMO > 0) { + /* eq. 39 - compute actual reflected direction */ + *omega_in = 2 * cosMO * m - I; + + if (dot(Ng, *omega_in) > 0) { + if (alpha_x * alpha_y <= 1e-7f) { + /* some high number for MIS */ + *pdf = 1e6f; + *eval = make_spectrum(1e6f); + label = LABEL_REFLECT | LABEL_SINGULAR; + } + else { + /* microfacet normal is visible to this ray + * eq. 25 */ + float alpha2 = alpha_x * alpha_y; + float D, G1i; + + if (alpha_x == alpha_y) { + /* Isotropic distribution. */ + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float tanThetaM2 = 1 / (cosThetaM2)-1; + D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + + /* eval BRDF*cosNI */ + float cosNI = dot(N, *omega_in); + + /* eq. 26, 27: now calculate G1(i,m) */ + G1i = bsdf_beckmann_G1(alpha_x, cosNI); + } + else { + /* anisotropic distribution */ + float3 local_m = make_float3(dot(X, m), dot(Y, m), dot(Z, m)); + float slope_x = -local_m.x / (local_m.z * alpha_x); + float slope_y = -local_m.y / (local_m.z * alpha_y); + + float cosThetaM = local_m.z; + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + + D = expf(-slope_x * slope_x - slope_y * slope_y) / (M_PI_F * alpha2 * cosThetaM4); + + /* G1(i,m) */ + G1i = bsdf_beckmann_aniso_G1( + alpha_x, alpha_y, dot(*omega_in, N), dot(*omega_in, X), dot(*omega_in, Y)); + } + + float G = G1o * G1i; + + /* see eval function for derivation */ + float common = D * 0.25f / cosNO; + float out = G * common; + *pdf = G1o * common; + + *eval = make_spectrum(out); + } + } + else { + *eval = zero_spectrum(); + *pdf = 0.0f; + } + } + } + else { + label = LABEL_TRANSMIT | LABEL_GLOSSY; + + /* CAUTION: the i and o variables are inverted relative to the paper + * eq. 39 - compute actual refractive direction */ + float3 R, T; + float m_eta = bsdf->ior, fresnel; + bool inside; + + fresnel = fresnel_dielectric(m_eta, m, I, &R, &T, &inside); + + if (!inside && fresnel != 1.0f) { + *omega_in = T; + + if (alpha_x * alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { + /* some high number for MIS */ + *pdf = 1e6f; + *eval = make_spectrum(1e6f); + label = LABEL_TRANSMIT | LABEL_SINGULAR; + } + else { + /* eq. 33 */ + float alpha2 = alpha_x * alpha_y; + float cosThetaM2 = cosThetaM * cosThetaM; + float cosThetaM4 = cosThetaM2 * cosThetaM2; + float tanThetaM2 = 1 / (cosThetaM2)-1; + float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); + + /* eval BRDF*cosNI */ + float cosNI = dot(N, *omega_in); + + /* eq. 26, 27: now calculate G1(i,m) */ + float G1i = bsdf_beckmann_G1(alpha_x, cosNI); + float G = G1o * G1i; + + /* eq. 21 */ + float cosHI = dot(m, *omega_in); + float cosHO = dot(m, I); + float Ht2 = m_eta * cosHI + cosHO; + Ht2 *= Ht2; + + /* see eval function for derivation */ + float common = D * (m_eta * m_eta) / (cosNO * Ht2); + float out = G * fabsf(cosHI * cosHO) * common; + *pdf = G1o * cosHO * fabsf(cosHI) * common; + + *eval = make_spectrum(out); + } + } + else { + *eval = zero_spectrum(); + *pdf = 0.0f; + } + } + } + else { + label = (m_refractive) ? LABEL_TRANSMIT | LABEL_GLOSSY : LABEL_REFLECT | LABEL_GLOSSY; + } + return label; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_glass.h b/intern/cycles/kernel/closure/bsdf_microfacet_glass.h new file mode 100644 index 00000000000..3c0ea32447b --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_microfacet_glass.h @@ -0,0 +1,283 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#pragma once + +#include "kernel/sample/lcg.h" + +#include "util/hash.h" + +CCL_NAMESPACE_BEGIN + +ccl_device_inline Spectrum +microfacet_ggx_glass_albedo_scaling(KernelGlobals kg, + ccl_private const ShaderData *sd, + ccl_private const MicrofacetBsdf *bsdf, + const Spectrum Fss) +{ + float mu = dot(sd->I, bsdf->N); + float rough = sqrtf(sqrtf(bsdf->alpha_x * bsdf->alpha_y)); + float E = microfacet_ggx_glass_E(kg, mu, rough, bsdf->ior); + + /* Close enough for glass, coloring here is unphysical anyways and it's unclear how to + * approximate it better. */ + Spectrum Fms = Fss; + + return one_spectrum() + Fms * ((1.0f - E) / E); + /* TODO: Ensure that increase in weight does not mess up glossy color, albedo etc. passes */ +} + +/* Currently no non-albedo-scaled version is implemented, could easily be added + * but would still break compatibility with the old glass due to the microfacet Fresnel. */ + +ccl_device int bsdf_microfacet_multi_ggx_glass_setup(KernelGlobals kg, + ccl_private MicrofacetBsdf *bsdf, + ccl_private const ShaderData *sd, + const Spectrum color) +{ + bsdf->extra = NULL; + + bsdf->alpha_x = saturatef(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; + + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + + bsdf->weight *= microfacet_ggx_glass_albedo_scaling(kg, sd, bsdf, saturate(color)); + + return SD_BSDF | SD_BSDF_HAS_EVAL; +} + +ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(KernelGlobals kg, + ccl_private MicrofacetBsdf *bsdf, + ccl_private const ShaderData *sd) +{ + bsdf->extra->cspec0 = saturate(bsdf->extra->cspec0); + + bsdf->alpha_x = saturatef(bsdf->alpha_x); + bsdf->alpha_y = bsdf->alpha_x; + + bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID; + + bsdf_microfacet_fresnel_color(sd, bsdf); + + Spectrum Fss = schlick_fresnel_Fss(bsdf->extra->cspec0); + bsdf->weight *= microfacet_ggx_glass_albedo_scaling(kg, sd, bsdf, Fss); + + return SD_BSDF | SD_BSDF_HAS_EVAL; +} + +ccl_device Spectrum bsdf_microfacet_ggx_glass_eval_reflect(ccl_private const MicrofacetBsdf *bsdf, + const float3 N, + const float3 I, + const float3 omega_in, + ccl_private float *pdf, + const float alpha_x, + const float alpha_y, + const float cosNO, + const float cosNI) +{ + if (cosNI <= 0 || cosNO <= 0) { + *pdf = 0.0f; + return zero_spectrum(); + } + + float alpha2 = alpha_x * alpha_y; + float3 m = normalize(omega_in + I); + float D = microfacet_ggx_D(dot(N, m), alpha2); + float lambdaO = microfacet_ggx_lambda(cosNO, alpha2); + float lambdaI = microfacet_ggx_lambda(cosNI, alpha2); + + float common = D * 0.25f / cosNO; + + float F = fresnel_dielectric_cos(dot(m, I), bsdf->ior); + float out = F * common / (1 + lambdaO + lambdaI); + *pdf = common / (1 + lambdaO); + + Spectrum eval = make_spectrum(out); + if (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID) { + eval *= reflection_color(bsdf, omega_in, m); + } + return eval; +} + +ccl_device Spectrum bsdf_microfacet_ggx_glass_eval_transmit(ccl_private const MicrofacetBsdf *bsdf, + const float3 N, + const float3 I, + const float3 omega_in, + ccl_private float *pdf, + const float alpha_x, + const float alpha_y, + const float cosNO, + const float cosNI) +{ + + if (cosNO <= 0 || cosNI >= 0) { + *pdf = 0.0f; + return zero_spectrum(); + } + + float eta = bsdf->ior; + float3 ht = -(eta * omega_in + I); + float3 m = normalize(ht); + float cosMO = dot(m, I); + float cosMI = dot(m, omega_in); + + float F = fresnel_dielectric_cos(cosMO, eta); + if (F == 1.0f) { + /* TIR */ + *pdf = 0.0f; + return zero_spectrum(); + } + + float alpha2 = alpha_x * alpha_y; + float D = microfacet_ggx_D(dot(N, m), alpha2); + float lambdaO = microfacet_ggx_lambda(cosNO, alpha2); + float lambdaI = microfacet_ggx_lambda(cosNI, alpha2); + + float Ht2 = dot(ht, ht); + + float common = fabsf(cosMI * cosMO) * D * sqr(eta) / (cosNO * Ht2); + float out = (1.0f - F) * common / (1 + lambdaO + lambdaI); + *pdf = common / (1 + lambdaO); + + Spectrum eval = make_spectrum(out); + if (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID) { + eval *= bsdf->extra->color; + } + return eval; +} + +ccl_device Spectrum bsdf_microfacet_ggx_glass_eval(ccl_private const ShaderClosure *sc, + const float3 I, + const float3 omega_in, + ccl_private float *pdf) +{ + ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; + const float alpha_x = bsdf->alpha_x; + const float alpha_y = bsdf->alpha_y; + const float3 N = bsdf->N; + const float cosNO = dot(N, I); + const float cosNI = dot(N, omega_in); + + if (alpha_x * alpha_y <= 1e-7f) { + *pdf = 0.0f; + return zero_spectrum(); + } + + return (cosNI < 0.0f) ? bsdf_microfacet_ggx_glass_eval_transmit( + bsdf, N, I, omega_in, pdf, alpha_x, alpha_y, cosNO, cosNI) : + bsdf_microfacet_ggx_glass_eval_reflect( + bsdf, N, I, omega_in, pdf, alpha_x, alpha_y, cosNO, cosNI); +} + +ccl_device int bsdf_microfacet_ggx_glass_sample(ccl_private const ShaderClosure *sc, + float3 Ng, + float3 I, + float randu, + float randv, + ccl_private Spectrum *eval, + ccl_private float3 *omega_in, + ccl_private float *pdf, + ccl_private float2 *sampled_roughness, + ccl_private float *eta) +{ + ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; + float alpha_x = bsdf->alpha_x; + float alpha_y = bsdf->alpha_y; + float3 N = bsdf->N; + int label; + + *sampled_roughness = make_float2(alpha_x, alpha_y); + *eta = bsdf->ior; // TODO: Do we need to invert in case of refraction? + + float cosNO = dot(N, I); + if (cosNO <= 0) { + *pdf = 0.0f; + return LABEL_NONE; + } + + float3 X, Y, Z = N; + make_orthonormals(Z, &X, &Y); + + /* importance sampling with distribution of visible normals. vectors are + * transformed to local space before and after */ + float3 local_O = make_float3(dot(X, I), dot(Y, I), cosNO); + float3 local_m = microfacet_ggx_sample_vndf(local_O, alpha_x, alpha_y, randu, randv); + + float3 m = X * local_m.x + Y * local_m.y + Z * local_m.z; + float cosThetaM = local_m.z; + + float cosMO = dot(m, I); + if (cosMO <= 0.0f) { + *pdf = 0.0f; + return LABEL_NONE; + } + + float3 R, T; + bool inside; /* Will never be inside, we already checked cosMO */ + float fresnel = fresnel_dielectric(bsdf->ior, m, I, &R, &T, &inside); + + // TODO: Somehow get a properly stratified value here, this causes considerable noise + float randw = hash_float2_to_float(make_float2(randu, randv)); + bool do_reflect = randw < fresnel; + + float alpha2 = alpha_x * alpha_y; + if (alpha2 <= 1e-7f) { + /* Specular case, just return some high number for MIS */ + *pdf = 1e6f; + *eval = make_float3(1e6f, 1e6f, 1e6f); + + *omega_in = do_reflect ? R : T; + + if (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID) { + *eval *= do_reflect ? reflection_color(bsdf, *omega_in, m) : bsdf->extra->color; + } + + return LABEL_SINGULAR | (do_reflect ? LABEL_REFLECT : LABEL_TRANSMIT); + } + + /* Common microfacet model terms. */ + float D = microfacet_ggx_D(cosThetaM, alpha2); + float lambdaO = microfacet_ggx_lambda(cosNO, alpha2); + + float cosNI, common; + if (do_reflect) { + cosNI = dot(N, R); + if (cosNI <= 0.0f || dot(Ng, R) <= 0.0f) { + *pdf = 0.0f; + return LABEL_NONE; + } + + label = LABEL_REFLECT | LABEL_GLOSSY; + *omega_in = R; + + common = fresnel * D * 0.25f / cosNO; + } + else { + cosNI = dot(N, T); + if (cosNI >= 0.0f || dot(Ng, T) >= 0.0f) { + *pdf = 0.0f; + return LABEL_NONE; + } + + label = LABEL_TRANSMIT | LABEL_GLOSSY; + *omega_in = T; + + float cosMI = dot(m, *omega_in); + float Ht2 = sqr(bsdf->ior * cosMI + cosMO); + + common = (1.0f - fresnel) * D * fabsf(cosMI * cosMO) * sqr(bsdf->ior) / (cosNO * Ht2); + } + + float lambdaI = microfacet_ggx_lambda(cosNI, alpha2); + float out = common / (1 + lambdaO + lambdaI); + *pdf = common / (1 + lambdaO); + *eval = make_spectrum(out); + + if (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID) { + *eval *= do_reflect ? reflection_color(bsdf, *omega_in, m) : bsdf->extra->color; + } + return label; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h deleted file mode 100644 index 73cc0d292a1..00000000000 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h +++ /dev/null @@ -1,686 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 - * Copyright 2011-2022 Blender Foundation */ - -#pragma once - -#include "kernel/sample/lcg.h" -#include "kernel/sample/mapping.h" - -CCL_NAMESPACE_BEGIN - -/* Most of the code is based on the supplemental implementations from - * https://eheitzresearch.wordpress.com/240-2/. */ - -/* === GGX Microfacet distribution functions === */ - -/* Isotropic GGX microfacet distribution */ -ccl_device_forceinline float D_ggx(float3 wm, float alpha) -{ - wm.z *= wm.z; - alpha *= alpha; - float tmp = (1.0f - wm.z) + alpha * wm.z; - return alpha / max(M_PI_F * tmp * tmp, 1e-7f); -} - -/* Anisotropic GGX microfacet distribution */ -ccl_device_forceinline float D_ggx_aniso(const float3 wm, const float2 alpha) -{ - float slope_x = -wm.x / alpha.x; - float slope_y = -wm.y / alpha.y; - float tmp = wm.z * wm.z + slope_x * slope_x + slope_y * slope_y; - - return 1.0f / max(M_PI_F * tmp * tmp * alpha.x * alpha.y, 1e-7f); -} - -/* Sample slope distribution (based on page 14 of the supplemental implementation). */ -ccl_device_forceinline float2 mf_sampleP22_11(const float cosI, - const float randx, - const float randy) -{ - if (cosI > 0.9999f || fabsf(cosI) < 1e-6f) { - const float r = sqrtf(randx / max(1.0f - randx, 1e-7f)); - const float phi = M_2PI_F * randy; - return make_float2(r * cosf(phi), r * sinf(phi)); - } - - const float sinI = safe_sqrtf(1.0f - cosI * cosI); - const float tanI = sinI / cosI; - const float projA = 0.5f * (cosI + 1.0f); - if (projA < 0.0001f) - return make_float2(0.0f, 0.0f); - const float A = 2.0f * randx * projA / cosI - 1.0f; - float tmp = A * A - 1.0f; - if (fabsf(tmp) < 1e-7f) - return make_float2(0.0f, 0.0f); - tmp = 1.0f / tmp; - const float D = safe_sqrtf(tanI * tanI * tmp * tmp - (A * A - tanI * tanI) * tmp); - - const float slopeX2 = tanI * tmp + D; - const float slopeX = (A < 0.0f || slopeX2 > 1.0f / tanI) ? (tanI * tmp - D) : slopeX2; - - float U2; - if (randy >= 0.5f) - U2 = 2.0f * (randy - 0.5f); - else - U2 = 2.0f * (0.5f - randy); - const float z = (U2 * (U2 * (U2 * 0.27385f - 0.73369f) + 0.46341f)) / - (U2 * (U2 * (U2 * 0.093073f + 0.309420f) - 1.0f) + 0.597999f); - const float slopeY = z * sqrtf(1.0f + slopeX * slopeX); - - if (randy >= 0.5f) - return make_float2(slopeX, slopeY); - else - return make_float2(slopeX, -slopeY); -} - -/* Visible normal sampling for the GGX distribution - * (based on page 7 of the supplemental implementation). */ -ccl_device_forceinline float3 mf_sample_vndf(const float3 wi, - const float2 alpha, - const float randx, - const float randy) -{ - const float3 wi_11 = normalize(make_float3(alpha.x * wi.x, alpha.y * wi.y, wi.z)); - const float2 slope_11 = mf_sampleP22_11(wi_11.z, randx, randy); - - const float3 cossin_phi = safe_normalize(make_float3(wi_11.x, wi_11.y, 0.0f)); - const float slope_x = alpha.x * (cossin_phi.x * slope_11.x - cossin_phi.y * slope_11.y); - const float slope_y = alpha.y * (cossin_phi.y * slope_11.x + cossin_phi.x * slope_11.y); - - kernel_assert(isfinite(slope_x)); - return normalize(make_float3(-slope_x, -slope_y, 1.0f)); -} - -/* === Phase functions: Glossy and Glass === */ - -/* Phase function for reflective materials. */ -ccl_device_forceinline float3 mf_sample_phase_glossy(const float3 wi, - ccl_private Spectrum *weight, - const float3 wm) -{ - return -wi + 2.0f * wm * dot(wi, wm); -} - -ccl_device_forceinline Spectrum mf_eval_phase_glossy(const float3 w, - const float lambda, - const float3 wo, - const float2 alpha) -{ - if (w.z > 0.9999f) - return zero_spectrum(); - - const float3 wh = normalize(wo - w); - if (wh.z < 0.0f) - return zero_spectrum(); - - float pArea = (w.z < -0.9999f) ? 1.0f : lambda * w.z; - - const float dotW_WH = dot(-w, wh); - if (dotW_WH < 0.0f) - return zero_spectrum(); - - float phase = max(0.0f, dotW_WH) * 0.25f / max(pArea * dotW_WH, 1e-7f); - if (alpha.x == alpha.y) - phase *= D_ggx(wh, alpha.x); - else - phase *= D_ggx_aniso(wh, alpha); - - return make_spectrum(phase); -} - -/* Phase function for dielectric transmissive materials, including both reflection and refraction - * according to the dielectric fresnel term. */ -ccl_device_forceinline float3 mf_sample_phase_glass(const float3 wi, - const float eta, - const float3 wm, - const float randV, - ccl_private bool *outside) -{ - float cosI = dot(wi, wm); - float f = fresnel_dielectric_cos(cosI, eta); - if (randV < f) { - *outside = true; - return -wi + 2.0f * wm * cosI; - } - *outside = false; - float inv_eta = 1.0f / eta; - float cosT = -safe_sqrtf(1.0f - (1.0f - cosI * cosI) * inv_eta * inv_eta); - return normalize(wm * (cosI * inv_eta + cosT) - wi * inv_eta); -} - -ccl_device_forceinline Spectrum mf_eval_phase_glass(const float3 w, - const float lambda, - const float3 wo, - const bool wo_outside, - const float2 alpha, - const float eta) -{ - if (w.z > 0.9999f) - return zero_spectrum(); - - float pArea = (w.z < -0.9999f) ? 1.0f : lambda * w.z; - float v; - if (wo_outside) { - const float3 wh = normalize(wo - w); - if (wh.z < 0.0f) - return zero_spectrum(); - - const float dotW_WH = dot(-w, wh); - v = fresnel_dielectric_cos(dotW_WH, eta) * max(0.0f, dotW_WH) * D_ggx(wh, alpha.x) * 0.25f / - (pArea * dotW_WH); - } - else { - float3 wh = normalize(wo * eta - w); - if (wh.z < 0.0f) - wh = -wh; - const float dotW_WH = dot(-w, wh), dotWO_WH = dot(wo, wh); - if (dotW_WH < 0.0f) - return zero_spectrum(); - - float temp = dotW_WH + eta * dotWO_WH; - v = (1.0f - fresnel_dielectric_cos(dotW_WH, eta)) * max(0.0f, dotW_WH) * max(0.0f, -dotWO_WH) * - D_ggx(wh, alpha.x) / (pArea * temp * temp); - } - - return make_spectrum(v); -} - -/* === Utility functions for the random walks === */ - -/* Smith Lambda function for GGX (based on page 12 of the supplemental implementation). */ -ccl_device_forceinline float mf_lambda(const float3 w, const float2 alpha) -{ - if (w.z > 0.9999f) - return 0.0f; - else if (w.z < -0.9999f) - return -0.9999f; - - const float inv_wz2 = 1.0f / max(w.z * w.z, 1e-7f); - const float2 wa = make_float2(w.x, w.y) * alpha; - float v = sqrtf(1.0f + dot(wa, wa) * inv_wz2); - if (w.z <= 0.0f) - v = -v; - - return 0.5f * (v - 1.0f); -} - -/* Height distribution CDF (based on page 4 of the supplemental implementation). */ -ccl_device_forceinline float mf_invC1(const float h) -{ - return 2.0f * saturatef(h) - 1.0f; -} - -ccl_device_forceinline float mf_C1(const float h) -{ - return saturatef(0.5f * (h + 1.0f)); -} - -/* Masking function (based on page 16 of the supplemental implementation). */ -ccl_device_forceinline float mf_G1(const float3 w, const float C1, const float lambda) -{ - if (w.z > 0.9999f) - return 1.0f; - if (w.z < 1e-5f) - return 0.0f; - return powf(C1, lambda); -} - -/* Sampling from the visible height distribution (based on page 17 of the supplemental - * implementation). */ -ccl_device_forceinline bool mf_sample_height(const float3 w, - ccl_private float *h, - ccl_private float *C1, - ccl_private float *G1, - ccl_private float *lambda, - const float U) -{ - if (w.z > 0.9999f) - return false; - if (w.z < -0.9999f) { - *C1 *= U; - *h = mf_invC1(*C1); - *G1 = mf_G1(w, *C1, *lambda); - } - else if (fabsf(w.z) >= 0.0001f) { - if (U > 1.0f - *G1) - return false; - if (*lambda >= 0.0f) { - *C1 = 1.0f; - } - else { - *C1 *= powf(1.0f - U, -1.0f / *lambda); - } - *h = mf_invC1(*C1); - *G1 = mf_G1(w, *C1, *lambda); - } - return true; -} - -/* === PDF approximations for the different phase functions. === - * As explained in bsdf_microfacet_multi_impl.h, using approximations with MIS still produces an - * unbiased result. */ - -/* Approximation for the albedo of the single-scattering GGX distribution, - * the missing energy is then approximated as a diffuse reflection for the PDF. */ -ccl_device_forceinline float mf_ggx_albedo(float r) -{ - float albedo = 0.806495f * expf(-1.98712f * r * r) + 0.199531f; - albedo -= ((((((1.76741f * r - 8.43891f) * r + 15.784f) * r - 14.398f) * r + 6.45221f) * r - - 1.19722f) * - r + - 0.027803f) * - r + - 0.00568739f; - return saturatef(albedo); -} - -ccl_device_inline float mf_ggx_transmission_albedo(float a, float ior) -{ - if (ior < 1.0f) { - ior = 1.0f / ior; - } - a = saturatef(a); - ior = clamp(ior, 1.0f, 3.0f); - float I_1 = 0.0476898f * expf(-0.978352f * (ior - 0.65657f) * (ior - 0.65657f)) - - 0.033756f * ior + 0.993261f; - float R_1 = (((0.116991f * a - 0.270369f) * a + 0.0501366f) * a - 0.00411511f) * a + 1.00008f; - float I_2 = (((-2.08704f * ior + 26.3298f) * ior - 127.906f) * ior + 292.958f) * ior - 287.946f + - 199.803f / (ior * ior) - 101.668f / (ior * ior * ior); - float R_2 = ((((5.3725f * a - 24.9307f) * a + 22.7437f) * a - 3.40751f) * a + 0.0986325f) * a + - 0.00493504f; - - return saturatef(1.0f + I_2 * R_2 * 0.0019127f - (1.0f - I_1) * (1.0f - R_1) * 9.3205f); -} - -ccl_device_forceinline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha) -{ - float D = D_ggx(normalize(wi + wo), alpha); - float lambda = mf_lambda(wi, make_float2(alpha, alpha)); - float singlescatter = 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f); - - float multiscatter = wo.z * M_1_PI_F; - - float albedo = mf_ggx_albedo(alpha); - return albedo * singlescatter + (1.0f - albedo) * multiscatter; -} - -ccl_device_forceinline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha) -{ - float D = D_ggx_aniso(normalize(wi + wo), alpha); - float lambda = mf_lambda(wi, alpha); - float singlescatter = 0.25f * D / max((1.0f + lambda) * wi.z, 1e-7f); - - float multiscatter = wo.z * M_1_PI_F; - - float albedo = mf_ggx_albedo(sqrtf(alpha.x * alpha.y)); - return albedo * singlescatter + (1.0f - albedo) * multiscatter; -} - -ccl_device_forceinline float mf_glass_pdf(const float3 wi, - const float3 wo, - const float alpha, - const float eta) -{ - bool reflective = (wi.z * wo.z > 0.0f); - - float wh_len; - float3 wh = normalize_len(wi + (reflective ? wo : (wo * eta)), &wh_len); - if (wh.z < 0.0f) - wh = -wh; - float3 r_wi = (wi.z < 0.0f) ? -wi : wi; - float lambda = mf_lambda(r_wi, make_float2(alpha, alpha)); - float D = D_ggx(wh, alpha); - float fresnel = fresnel_dielectric_cos(dot(r_wi, wh), eta); - - float multiscatter = fabsf(wo.z * M_1_PI_F); - if (reflective) { - float singlescatter = 0.25f * D / max((1.0f + lambda) * r_wi.z, 1e-7f); - float albedo = mf_ggx_albedo(alpha); - return fresnel * (albedo * singlescatter + (1.0f - albedo) * multiscatter); - } - else { - float singlescatter = fabsf(dot(r_wi, wh) * dot(wo, wh) * D * eta * eta / - max((1.0f + lambda) * r_wi.z * wh_len * wh_len, 1e-7f)); - float albedo = mf_ggx_transmission_albedo(alpha, eta); - return (1.0f - fresnel) * (albedo * singlescatter + (1.0f - albedo) * multiscatter); - } -} - -/* === Actual random walk implementations === */ -/* One version of mf_eval and mf_sample per phase function. */ - -#define MF_NAME_JOIN(x, y) x##_##y -#define MF_NAME_EVAL(x, y) MF_NAME_JOIN(x, y) -#define MF_FUNCTION_FULL_NAME(prefix) MF_NAME_EVAL(prefix, MF_PHASE_FUNCTION) - -#define MF_PHASE_FUNCTION glass -#define MF_MULTI_GLASS -#include "kernel/closure/bsdf_microfacet_multi_impl.h" - -#define MF_PHASE_FUNCTION glossy -#define MF_MULTI_GLOSSY -#include "kernel/closure/bsdf_microfacet_multi_impl.h" - -ccl_device void bsdf_microfacet_multi_ggx_blur(ccl_private ShaderClosure *sc, float roughness) -{ - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc; - - bsdf->alpha_x = fmaxf(roughness, bsdf->alpha_x); - bsdf->alpha_y = fmaxf(roughness, bsdf->alpha_y); -} - -/* === Closure implementations === */ - -/* Multi-scattering GGX Glossy closure */ - -ccl_device int bsdf_microfacet_multi_ggx_common_setup(ccl_private MicrofacetBsdf *bsdf) -{ - bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); - bsdf->alpha_y = clamp(bsdf->alpha_y, 1e-4f, 1.0f); - bsdf->extra->color = saturate(bsdf->extra->color); - bsdf->extra->cspec0 = saturate(bsdf->extra->cspec0); - - return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG; -} - -ccl_device int bsdf_microfacet_multi_ggx_setup(ccl_private MicrofacetBsdf *bsdf) -{ - if (is_zero(bsdf->T)) - bsdf->T = make_float3(1.0f, 0.0f, 0.0f); - - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; - - return bsdf_microfacet_multi_ggx_common_setup(bsdf); -} - -ccl_device int bsdf_microfacet_multi_ggx_fresnel_setup(ccl_private MicrofacetBsdf *bsdf, - ccl_private const ShaderData *sd) -{ - if (is_zero(bsdf->T)) - bsdf->T = make_float3(1.0f, 0.0f, 0.0f); - - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID; - - bsdf_microfacet_fresnel_color(sd, bsdf); - - return bsdf_microfacet_multi_ggx_common_setup(bsdf); -} - -ccl_device int bsdf_microfacet_multi_ggx_refraction_setup(ccl_private MicrofacetBsdf *bsdf) -{ - bsdf->alpha_y = bsdf->alpha_x; - - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; - - return bsdf_microfacet_multi_ggx_common_setup(bsdf); -} - -ccl_device Spectrum bsdf_microfacet_multi_ggx_eval(ccl_private const ShaderClosure *sc, - const float3 I, - const float3 omega_in, - ccl_private float *pdf, - ccl_private uint *lcg_state) -{ - ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; - - if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { - *pdf = 0.0f; - return zero_spectrum(); - } - - float3 X, Y, Z; - Z = bsdf->N; - - /* Ensure that the both directions are on the outside w.r.t. the shading normal. */ - if (dot(Z, I) <= 0.0f || dot(Z, omega_in) <= 0.0f) { - *pdf = 0.0f; - return zero_spectrum(); - } - - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID); - - bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y); - if (is_aniso) - make_orthonormals_tangent(Z, bsdf->T, &X, &Y); - else - make_orthonormals(Z, &X, &Y); - - float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); - float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); - - if (is_aniso) - *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y)); - else - *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x); - - if (*pdf <= 0.f) { - *pdf = 0.f; - return make_float3(0.f, 0.f, 0.f); - } - - return mf_eval_glossy(localI, - localO, - true, - bsdf->extra->color, - bsdf->alpha_x, - bsdf->alpha_y, - lcg_state, - bsdf->ior, - use_fresnel, - bsdf->extra->cspec0); -} - -ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals kg, - ccl_private const ShaderClosure *sc, - float3 Ng, - float3 I, - float randu, - float randv, - ccl_private Spectrum *eval, - ccl_private float3 *omega_in, - ccl_private float *pdf, - ccl_private uint *lcg_state, - ccl_private float2 *sampled_roughness, - ccl_private float *eta) -{ - ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; - - float3 X, Y, Z; - Z = bsdf->N; - - /* Ensure that the view direction is on the outside w.r.t. the shading normal. */ - if (dot(Z, I) <= 0.0f) { - *pdf = 0.0f; - return LABEL_NONE; - } - - /* Special case: Extremely low roughness. - * Don't bother with microfacets, just do specular reflection. */ - if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { - *omega_in = 2 * dot(Z, I) * Z - I; - if (dot(Ng, *omega_in) <= 0.0f) { - *pdf = 0.0f; - return LABEL_NONE; - } - *pdf = 1e6f; - *eval = make_spectrum(1e6f); - return LABEL_REFLECT | LABEL_SINGULAR; - } - - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID); - - *eta = bsdf->ior; - *sampled_roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y); - - bool is_aniso = (bsdf->alpha_x != bsdf->alpha_y); - if (is_aniso) - make_orthonormals_tangent(Z, bsdf->T, &X, &Y); - else - make_orthonormals(Z, &X, &Y); - - float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); - float3 localO; - - *eval = mf_sample_glossy(localI, - &localO, - bsdf->extra->color, - bsdf->alpha_x, - bsdf->alpha_y, - lcg_state, - bsdf->ior, - use_fresnel, - bsdf->extra->cspec0); - *omega_in = X * localO.x + Y * localO.y + Z * localO.z; - - /* Ensure that the light direction is on the outside w.r.t. the geometry normal. */ - if (dot(Ng, *omega_in) <= 0.0f) { - *pdf = 0.0f; - return LABEL_NONE; - } - - if (is_aniso) - *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(bsdf->alpha_x, bsdf->alpha_y)); - else - *pdf = mf_ggx_pdf(localI, localO, bsdf->alpha_x); - *pdf = fmaxf(0.f, *pdf); - *eval *= *pdf; - - return LABEL_REFLECT | LABEL_GLOSSY; -} - -/* Multi-scattering GGX Glass closure */ - -ccl_device int bsdf_microfacet_multi_ggx_glass_setup(ccl_private MicrofacetBsdf *bsdf) -{ - bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); - bsdf->alpha_y = bsdf->alpha_x; - bsdf->ior = max(0.0f, bsdf->ior); - bsdf->extra->color = saturate(bsdf->extra->color); - - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; - - return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG; -} - -ccl_device int bsdf_microfacet_multi_ggx_glass_fresnel_setup(ccl_private MicrofacetBsdf *bsdf, - ccl_private const ShaderData *sd) -{ - bsdf->alpha_x = clamp(bsdf->alpha_x, 1e-4f, 1.0f); - bsdf->alpha_y = bsdf->alpha_x; - bsdf->ior = max(0.0f, bsdf->ior); - bsdf->extra->color = saturate(bsdf->extra->color); - bsdf->extra->cspec0 = saturate(bsdf->extra->cspec0); - - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID; - - bsdf_microfacet_fresnel_color(sd, bsdf); - - return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG; -} - -ccl_device Spectrum bsdf_microfacet_multi_ggx_glass_eval(ccl_private const ShaderClosure *sc, - const float3 I, - const float3 omega_in, - ccl_private float *pdf, - ccl_private uint *lcg_state) -{ - ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; - - if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { - *pdf = 0.0f; - return zero_spectrum(); - } - - float3 X, Y, Z; - Z = bsdf->N; - make_orthonormals(Z, &X, &Y); - - float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); - float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); - - const bool is_transmission = localO.z < 0.0f; - const bool use_fresnel = !is_transmission && - (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); - - *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); - kernel_assert(*pdf >= 0.f); - return mf_eval_glass(localI, - localO, - !is_transmission, - bsdf->extra->color, - bsdf->alpha_x, - bsdf->alpha_y, - lcg_state, - bsdf->ior, - use_fresnel, - (is_transmission) ? bsdf->extra->color : bsdf->extra->cspec0); -} - -ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals kg, - ccl_private const ShaderClosure *sc, - float3 Ng, - float3 I, - float randu, - float randv, - ccl_private Spectrum *eval, - ccl_private float3 *omega_in, - ccl_private float *pdf, - ccl_private uint *lcg_state, - ccl_private float2 *sampled_roughness, - ccl_private float *eta) -{ - ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; - - float3 X, Y, Z; - Z = bsdf->N; - - *eta = bsdf->ior; - *sampled_roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y); - - if (bsdf->alpha_x * bsdf->alpha_y < 1e-7f) { - float3 R, T; - bool inside; - float fresnel = fresnel_dielectric(bsdf->ior, Z, I, &R, &T, &inside); - - *pdf = 1e6f; - *eval = make_spectrum(1e6f); - if (randu < fresnel) { - *omega_in = R; - return LABEL_REFLECT | LABEL_SINGULAR; - } - else { - *omega_in = T; - return LABEL_TRANSMIT | LABEL_SINGULAR; - } - } - - bool use_fresnel = (bsdf->type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); - - make_orthonormals(Z, &X, &Y); - - float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); - float3 localO; - - *eval = mf_sample_glass(localI, - &localO, - bsdf->extra->color, - bsdf->alpha_x, - bsdf->alpha_y, - lcg_state, - bsdf->ior, - use_fresnel, - bsdf->extra->cspec0); - *pdf = mf_glass_pdf(localI, localO, bsdf->alpha_x, bsdf->ior); - kernel_assert(*pdf >= 0.f); - *eval *= *pdf; - - *omega_in = X * localO.x + Y * localO.y + Z * localO.z; - if (localO.z * localI.z > 0.0f) { - return LABEL_REFLECT | LABEL_GLOSSY; - } - else { - return LABEL_TRANSMIT | LABEL_GLOSSY; - } -} - -CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h deleted file mode 100644 index 91fb9158050..00000000000 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h +++ /dev/null @@ -1,262 +0,0 @@ -/* SPDX-License-Identifier: Apache-2.0 - * Copyright 2011-2022 Blender Foundation */ - -/* Evaluate the BSDF from wi to wo. - * Evaluation is split into the analytical single-scattering BSDF and the multi-scattering BSDF, - * which is evaluated stochastically through a random walk. At each bounce (except for the first - * one), the amount of reflection from here towards wo is evaluated before bouncing again. - * - * Because of the random walk, the evaluation is not deterministic, but its expected value is equal - * to the correct BSDF, which is enough for Monte-Carlo rendering. The PDF also can't be determined - * analytically, so the single-scattering PDF plus a diffuse term to account for the - * multi-scattered energy is used. In combination with MIS, that is enough to produce an unbiased - * result, although the balance heuristic isn't necessarily optimal anymore. - */ -ccl_device_forceinline Spectrum MF_FUNCTION_FULL_NAME(mf_eval)(float3 wi, - float3 wo, - const bool wo_outside, - const Spectrum color, - const float alpha_x, - const float alpha_y, - ccl_private uint *lcg_state, - const float eta, - bool use_fresnel, - const Spectrum cspec0) -{ - /* Evaluating for a shallower incoming direction produces less noise, and the properties of the - * BSDF guarantee reciprocity. */ - bool swapped = false; -#ifdef MF_MULTI_GLASS - if (wi.z * wo.z < 0.0f) { - /* Glass transmission is a special case and requires the directions to change hemisphere. */ - if (-wo.z < wi.z) { - swapped = true; - float3 tmp = -wo; - wo = -wi; - wi = tmp; - } - } - else -#endif - if (wo.z < wi.z) { - swapped = true; - float3 tmp = wo; - wo = wi; - wi = tmp; - } - - if (wi.z < 1e-5f || (wo.z < 1e-5f && wo_outside) || (wo.z > -1e-5f && !wo_outside)) - return zero_spectrum(); - - const float2 alpha = make_float2(alpha_x, alpha_y); - - float lambda_r = mf_lambda(-wi, alpha); - float shadowing_lambda = mf_lambda(wo_outside ? wo : -wo, alpha); - - /* Analytically compute single scattering for lower noise. */ - Spectrum eval; - Spectrum throughput = one_spectrum(); - const float3 wh = normalize(wi + wo); -#ifdef MF_MULTI_GLASS - eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta); - if (wo_outside) - eval *= -lambda_r / (shadowing_lambda - lambda_r); - else - eval *= -lambda_r * beta(-lambda_r, shadowing_lambda + 1.0f); -#else /* MF_MULTI_GLOSSY */ - const float G2 = 1.0f / (1.0f - (lambda_r + 1.0f) + shadowing_lambda); - float val = G2 * 0.25f / wi.z; - if (alpha.x == alpha.y) - val *= D_ggx(wh, alpha.x); - else - val *= D_ggx_aniso(wh, alpha); - eval = make_spectrum(val); -#endif - - float F0 = fresnel_dielectric_cos(1.0f, eta); - if (use_fresnel) { - throughput = interpolate_fresnel_color(wi, wh, eta, F0, cspec0); - - eval *= throughput; - } - - float3 wr = -wi; - float hr = 1.0f; - float C1_r = 1.0f; - float G1_r = 0.0f; - bool outside = true; - - for (int order = 0; order < 10; order++) { - /* Sample microfacet height. */ - float height_rand = lcg_step_float(lcg_state); - if (!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand)) - break; - /* Sample microfacet normal. */ - float vndf_rand_y = lcg_step_float(lcg_state); - float vndf_rand_x = lcg_step_float(lcg_state); - float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y); - -#ifdef MF_MULTI_GLASS - if (order == 0 && use_fresnel) { - /* Evaluate amount of scattering towards wo on this microfacet. */ - Spectrum phase; - if (outside) - phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta); - else - phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f / eta); - - eval = throughput * phase * - mf_G1(wo_outside ? wo : -wo, - mf_C1((outside == wo_outside) ? hr : -hr), - shadowing_lambda); - } -#endif - if (order > 0) { - /* Evaluate amount of scattering towards wo on this microfacet. */ - Spectrum phase; -#ifdef MF_MULTI_GLASS - if (outside) - phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta); - else - phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f / eta); -#else /* MF_MULTI_GLOSSY */ - phase = mf_eval_phase_glossy(wr, lambda_r, wo, alpha) * throughput; -#endif - eval += throughput * phase * - mf_G1(wo_outside ? wo : -wo, - mf_C1((outside == wo_outside) ? hr : -hr), - shadowing_lambda); - } - if (order + 1 < 10) { - /* Bounce from the microfacet. */ -#ifdef MF_MULTI_GLASS - bool next_outside; - float3 wi_prev = -wr; - float phase_rand = lcg_step_float(lcg_state); - wr = mf_sample_phase_glass(-wr, outside ? eta : 1.0f / eta, wm, phase_rand, &next_outside); - if (!next_outside) { - outside = !outside; - wr = -wr; - hr = -hr; - } - - if (use_fresnel && !next_outside) { - throughput *= color; - } - else if (use_fresnel && order > 0) { - throughput *= interpolate_fresnel_color(wi_prev, wm, eta, F0, cspec0); - } -#else /* MF_MULTI_GLOSSY */ - if (use_fresnel && order > 0) { - throughput *= interpolate_fresnel_color(-wr, wm, eta, F0, cspec0); - } - wr = mf_sample_phase_glossy(-wr, &throughput, wm); -#endif - - lambda_r = mf_lambda(wr, alpha); - - if (!use_fresnel) - throughput *= color; - - C1_r = mf_C1(hr); - G1_r = mf_G1(wr, C1_r, lambda_r); - } - } - - if (swapped) - eval *= fabsf(wi.z / wo.z); - return eval; -} - -/* Perform a random walk on the microsurface starting from wi, returning the direction in which the - * walk escaped the surface in wo. The function returns the throughput between wi and wo. Without - * reflection losses due to coloring or fresnel absorption in conductors, the sampling is optimal. - */ -ccl_device_forceinline Spectrum MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, - ccl_private float3 *wo, - const Spectrum color, - const float alpha_x, - const float alpha_y, - ccl_private uint *lcg_state, - const float eta, - bool use_fresnel, - const Spectrum cspec0) -{ - const float2 alpha = make_float2(alpha_x, alpha_y); - - Spectrum throughput = one_spectrum(); - float3 wr = -wi; - float lambda_r = mf_lambda(wr, alpha); - float hr = 1.0f; - float C1_r = 1.0f; - float G1_r = 0.0f; - bool outside = true; - - float F0 = fresnel_dielectric_cos(1.0f, eta); - - int order; - for (order = 0; order < 10; order++) { - /* Sample microfacet height. */ - float height_rand = lcg_step_float(lcg_state); - if (!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, height_rand)) { - /* The random walk has left the surface. */ - *wo = outside ? wr : -wr; - return throughput; - } - /* Sample microfacet normal. */ - float vndf_rand_y = lcg_step_float(lcg_state); - float vndf_rand_x = lcg_step_float(lcg_state); - float3 wm = mf_sample_vndf(-wr, alpha, vndf_rand_x, vndf_rand_y); - - /* First-bounce color is already accounted for in mix weight. */ - if (!use_fresnel && order > 0) - throughput *= color; - - /* Bounce from the microfacet. */ -#ifdef MF_MULTI_GLASS - bool next_outside; - float3 wi_prev = -wr; - float phase_rand = lcg_step_float(lcg_state); - wr = mf_sample_phase_glass(-wr, outside ? eta : 1.0f / eta, wm, phase_rand, &next_outside); - if (!next_outside) { - hr = -hr; - wr = -wr; - outside = !outside; - } - - if (use_fresnel) { - if (!next_outside) { - throughput *= color; - } - else { - Spectrum t_color = interpolate_fresnel_color(wi_prev, wm, eta, F0, cspec0); - - if (order == 0) - throughput = t_color; - else - throughput *= t_color; - } - } -#else /* MF_MULTI_GLOSSY */ - if (use_fresnel) { - Spectrum t_color = interpolate_fresnel_color(-wr, wm, eta, F0, cspec0); - - if (order == 0) - throughput = t_color; - else - throughput *= t_color; - } - wr = mf_sample_phase_glossy(-wr, &throughput, wm); -#endif - - /* Update random walk parameters. */ - lambda_r = mf_lambda(wr, alpha); - G1_r = mf_G1(wr, C1_r, lambda_r); - } - *wo = make_float3(0.0f, 0.0f, 1.0f); - return zero_spectrum(); -} - -#undef MF_MULTI_GLASS -#undef MF_MULTI_GLOSSY -#undef MF_PHASE_FUNCTION diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_util.h b/intern/cycles/kernel/closure/bsdf_microfacet_util.h new file mode 100644 index 00000000000..b531c192e03 --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_microfacet_util.h @@ -0,0 +1,158 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#pragma once + +#include "kernel/closure/bsdf_util.h" + +#include "kernel/util/lookup_table.h" + +CCL_NAMESPACE_BEGIN + +/* GGX microfacet with Smith shadow-masking from: + * + * Microfacet Models for Refraction through Rough Surfaces + * B. Walter, S. R. Marschner, H. Li, K. E. Torrance, EGSR 2007 + * + * VNDF sampling as well as D and lambda terms from: + * + * Sampling the GGX Distribution of Visible Normals. + * E. Heitz and E. d'Eon, JCGT Vol. 7, No. 4, 2018. + * https://jcgt.org/published/0007/04/01/ + * + * Also see for more details on marking-shadowing: + * Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs. + * E. Heitz, JCGT Vol. 3, No. 2, 2014. + * https://jcgt.org/published/0003/02/03/ */ + +ccl_device_forceinline float microfacet_ggx_lambda(const float cosTheta, const float alpha2) +{ + float tanTheta2 = (1 - sqr(cosTheta)) / sqr(cosTheta); + return 0.5f * (safe_sqrtf(1 + alpha2 * tanTheta2) - 1); +} + +ccl_device_forceinline float microfacet_ggx_lambda_aniso(const float3 w, + const float alpha_x, + const float alpha_y) +{ + return 0.5f * (safe_sqrtf(1 + (sqr(w.x * alpha_x) + sqr(w.y * alpha_y)) / sqr(w.z)) - 1); +} + +ccl_device_forceinline float microfacet_ggx_D(const float cosThetaM, const float alpha2) +{ + float cosThetaM2 = sqr(cosThetaM); + float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2; + return alpha2 / (M_PI_F * sqr(cosThetaM2 * (alpha2 + tanThetaM2))); +} + +ccl_device_forceinline float microfacet_ggx_D_aniso(const float3 m, + const float alpha_x, + const float alpha_y) +{ + return 1 / + (M_PI_F * alpha_x * alpha_y * sqr(sqr(m.x / alpha_x) + sqr(m.y / alpha_y) + sqr(m.z))); +} + +ccl_device_forceinline float microfacet_GTR1_D(const float cosThetaM, const float alpha2) +{ + if (alpha2 >= 1.0f) + return M_1_PI_F; + float t = 1.0f + (alpha2 - 1.0f) * sqr(cosThetaM); + return (alpha2 - 1.0f) / (M_PI_F * logf(alpha2) * t); +} + +ccl_device_forceinline float3 microfacet_ggx_sample_vndf( + const float3 V, const float alpha_x, const float alpha_y, const float U1, const float U2) +{ + /* Section 3.2: Transforming the view direction to the hemisphere configuration. */ + float3 Vh = normalize(make_float3(alpha_x * V.x, alpha_y * V.y, V.z)); + /* Section 4.1: Orthonormal basis (with special case if cross product is zero). */ + float lensq = sqr(Vh.x) + sqr(Vh.y); + float3 T1 = lensq > 1e-7f ? make_float3(-Vh.y, Vh.x, 0.0f) / sqrtf(lensq) : + make_float3(1.0f, 0.0f, 0.0f); + float3 T2 = cross(Vh, T1); + /* Section 4.2: Parameterization of the projected area. */ + float2 t = concentric_sample_disk(U1, U2); + t.y = mix(safe_sqrtf(1.0f - sqr(t.x)), t.y, 0.5f * (1.0f + Vh.z)); + /* Section 4.3: Reprojection onto hemisphere. */ + float3 Mh = t.x * T1 + t.y * T2 + safe_sqrtf(1.0f - len_squared(t)) * Vh; + /* Section 3.4: Transforming the normal back to the ellipsoid configuration. */ + return normalize(make_float3(alpha_x * Mh.x, alpha_y * Mh.y, max(0.0f, Mh.z))); +} + +/* Albedo correction. */ + +ccl_device_forceinline float microfacet_ggx_glass_E(KernelGlobals kg, + float mu, + float rough, + float ior) +{ + bool inv_table = (ior < 1.0f); + int offset = inv_table ? kernel_data.tables.ggx_glass_inv_E_offset : + kernel_data.tables.ggx_glass_E_offset; + + float x = mu, y = 1 - rough; + float z = sqrtf(0.5f * ((inv_table ? 1.0f / ior : ior) - 1.0f)); + return lookup_table_read_3D(kg, x, y, z, offset, 16, 16, 16); +} + +ccl_device_forceinline float microfacet_ggx_dielectric_E(KernelGlobals kg, + float mu, + float rough, + float ior) +{ + bool inv_table = (ior < 1.0f); + int offset = inv_table ? kernel_data.tables.ggx_dielectric_inv_E_offset : + kernel_data.tables.ggx_dielectric_E_offset; + + float macro_fresnel = fresnel_dielectric_cos(mu, ior); + float F0 = fresnel_dielectric_cos(1.0f, ior); + float x = mix(mu, inverse_lerp(1.0f, F0, macro_fresnel), 0.5f); + float y = 1 - rough; + float z = sqrtf(0.5f * ((inv_table ? 1.0f / ior : ior) - 1.0f)); + + return lookup_table_read_3D(kg, x, y, z, offset, 16, 16, 16); +} + +ccl_device_forceinline float microfacet_ggx_E(KernelGlobals kg, float mu, float rough) +{ + return lookup_table_read_2D(kg, mu, 1 - rough, kernel_data.tables.ggx_E_offset, 32, 32); +} + +ccl_device_forceinline float microfacet_ggx_E_avg(KernelGlobals kg, float rough) +{ + return lookup_table_read(kg, 1 - rough, kernel_data.tables.ggx_E_avg_offset, 32); +} + +ccl_device_forceinline float clearcoat_E(KernelGlobals kg, float mu, float rough) +{ + float x = mu, y = 1 - rough; + float table = lookup_table_read_2D(kg, x, y, kernel_data.tables.ggx_clearcoat_E_offset, 16, 16); + return table * fresnel_dielectric_cos(mu, 1.5f); +} + +ccl_device_inline Spectrum fresnel_metallic_Fss(Spectrum F0, Spectrum B) +{ + return saturate(mix(F0, one_spectrum(), 1.0f / 21.0f) - B * (1.0f / 126.0f)); +} + +ccl_device_inline Spectrum schlick_fresnel_Fss(Spectrum F0) +{ + return saturate(mix(F0, one_spectrum(), 1.0f / 21.0f)); +} + +/* TODO Imageworks source */ +ccl_device_inline float dielectric_fresnel_Fss(float eta) +{ + /* TODO validate using multiGGX code */ + float f; + if (eta < 1.0f) { + f = 0.997118f + eta * (0.1014f - eta * (0.965241f + eta * 0.130607f)); + } + else { + f = (eta - 1.0f) / (4.08567f + 1.00071f * eta); + } + return f; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_principled_sheen.h b/intern/cycles/kernel/closure/bsdf_principled_sheen.h index f6499cc437c..949a6f8f567 100644 --- a/intern/cycles/kernel/closure/bsdf_principled_sheen.h +++ b/intern/cycles/kernel/closure/bsdf_principled_sheen.h @@ -15,6 +15,7 @@ CCL_NAMESPACE_BEGIN typedef struct PrincipledSheenBsdf { SHADER_CLOSURE_BASE; float avg_value; + float roughness; } PrincipledSheenBsdf; static_assert(sizeof(ShaderClosure) >= sizeof(PrincipledSheenBsdf), @@ -50,6 +51,64 @@ calculate_principled_sheen_brdf(float3 N, float3 V, float3 L, float3 H, ccl_priv return make_spectrum(value); } +/* Based on + * https://dassaultsystemes-technology.github.io/EnterprisePBRShadingModel/spec-2022x.md.html#components/sheen. + */ +ccl_device_inline float sheen_v2_lambda(float mu, float w) +{ + float a = mix(11.9095f, 13.7000f, w); + float b = mix(4.68753f, 2.92754f, w); + float c = mix(0.33467f, 0.28670f, w); + float d = mix(-2.22664f, -0.81757f, w); + float e = mix(-1.76591f, -1.22466f, w); + + float exponent; + if (mu < 0.5f) { + exponent = a / (1 + b * powf(mu, c)) + d * mu + e; + } + else { + exponent = 2 * a / (1 + b * exp2(-c)) - a / (1 + b * powf(1 - mu, c)) + d * mu + e; + } + return expf(exponent); +} + +ccl_device_inline Spectrum +sheen_v2_eval(float3 N, float3 V, float3 L, float3 H, float r, float *pdf) +{ + float cosNH = dot(N, H), cosNV = dot(N, V), cosNL = dot(N, L); + + if (cosNH < 0 || cosNV < 0 || cosNL < 0) { + *pdf = 0.0f; + return zero_float3(); + } + + /* Evaluate microfacet distribution. */ + float sinTheta2 = 1 - sqr(cosNH); + float invR = 1 / r; + float D = M_1_2PI_F * (2 + invR) * powf(sinTheta2, 0.5f * invR); + + /* Evaluate shadowing-masking terms. */ + float w = -1.59612f / (1 + 0.20375f * fast_safe_powf(r, -0.55825f)) + 1.32805f; + float lambdaV = sheen_v2_lambda(cosNV, w); + float lambdaL = sheen_v2_lambda(cosNL, w); + + /* Soften shadow terminator. */ + lambdaL = fast_safe_powf(lambdaL, 1 + 2 * sqr(sqr(sqr(1 - cosNL)))); + + /* Combined microfacet BSDF. + * Usual form is F*D*G/(4*cosNL*cosNV), but here we have no Fresnel, we skip dividing by cosNL + * since Cycles convention is returning BSDF*cosNL, and we use the combined shadowing-masking + * term G=1/(1+lambdaV+lambdaL). + */ + float val = D / (4 * cosNV * (1 + lambdaV + lambdaL)); + return make_spectrum(val); +} + +ccl_device_forceinline float sheen_v2_E(KernelGlobals kg, float mu, float rough) +{ + return lookup_table_read_2D(kg, mu, 1 - sqrtf(rough), kernel_data.tables.sheen_E_offset, 32, 32); +} + ccl_device int bsdf_principled_sheen_setup(ccl_private const ShaderData *sd, ccl_private PrincipledSheenBsdf *bsdf) { @@ -59,6 +118,21 @@ ccl_device int bsdf_principled_sheen_setup(ccl_private const ShaderData *sd, return SD_BSDF | SD_BSDF_HAS_EVAL; } +ccl_device int bsdf_principled_sheen_v2_setup(KernelGlobals kg, + ccl_private const ShaderData *sd, + ccl_private PrincipledSheenBsdf *bsdf) +{ + // TODO: Also expose as separate node. Add enum to Velvet BSDF maybe? + bsdf->type = CLOSURE_BSDF_PRINCIPLED_SHEEN_V2_ID; + + bsdf->roughness = clamp(bsdf->roughness, 1e-3f, 1.0f); + + bsdf->avg_value = sheen_v2_E(kg, dot(bsdf->N, sd->I), bsdf->roughness); + bsdf->sample_weight *= bsdf->avg_value; + + return SD_BSDF | SD_BSDF_HAS_EVAL; +} + ccl_device Spectrum bsdf_principled_sheen_eval(ccl_private const ShaderClosure *sc, const float3 I, const float3 omega_in, @@ -72,8 +146,13 @@ ccl_device Spectrum bsdf_principled_sheen_eval(ccl_private const ShaderClosure * const float3 L = omega_in; // incoming const float3 H = normalize(L + V); - *pdf = fmaxf(dot(N, omega_in), 0.0f) * M_1_PI_F; - return calculate_principled_sheen_brdf(N, V, L, H, pdf); + *pdf = M_1_2PI_F; + if (bsdf->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_V2_ID) { + return sheen_v2_eval(N, V, L, H, bsdf->roughness, pdf); + } + else { + return calculate_principled_sheen_brdf(N, V, L, H, pdf); + } } else { *pdf = 0.0f; @@ -94,12 +173,17 @@ ccl_device int bsdf_principled_sheen_sample(ccl_private const ShaderClosure *sc, float3 N = bsdf->N; - sample_cos_hemisphere(N, randu, randv, omega_in, pdf); + sample_uniform_hemisphere(N, randu, randv, omega_in, pdf); if (dot(Ng, *omega_in) > 0) { float3 H = normalize(I + *omega_in); - *eval = calculate_principled_sheen_brdf(N, I, *omega_in, H, pdf); + if (bsdf->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_V2_ID) { + *eval = sheen_v2_eval(N, I, *omega_in, H, bsdf->roughness, pdf); + } + else { + *eval = calculate_principled_sheen_brdf(N, I, *omega_in, H, pdf); + } } else { *eval = zero_spectrum(); diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h index 3c48b98fed9..13de4ac15b0 100644 --- a/intern/cycles/kernel/closure/bsdf_util.h +++ b/intern/cycles/kernel/closure/bsdf_util.h @@ -71,14 +71,14 @@ ccl_device float fresnel_dielectric_cos(float cosi, float eta) return 1.0f; // TIR(no refracted component) } -ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k) +ccl_device Spectrum fresnel_conductor(float cosi, const Spectrum eta, const Spectrum k) { - float3 cosi2 = make_float3(cosi * cosi, cosi * cosi, cosi * cosi); - float3 one = make_float3(1.0f, 1.0f, 1.0f); - float3 tmp_f = eta * eta + k * k; - float3 tmp = tmp_f * cosi2; - float3 Rparl2 = (tmp - (2.0f * eta * cosi) + one) / (tmp + (2.0f * eta * cosi) + one); - float3 Rperp2 = (tmp_f - (2.0f * eta * cosi) + cosi2) / (tmp_f + (2.0f * eta * cosi) + cosi2); + Spectrum cosi2 = make_spectrum(sqr(cosi)); + Spectrum one = make_spectrum(1.0f); + Spectrum tmp_f = eta * eta + k * k; + Spectrum tmp = tmp_f * cosi2; + Spectrum Rparl2 = (tmp - (2.0f * eta * cosi) + one) / (tmp + (2.0f * eta * cosi) + one); + Spectrum Rperp2 = (tmp_f - (2.0f * eta * cosi) + cosi2) / (tmp_f + (2.0f * eta * cosi) + cosi2); return (Rparl2 + Rperp2) * 0.5f; } @@ -89,19 +89,46 @@ ccl_device float schlick_fresnel(float u) return m2 * m2 * m; // pow(m, 5) } -/* Calculate the fresnel color which is a blend between white and the F0 color (cspec0) */ -ccl_device_forceinline Spectrum -interpolate_fresnel_color(float3 L, float3 H, float ior, float F0, Spectrum cspec0) +/* Metallic Fresnel term with edge color control. + * Based on Schlick Fresnel, but with an optional F82 input that adds the dip at + * near-grazing angles that is characteristic for conductors. + * + * Source: + * https://substance3d.adobe.com/documentation/s3d/files/225969599/225969601/1/1647019577092/Adobe+Standard+Material+-+Technical+Documentation.pdf + */ +ccl_device Spectrum metallic_edge_factor(Spectrum F0, Spectrum F82) { - /* Calculate the fresnel interpolation factor - * The value from fresnel_dielectric_cos(...) has to be normalized because - * the cspec0 keeps the F0 color + if (F82 == one_spectrum()) { + return zero_spectrum(); + } + + /* Precompute the B factor of the F82 model, which scales an additional term around cosI == 1/7. */ - float F0_norm = 1.0f / (1.0f - F0); - float FH = (fresnel_dielectric_cos(dot(L, H), ior) - F0) * F0_norm; + const float f = 6.0f / 7.0f; /* 1 - cosI_max */ + const float f5 = sqr(sqr(f)) * f; + return (7.0f / (f5 * f)) * mix(F0, one_spectrum(), f5) * (one_spectrum() - F82); +} + +ccl_device Spectrum fresnel_metallic(Spectrum F0, Spectrum B, float cosi) +{ + float s = saturatef(1.0f - cosi); + float s5 = sqr(sqr(s)) * s; + return saturate(mix(F0, one_spectrum(), s5) - B * cosi * s5 * s); +} + +/* Calculate the fresnel color which is a blend between white and the F0 color */ +ccl_device_forceinline Spectrum interpolate_fresnel_color(Spectrum L, + Spectrum H, + float ior, + Spectrum F0) +{ + /* Compute the real Fresnel term and remap it from real_F0...1 to F0...1. + * We could also just use actual Schlick fresnel (mix(F0, 1, (1-cosI)^5)) here. */ + float real_F0 = fresnel_dielectric_cos(1.0f, ior); + float F0_norm = 1.0f / (1.0f - real_F0); + float FH = (fresnel_dielectric_cos(dot(L, H), ior) - real_F0) * F0_norm; - /* Blend between white and a specular color with respect to the fresnel */ - return cspec0 * (1.0f - FH) + make_spectrum(FH); + return mix(F0, one_spectrum(), FH); } ccl_device float3 ensure_valid_reflection(float3 Ng, float3 I, float3 N) diff --git a/intern/cycles/kernel/film/denoising_passes.h b/intern/cycles/kernel/film/denoising_passes.h index dfc21d787f2..11672235b06 100644 --- a/intern/cycles/kernel/film/denoising_passes.h +++ b/intern/cycles/kernel/film/denoising_passes.h @@ -60,7 +60,7 @@ ccl_device_forceinline void film_write_denoising_features_surface(KernelGlobals ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc; closure_albedo *= bsdf->extra->fresnel_color; } - else if (sc->type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID) { + else if (CLOSURE_IS_BSDF_SHEEN(sc->type)) { ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)sc; closure_albedo *= bsdf->avg_value; } diff --git a/intern/cycles/kernel/film/passes.h b/intern/cycles/kernel/film/passes.h new file mode 100644 index 00000000000..d6562a32cc4 --- /dev/null +++ b/intern/cycles/kernel/film/passes.h @@ -0,0 +1,302 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#pragma once + +#include "kernel/geom/geom.h" + +#include "kernel/film/id_passes.h" +#include "kernel/film/write_passes.h" + +CCL_NAMESPACE_BEGIN + +/* Get pointer to pixel in render buffer. */ +ccl_device_forceinline ccl_global float *kernel_pass_pixel_render_buffer( + KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer) +{ + const uint32_t render_pixel_index = INTEGRATOR_STATE(state, path, render_pixel_index); + const uint64_t render_buffer_offset = (uint64_t)render_pixel_index * + kernel_data.film.pass_stride; + return render_buffer + render_buffer_offset; +} + +#ifdef __DENOISING_FEATURES__ + +ccl_device_forceinline void kernel_write_denoising_features_surface( + KernelGlobals kg, + IntegratorState state, + ccl_private const ShaderData *sd, + ccl_global float *ccl_restrict render_buffer) +{ + if (!(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_DENOISING_FEATURES)) { + return; + } + + /* Skip implicitly transparent surfaces. */ + if (sd->flag & SD_HAS_ONLY_VOLUME) { + return; + } + + ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); + + if (kernel_data.film.pass_denoising_depth != PASS_UNUSED) { + const float3 denoising_feature_throughput = INTEGRATOR_STATE( + state, path, denoising_feature_throughput); + const float denoising_depth = ensure_finite(average(denoising_feature_throughput) * + sd->ray_length); + kernel_write_pass_float(buffer + kernel_data.film.pass_denoising_depth, denoising_depth); + } + + float3 normal = zero_float3(); + float3 diffuse_albedo = zero_float3(); + float3 specular_albedo = zero_float3(); + float sum_weight = 0.0f, sum_nonspecular_weight = 0.0f; + + for (int i = 0; i < sd->num_closure; i++) { + ccl_private const ShaderClosure *sc = &sd->closure[i]; + + if (!CLOSURE_IS_BSDF_OR_BSSRDF(sc->type)) { + continue; + } + + /* All closures contribute to the normal feature, but only diffuse-like ones to the albedo. */ + normal += sc->N * sc->sample_weight; + sum_weight += sc->sample_weight; + + float3 closure_albedo = sc->weight; + /* Closures that include a Fresnel term typically have weights close to 1 even though their + * actual contribution is significantly lower. + * To account for this, we scale their weight by the average fresnel factor (the same is also + * done for the sample weight in the BSDF setup, so we don't need to scale that here). */ + if (CLOSURE_IS_BSDF_MICROFACET_FRESNEL(sc->type)) { + ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)sc; + closure_albedo *= bsdf->extra->fresnel_color; + } + else if (CLOSURE_IS_BSDF_SHEEN(sc->type)) { + ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)sc; + closure_albedo *= bsdf->avg_value; + } + else if (sc->type == CLOSURE_BSDF_HAIR_PRINCIPLED_ID) { + closure_albedo *= bsdf_principled_hair_albedo(sc); + } + else if (sc->type == CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID) { + /* BSSRDF already accounts for weight, retro-reflection would double up. */ + ccl_private const PrincipledDiffuseBsdf *bsdf = (ccl_private const PrincipledDiffuseBsdf *) + sc; + if (bsdf->components == PRINCIPLED_DIFFUSE_RETRO_REFLECTION) { + continue; + } + } + + if (bsdf_get_specular_roughness_squared(sc) > sqr(0.075f)) { + diffuse_albedo += closure_albedo; + sum_nonspecular_weight += sc->sample_weight; + } + else { + specular_albedo += closure_albedo; + } + } + + /* Wait for next bounce if 75% or more sample weight belongs to specular-like closures. */ + if ((sum_weight == 0.0f) || (sum_nonspecular_weight * 4.0f > sum_weight)) { + if (sum_weight != 0.0f) { + normal /= sum_weight; + } + + if (kernel_data.film.pass_denoising_normal != PASS_UNUSED) { + /* Transform normal into camera space. */ + const Transform worldtocamera = kernel_data.cam.worldtocamera; + normal = transform_direction(&worldtocamera, normal); + + const float3 denoising_normal = ensure_finite(normal); + kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal); + } + + if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) { + const float3 denoising_feature_throughput = INTEGRATOR_STATE( + state, path, denoising_feature_throughput); + const float3 denoising_albedo = ensure_finite(denoising_feature_throughput * diffuse_albedo); + kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo); + } + + INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES; + } + else { + INTEGRATOR_STATE_WRITE(state, path, denoising_feature_throughput) *= specular_albedo; + } +} + +ccl_device_forceinline void kernel_write_denoising_features_volume(KernelGlobals kg, + IntegratorState state, + const float3 albedo, + const bool scatter, + ccl_global float *ccl_restrict + render_buffer) +{ + ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); + const float3 denoising_feature_throughput = INTEGRATOR_STATE( + state, path, denoising_feature_throughput); + + if (scatter && kernel_data.film.pass_denoising_normal != PASS_UNUSED) { + /* Assume scatter is sufficiently diffuse to stop writing denoising features. */ + INTEGRATOR_STATE_WRITE(state, path, flag) &= ~PATH_RAY_DENOISING_FEATURES; + + /* Write view direction as normal. */ + const float3 denoising_normal = make_float3(0.0f, 0.0f, -1.0f); + kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_normal, denoising_normal); + } + + if (kernel_data.film.pass_denoising_albedo != PASS_UNUSED) { + /* Write albedo. */ + const float3 denoising_albedo = ensure_finite(denoising_feature_throughput * albedo); + kernel_write_pass_float3(buffer + kernel_data.film.pass_denoising_albedo, denoising_albedo); + } +} +#endif /* __DENOISING_FEATURES__ */ + +ccl_device_inline size_t kernel_write_id_pass(ccl_global float *ccl_restrict buffer, + size_t depth, + float id, + float matte_weight) +{ + kernel_write_id_slots(buffer, depth * 2, id, matte_weight); + return depth * 4; +} + +ccl_device_inline void kernel_write_data_passes(KernelGlobals kg, + IntegratorState state, + ccl_private const ShaderData *sd, + ccl_global float *ccl_restrict render_buffer) +{ +#ifdef __PASSES__ + const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); + + if (!(path_flag & PATH_RAY_TRANSPARENT_BACKGROUND)) { + return; + } + + const int flag = kernel_data.film.pass_flag; + + if (!(flag & PASS_ANY)) { + return; + } + + ccl_global float *buffer = kernel_pass_pixel_render_buffer(kg, state, render_buffer); + + if (!(path_flag & PATH_RAY_SINGLE_PASS_DONE)) { + if (!(sd->flag & SD_TRANSPARENT) || kernel_data.film.pass_alpha_threshold == 0.0f || + average(shader_bsdf_alpha(kg, sd)) >= kernel_data.film.pass_alpha_threshold) { + if (INTEGRATOR_STATE(state, path, sample) == 0) { + if (flag & PASSMASK(DEPTH)) { + const float depth = camera_z_depth(kg, sd->P); + kernel_write_pass_float(buffer + kernel_data.film.pass_depth, depth); + } + if (flag & PASSMASK(OBJECT_ID)) { + const float id = object_pass_id(kg, sd->object); + kernel_write_pass_float(buffer + kernel_data.film.pass_object_id, id); + } + if (flag & PASSMASK(MATERIAL_ID)) { + const float id = shader_pass_id(kg, sd); + kernel_write_pass_float(buffer + kernel_data.film.pass_material_id, id); + } + if (flag & PASSMASK(POSITION)) { + const float3 position = sd->P; + kernel_write_pass_float3(buffer + kernel_data.film.pass_position, position); + } + } + + if (flag & PASSMASK(NORMAL)) { + const float3 normal = shader_bsdf_average_normal(kg, sd); + kernel_write_pass_float3(buffer + kernel_data.film.pass_normal, normal); + } + if (flag & PASSMASK(ROUGHNESS)) { + const float roughness = shader_bsdf_average_roughness(sd); + kernel_write_pass_float(buffer + kernel_data.film.pass_roughness, roughness); + } + if (flag & PASSMASK(UV)) { + const float3 uv = primitive_uv(kg, sd); + kernel_write_pass_float3(buffer + kernel_data.film.pass_uv, uv); + } + if (flag & PASSMASK(MOTION)) { + const float4 speed = primitive_motion_vector(kg, sd); + kernel_write_pass_float4(buffer + kernel_data.film.pass_motion, speed); + kernel_write_pass_float(buffer + kernel_data.film.pass_motion_weight, 1.0f); + } + + INTEGRATOR_STATE_WRITE(state, path, flag) |= PATH_RAY_SINGLE_PASS_DONE; + } + } + + if (kernel_data.film.cryptomatte_passes) { + const float3 throughput = INTEGRATOR_STATE(state, path, throughput); + const float matte_weight = average(throughput) * + (1.0f - average(shader_bsdf_transparency(kg, sd))); + if (matte_weight > 0.0f) { + ccl_global float *cryptomatte_buffer = buffer + kernel_data.film.pass_cryptomatte; + if (kernel_data.film.cryptomatte_passes & CRYPT_OBJECT) { + const float id = object_cryptomatte_id(kg, sd->object); + cryptomatte_buffer += kernel_write_id_pass( + cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); + } + if (kernel_data.film.cryptomatte_passes & CRYPT_MATERIAL) { + const float id = shader_cryptomatte_id(kg, sd->shader); + cryptomatte_buffer += kernel_write_id_pass( + cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); + } + if (kernel_data.film.cryptomatte_passes & CRYPT_ASSET) { + const float id = object_cryptomatte_asset_id(kg, sd->object); + cryptomatte_buffer += kernel_write_id_pass( + cryptomatte_buffer, kernel_data.film.cryptomatte_depth, id, matte_weight); + } + } + } + + if (flag & PASSMASK(DIFFUSE_COLOR)) { + const float3 throughput = INTEGRATOR_STATE(state, path, throughput); + kernel_write_pass_float3(buffer + kernel_data.film.pass_diffuse_color, + shader_bsdf_diffuse(kg, sd) * throughput); + } + if (flag & PASSMASK(GLOSSY_COLOR)) { + const float3 throughput = INTEGRATOR_STATE(state, path, throughput); + kernel_write_pass_float3(buffer + kernel_data.film.pass_glossy_color, + shader_bsdf_glossy(kg, sd) * throughput); + } + if (flag & PASSMASK(TRANSMISSION_COLOR)) { + const float3 throughput = INTEGRATOR_STATE(state, path, throughput); + kernel_write_pass_float3(buffer + kernel_data.film.pass_transmission_color, + shader_bsdf_transmission(kg, sd) * throughput); + } + if (flag & PASSMASK(MIST)) { + /* Bring depth into 0..1 range. */ + const float mist_start = kernel_data.film.mist_start; + const float mist_inv_depth = kernel_data.film.mist_inv_depth; + + const float depth = camera_distance(kg, sd->P); + float mist = saturatef((depth - mist_start) * mist_inv_depth); + + /* Falloff */ + const float mist_falloff = kernel_data.film.mist_falloff; + + if (mist_falloff == 1.0f) + ; + else if (mist_falloff == 2.0f) + mist = mist * mist; + else if (mist_falloff == 0.5f) + mist = sqrtf(mist); + else + mist = powf(mist, mist_falloff); + + /* Modulate by transparency */ + const float3 throughput = INTEGRATOR_STATE(state, path, throughput); + const float3 alpha = shader_bsdf_alpha(kg, sd); + const float mist_output = (1.0f - mist) * average(throughput * alpha); + + /* Note that the final value in the render buffer we want is 1 - mist_output, + * to avoid having to tracking this in the Integrator state we do the negation + * after rendering. */ + kernel_write_pass_float(buffer + kernel_data.film.pass_mist, mist_output); + } +#endif +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/integrator/mnee.h b/intern/cycles/kernel/integrator/mnee.h index 23885306885..142977f1ac7 100644 --- a/intern/cycles/kernel/integrator/mnee.h +++ b/intern/cycles/kernel/integrator/mnee.h @@ -658,6 +658,7 @@ ccl_device_forceinline Spectrum mnee_eval_bsdf_contribution(ccl_private ShaderCl float cosThetaM = dot(bsdf->N, Ht); float G; + /* TODO: Use bsdf_microfacet_util.h */ if (bsdf->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID) { /* Eq. 26, 27: now calculate G1(i,m) and G1(o,m). */ G = bsdf_beckmann_G1(bsdf->alpha_x, cosNO) * bsdf_beckmann_G1(bsdf->alpha_x, cosNI); diff --git a/intern/cycles/kernel/osl/closures_setup.h b/intern/cycles/kernel/osl/closures_setup.h index 96c551b9951..23f62ec2f3d 100644 --- a/intern/cycles/kernel/osl/closures_setup.h +++ b/intern/cycles/kernel/osl/closures_setup.h @@ -14,7 +14,8 @@ #include "kernel/closure/bsdf_ashikhmin_velvet.h" #include "kernel/closure/bsdf_diffuse.h" #include "kernel/closure/bsdf_microfacet.h" -#include "kernel/closure/bsdf_microfacet_multi.h" +#include "kernel/closure/bsdf_microfacet_beckmann.h" +#include "kernel/closure/bsdf_microfacet_glass.h" #include "kernel/closure/bsdf_oren_nayar.h" #include "kernel/closure/bsdf_reflection.h" #include "kernel/closure/bsdf_refraction.h" @@ -216,14 +217,7 @@ ccl_device void osl_closure_microfacet_setup(KernelGlobals kg, /* GGX */ if (closure->distribution == u_ggx || closure->distribution == u_default) { if (!closure->refract) { - if (closure->alpha_x == closure->alpha_y) { - /* Isotropic */ - sd->flag |= bsdf_microfacet_ggx_isotropic_setup(bsdf); - } - else { - /* Anisotropic */ - sd->flag |= bsdf_microfacet_ggx_setup(bsdf); - } + sd->flag |= bsdf_microfacet_ggx_setup(bsdf); } else { sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf); @@ -232,14 +226,7 @@ ccl_device void osl_closure_microfacet_setup(KernelGlobals kg, /* Beckmann */ else { if (!closure->refract) { - if (closure->alpha_x == closure->alpha_y) { - /* Isotropic */ - sd->flag |= bsdf_microfacet_beckmann_isotropic_setup(bsdf); - } - else { - /* Anisotropic */ - sd->flag |= bsdf_microfacet_beckmann_setup(bsdf); - } + sd->flag |= bsdf_microfacet_beckmann_setup(bsdf); } else { sd->flag |= bsdf_microfacet_beckmann_refraction_setup(bsdf); @@ -267,7 +254,7 @@ ccl_device void osl_closure_microfacet_ggx_setup( bsdf->N = ensure_valid_reflection(sd->Ng, sd->I, closure->N); bsdf->alpha_x = closure->alpha_x; - sd->flag |= bsdf_microfacet_ggx_isotropic_setup(bsdf); + sd->flag |= bsdf_microfacet_ggx_setup(bsdf); } ccl_device void osl_closure_microfacet_ggx_aniso_setup( @@ -352,7 +339,6 @@ ccl_device void osl_closure_microfacet_ggx_fresnel_setup( bsdf->extra = extra; bsdf->extra->color = rgb_to_spectrum(closure->color); bsdf->extra->cspec0 = rgb_to_spectrum(closure->cspec0); - bsdf->extra->clearcoat = 0.0f; bsdf->T = zero_float3(); @@ -390,7 +376,6 @@ ccl_device void osl_closure_microfacet_ggx_aniso_fresnel_setup( bsdf->extra = extra; bsdf->extra->color = rgb_to_spectrum(closure->color); bsdf->extra->cspec0 = rgb_to_spectrum(closure->cspec0); - bsdf->extra->clearcoat = 0.0f; bsdf->T = closure->T; @@ -419,25 +404,14 @@ ccl_device void osl_closure_microfacet_multi_ggx_setup( return; } - ccl_private MicrofacetExtra *extra = (ccl_private MicrofacetExtra *)closure_alloc_extra( - sd, sizeof(MicrofacetExtra)); - if (!extra) { - return; - } - bsdf->N = ensure_valid_reflection(sd->Ng, sd->I, closure->N); bsdf->alpha_x = closure->alpha_x; bsdf->alpha_y = bsdf->alpha_x; bsdf->ior = 1.0f; - bsdf->extra = extra; - bsdf->extra->color = rgb_to_spectrum(closure->color); - bsdf->extra->cspec0 = zero_spectrum(); - bsdf->extra->clearcoat = 0.0f; - bsdf->T = zero_float3(); - sd->flag |= bsdf_microfacet_multi_ggx_setup(bsdf); + sd->flag |= bsdf_microfacet_multi_ggx_setup(kg, bsdf, sd, rgb_to_spectrum(closure->color)); } ccl_device void osl_closure_microfacet_multi_ggx_glass_setup( @@ -460,25 +434,14 @@ ccl_device void osl_closure_microfacet_multi_ggx_glass_setup( return; } - ccl_private MicrofacetExtra *extra = (ccl_private MicrofacetExtra *)closure_alloc_extra( - sd, sizeof(MicrofacetExtra)); - if (!extra) { - return; - } - bsdf->N = ensure_valid_reflection(sd->Ng, sd->I, closure->N); bsdf->alpha_x = closure->alpha_x; bsdf->alpha_y = bsdf->alpha_x; bsdf->ior = closure->ior; - bsdf->extra = extra; - bsdf->extra->color = rgb_to_spectrum(closure->color); - bsdf->extra->cspec0 = zero_spectrum(); - bsdf->extra->clearcoat = 0.0f; - bsdf->T = zero_float3(); - sd->flag |= bsdf_microfacet_multi_ggx_glass_setup(bsdf); + sd->flag |= bsdf_microfacet_multi_ggx_glass_setup(kg, bsdf, sd, rgb_to_spectrum(closure->color)); } ccl_device void osl_closure_microfacet_multi_ggx_aniso_setup( @@ -512,14 +475,9 @@ ccl_device void osl_closure_microfacet_multi_ggx_aniso_setup( bsdf->alpha_y = closure->alpha_y; bsdf->ior = 1.0f; - bsdf->extra = extra; - bsdf->extra->color = rgb_to_spectrum(closure->color); - bsdf->extra->cspec0 = zero_spectrum(); - bsdf->extra->clearcoat = 0.0f; - bsdf->T = closure->T; - sd->flag |= bsdf_microfacet_multi_ggx_setup(bsdf); + sd->flag |= bsdf_microfacet_multi_ggx_setup(kg, bsdf, sd, rgb_to_spectrum(closure->color)); } /* Multi-scattering GGX closures with Fresnel */ @@ -558,11 +516,10 @@ ccl_device void osl_closure_microfacet_multi_ggx_fresnel_setup( bsdf->extra = extra; bsdf->extra->color = rgb_to_spectrum(closure->color); bsdf->extra->cspec0 = rgb_to_spectrum(closure->cspec0); - bsdf->extra->clearcoat = 0.0f; bsdf->T = zero_float3(); - sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd); + sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(kg, bsdf, sd); } ccl_device void osl_closure_microfacet_multi_ggx_glass_fresnel_setup( @@ -599,11 +556,10 @@ ccl_device void osl_closure_microfacet_multi_ggx_glass_fresnel_setup( bsdf->extra = extra; bsdf->extra->color = rgb_to_spectrum(closure->color); bsdf->extra->cspec0 = rgb_to_spectrum(closure->cspec0); - bsdf->extra->clearcoat = 0.0f; bsdf->T = zero_float3(); - sd->flag |= bsdf_microfacet_multi_ggx_glass_fresnel_setup(bsdf, sd); + sd->flag |= bsdf_microfacet_multi_ggx_glass_fresnel_setup(kg, bsdf, sd); } ccl_device void osl_closure_microfacet_multi_ggx_aniso_fresnel_setup( @@ -640,11 +596,10 @@ ccl_device void osl_closure_microfacet_multi_ggx_aniso_fresnel_setup( bsdf->extra = extra; bsdf->extra->color = rgb_to_spectrum(closure->color); bsdf->extra->cspec0 = rgb_to_spectrum(closure->cspec0); - bsdf->extra->clearcoat = 0.0f; bsdf->T = closure->T; - sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd); + sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(kg, bsdf, sd); } /* Beckmann closures */ @@ -669,7 +624,7 @@ ccl_device void osl_closure_microfacet_beckmann_setup( bsdf->N = ensure_valid_reflection(sd->Ng, sd->I, closure->N); bsdf->alpha_x = closure->alpha_x; - sd->flag |= bsdf_microfacet_beckmann_isotropic_setup(bsdf); + sd->flag |= bsdf_microfacet_beckmann_setup(bsdf); } ccl_device void osl_closure_microfacet_beckmann_aniso_setup( @@ -873,26 +828,16 @@ ccl_device void osl_closure_principled_clearcoat_setup( ccl_private const PrincipledClearcoatClosure *closure) { ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight)); + sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight) * closure->clearcoat); if (!bsdf) { return; } - MicrofacetExtra *extra = (MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra)); - if (!extra) { - return; - } - bsdf->N = ensure_valid_reflection(sd->Ng, sd->I, closure->N); bsdf->alpha_x = closure->clearcoat_roughness; bsdf->alpha_y = closure->clearcoat_roughness; bsdf->ior = 1.5f; - bsdf->extra = extra; - bsdf->extra->color = zero_spectrum(); - bsdf->extra->cspec0 = make_spectrum(0.04f); - bsdf->extra->clearcoat = closure->clearcoat; - bsdf->T = zero_float3(); sd->flag |= bsdf_microfacet_ggx_clearcoat_setup(bsdf, sd); diff --git a/intern/cycles/kernel/svm/closure.h b/intern/cycles/kernel/svm/closure.h index d18f2cc0854..82274adeea8 100644 --- a/intern/cycles/kernel/svm/closure.h +++ b/intern/cycles/kernel/svm/closure.h @@ -10,6 +10,8 @@ #include "kernel/util/color.h" +#include "kernel/svm/closure_principled.h" + CCL_NAMESPACE_BEGIN /* Closure Nodes */ @@ -57,19 +59,6 @@ ccl_device void svm_node_glass_setup(ccl_private ShaderData *sd, } } -ccl_device_inline int svm_node_closure_bsdf_skip(KernelGlobals kg, int offset, uint type) -{ - if (type == CLOSURE_BSDF_PRINCIPLED_ID) { - /* Read all principled BSDF extra data to get the right offset. */ - read_node(kg, &offset); - read_node(kg, &offset); - read_node(kg, &offset); - read_node(kg, &offset); - } - - return offset; -} - template<uint node_feature_mask, ShaderType shader_type> ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, ccl_private ShaderData *sd, @@ -92,12 +81,18 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, IF_KERNEL_NODES_FEATURE(BSDF) { if ((shader_type != SHADER_TYPE_SURFACE) || mix_weight == 0.0f) { - return svm_node_closure_bsdf_skip(kg, offset, type); + return offset; } } else { - return svm_node_closure_bsdf_skip(kg, offset, type); + return offset; + } + + if (type == CLOSURE_BSDF_PRINCIPLED_ID) { + /* Principled BSDF uses different parameter packing. */ + svm_node_closure_principled(kg, sd, stack, node, data_node, mix_weight, path_flag, &offset); + return offset; } float3 N = stack_valid(data_node.x) ? stack_load_float3(stack, data_node.x) : sd->N; @@ -111,381 +106,6 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, __uint_as_float(node.w); switch (type) { - case CLOSURE_BSDF_PRINCIPLED_ID: { - uint specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset, - sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_roughness_offset, - eta_offset, transmission_offset, anisotropic_rotation_offset, - transmission_roughness_offset; - uint4 data_node2 = read_node(kg, &offset); - - float3 T = stack_load_float3(stack, data_node.y); - svm_unpack_node_uchar4(data_node.z, - &specular_offset, - &roughness_offset, - &specular_tint_offset, - &anisotropic_offset); - svm_unpack_node_uchar4(data_node.w, - &sheen_offset, - &sheen_tint_offset, - &clearcoat_offset, - &clearcoat_roughness_offset); - svm_unpack_node_uchar4(data_node2.x, - &eta_offset, - &transmission_offset, - &anisotropic_rotation_offset, - &transmission_roughness_offset); - - // get Disney principled parameters - float metallic = param1; - float subsurface = param2; - float specular = stack_load_float(stack, specular_offset); - float roughness = stack_load_float(stack, roughness_offset); - float specular_tint = stack_load_float(stack, specular_tint_offset); - float anisotropic = stack_load_float(stack, anisotropic_offset); - float sheen = stack_load_float(stack, sheen_offset); - float sheen_tint = stack_load_float(stack, sheen_tint_offset); - float clearcoat = stack_load_float(stack, clearcoat_offset); - float clearcoat_roughness = stack_load_float(stack, clearcoat_roughness_offset); - float transmission = stack_load_float(stack, transmission_offset); - float anisotropic_rotation = stack_load_float(stack, anisotropic_rotation_offset); - float transmission_roughness = stack_load_float(stack, transmission_roughness_offset); - float eta = fmaxf(stack_load_float(stack, eta_offset), 1e-5f); - - ClosureType distribution = (ClosureType)data_node2.y; - ClosureType subsurface_method = (ClosureType)data_node2.z; - - /* rotate tangent */ - if (anisotropic_rotation != 0.0f) - T = rotate_around_axis(T, N, anisotropic_rotation * M_2PI_F); - - /* calculate ior */ - float ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta; - - // calculate fresnel for refraction - float cosNO = dot(N, sd->I); - float fresnel = fresnel_dielectric_cos(cosNO, ior); - - // calculate weights of the diffuse and specular part - float diffuse_weight = (1.0f - saturatef(metallic)) * (1.0f - saturatef(transmission)); - - float final_transmission = saturatef(transmission) * (1.0f - saturatef(metallic)); - float specular_weight = (1.0f - final_transmission); - - // get the base color - uint4 data_base_color = read_node(kg, &offset); - float3 base_color = stack_valid(data_base_color.x) ? - stack_load_float3(stack, data_base_color.x) : - make_float3(__uint_as_float(data_base_color.y), - __uint_as_float(data_base_color.z), - __uint_as_float(data_base_color.w)); - - // get the additional clearcoat normal and subsurface scattering radius - uint4 data_cn_ssr = read_node(kg, &offset); - float3 clearcoat_normal = stack_valid(data_cn_ssr.x) ? - stack_load_float3(stack, data_cn_ssr.x) : - sd->N; - if (!(sd->type & PRIMITIVE_CURVE)) { - clearcoat_normal = ensure_valid_reflection(sd->Ng, sd->I, clearcoat_normal); - } - float3 subsurface_radius = stack_valid(data_cn_ssr.y) ? - stack_load_float3(stack, data_cn_ssr.y) : - one_float3(); - float subsurface_ior = stack_valid(data_cn_ssr.z) ? stack_load_float(stack, data_cn_ssr.z) : - 1.4f; - float subsurface_anisotropy = stack_valid(data_cn_ssr.w) ? - stack_load_float(stack, data_cn_ssr.w) : - 0.0f; - - // get the subsurface color - uint4 data_subsurface_color = read_node(kg, &offset); - float3 subsurface_color = stack_valid(data_subsurface_color.x) ? - stack_load_float3(stack, data_subsurface_color.x) : - make_float3(__uint_as_float(data_subsurface_color.y), - __uint_as_float(data_subsurface_color.z), - __uint_as_float(data_subsurface_color.w)); - - Spectrum weight = sd->svm_closure_weight * mix_weight; - -#ifdef __SUBSURFACE__ - float3 mixed_ss_base_color = subsurface_color * subsurface + - base_color * (1.0f - subsurface); - Spectrum subsurf_weight = weight * rgb_to_spectrum(mixed_ss_base_color) * diffuse_weight; - - /* disable in case of diffuse ancestor, can't see it well then and - * adds considerably noise due to probabilities of continuing path - * getting lower and lower */ - if (path_flag & PATH_RAY_DIFFUSE_ANCESTOR) { - subsurface = 0.0f; - - /* need to set the base color in this case such that the - * rays get the correctly mixed color after transmitting - * the object */ - base_color = mixed_ss_base_color; - } - - /* diffuse */ - if (fabsf(average(mixed_ss_base_color)) > CLOSURE_WEIGHT_CUTOFF) { - if (subsurface <= CLOSURE_WEIGHT_CUTOFF && diffuse_weight > CLOSURE_WEIGHT_CUTOFF) { - Spectrum diff_weight = weight * rgb_to_spectrum(base_color) * diffuse_weight; - - ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *) - bsdf_alloc(sd, sizeof(PrincipledDiffuseBsdf), diff_weight); - - if (bsdf) { - bsdf->N = N; - bsdf->roughness = roughness; - - /* setup bsdf */ - sd->flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_FULL); - } - } - else if (subsurface > CLOSURE_WEIGHT_CUTOFF) { - ccl_private Bssrdf *bssrdf = bssrdf_alloc(sd, subsurf_weight); - - if (bssrdf) { - bssrdf->radius = rgb_to_spectrum(subsurface_radius * subsurface); - bssrdf->albedo = rgb_to_spectrum(mixed_ss_base_color); - bssrdf->N = N; - bssrdf->roughness = roughness; - - /* Clamps protecting against bad/extreme and non physical values. */ - subsurface_ior = clamp(subsurface_ior, 1.01f, 3.8f); - bssrdf->anisotropy = clamp(subsurface_anisotropy, 0.0f, 0.9f); - - /* setup bsdf */ - sd->flag |= bssrdf_setup(sd, bssrdf, subsurface_method, subsurface_ior); - } - } - } -#else - /* diffuse */ - if (diffuse_weight > CLOSURE_WEIGHT_CUTOFF) { - Spectrum diff_weight = weight * rgb_to_spectrum(base_color) * diffuse_weight; - - ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)bsdf_alloc( - sd, sizeof(PrincipledDiffuseBsdf), diff_weight); - - if (bsdf) { - bsdf->N = N; - bsdf->roughness = roughness; - - /* setup bsdf */ - sd->flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_FULL); - } - } -#endif - - /* sheen */ - if (diffuse_weight > CLOSURE_WEIGHT_CUTOFF && sheen > CLOSURE_WEIGHT_CUTOFF) { - float m_cdlum = linear_rgb_to_gray(kg, base_color); - float3 m_ctint = m_cdlum > 0.0f ? base_color / m_cdlum : - one_float3(); // normalize lum. to isolate hue+sat - - /* color of the sheen component */ - float3 sheen_color = make_float3(1.0f - sheen_tint) + m_ctint * sheen_tint; - - Spectrum sheen_weight = weight * sheen * rgb_to_spectrum(sheen_color) * diffuse_weight; - - ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)bsdf_alloc( - sd, sizeof(PrincipledSheenBsdf), sheen_weight); - - if (bsdf) { - bsdf->N = N; - - /* setup bsdf */ - sd->flag |= bsdf_principled_sheen_setup(sd, bsdf); - } - } - - /* specular reflection */ -#ifdef __CAUSTICS_TRICKS__ - if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) { -#endif - if (specular_weight > CLOSURE_WEIGHT_CUTOFF && - (specular > CLOSURE_WEIGHT_CUTOFF || metallic > CLOSURE_WEIGHT_CUTOFF)) { - Spectrum spec_weight = weight * specular_weight; - - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), spec_weight); - ccl_private MicrofacetExtra *extra = - (bsdf != NULL) ? - (ccl_private MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra)) : - NULL; - - if (bsdf && extra) { - bsdf->N = N; - bsdf->ior = (2.0f / (1.0f - safe_sqrtf(0.08f * specular))) - 1.0f; - bsdf->T = T; - bsdf->extra = extra; - - float aspect = safe_sqrtf(1.0f - anisotropic * 0.9f); - float r2 = roughness * roughness; - - bsdf->alpha_x = r2 / aspect; - bsdf->alpha_y = r2 * aspect; - - float m_cdlum = 0.3f * base_color.x + 0.6f * base_color.y + - 0.1f * base_color.z; // luminance approx. - float3 m_ctint = m_cdlum > 0.0f ? base_color / m_cdlum : - one_float3(); // normalize lum. to isolate hue+sat - float3 tmp_col = make_float3(1.0f - specular_tint) + m_ctint * specular_tint; - - bsdf->extra->cspec0 = rgb_to_spectrum( - (specular * 0.08f * tmp_col) * (1.0f - metallic) + base_color * metallic); - bsdf->extra->color = rgb_to_spectrum(base_color); - bsdf->extra->clearcoat = 0.0f; - - /* setup bsdf */ - if (distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID || - roughness <= 0.075f) /* use single-scatter GGX */ - sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf, sd); - else /* use multi-scatter GGX */ - sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd); - } - } -#ifdef __CAUSTICS_TRICKS__ - } -#endif - - /* BSDF */ -#ifdef __CAUSTICS_TRICKS__ - if (kernel_data.integrator.caustics_reflective || - kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0) { -#endif - if (final_transmission > CLOSURE_WEIGHT_CUTOFF) { - Spectrum glass_weight = weight * final_transmission; - float3 cspec0 = base_color * specular_tint + make_float3(1.0f - specular_tint); - - if (roughness <= 5e-2f || - distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID) { /* use single-scatter GGX */ - float refl_roughness = roughness; - - /* reflection */ -#ifdef __CAUSTICS_TRICKS__ - if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) -#endif - { - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), glass_weight * fresnel); - ccl_private MicrofacetExtra *extra = - (bsdf != NULL) ? (ccl_private MicrofacetExtra *)closure_alloc_extra( - sd, sizeof(MicrofacetExtra)) : - NULL; - - if (bsdf && extra) { - bsdf->N = N; - bsdf->T = zero_float3(); - bsdf->extra = extra; - - bsdf->alpha_x = refl_roughness * refl_roughness; - bsdf->alpha_y = refl_roughness * refl_roughness; - bsdf->ior = ior; - - bsdf->extra->color = rgb_to_spectrum(base_color); - bsdf->extra->cspec0 = rgb_to_spectrum(cspec0); - bsdf->extra->clearcoat = 0.0f; - - /* setup bsdf */ - sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf, sd); - } - } - - /* refraction */ -#ifdef __CAUSTICS_TRICKS__ - if (kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0) -#endif - { - /* This is to prevent MNEE from receiving a null BSDF. */ - float refraction_fresnel = fmaxf(0.0001f, 1.0f - fresnel); - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, - sizeof(MicrofacetBsdf), - rgb_to_spectrum(base_color) * glass_weight * refraction_fresnel); - if (bsdf) { - bsdf->N = N; - bsdf->T = zero_float3(); - bsdf->extra = NULL; - - if (distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID) - transmission_roughness = 1.0f - (1.0f - refl_roughness) * - (1.0f - transmission_roughness); - else - transmission_roughness = refl_roughness; - - bsdf->alpha_x = transmission_roughness * transmission_roughness; - bsdf->alpha_y = transmission_roughness * transmission_roughness; - bsdf->ior = ior; - - /* setup bsdf */ - sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf); - } - } - } - else { /* use multi-scatter GGX */ - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), glass_weight); - ccl_private MicrofacetExtra *extra = - (bsdf != NULL) ? (ccl_private MicrofacetExtra *)closure_alloc_extra( - sd, sizeof(MicrofacetExtra)) : - NULL; - - if (bsdf && extra) { - bsdf->N = N; - bsdf->extra = extra; - bsdf->T = zero_float3(); - - bsdf->alpha_x = roughness * roughness; - bsdf->alpha_y = roughness * roughness; - bsdf->ior = ior; - - bsdf->extra->color = rgb_to_spectrum(base_color); - bsdf->extra->cspec0 = rgb_to_spectrum(cspec0); - bsdf->extra->clearcoat = 0.0f; - - /* setup bsdf */ - sd->flag |= bsdf_microfacet_multi_ggx_glass_fresnel_setup(bsdf, sd); - } - } - } -#ifdef __CAUSTICS_TRICKS__ - } -#endif - - /* clearcoat */ -#ifdef __CAUSTICS_TRICKS__ - if (kernel_data.integrator.caustics_reflective || (path_flag & PATH_RAY_DIFFUSE) == 0) { -#endif - if (clearcoat > CLOSURE_WEIGHT_CUTOFF) { - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), weight); - ccl_private MicrofacetExtra *extra = - (bsdf != NULL) ? - (ccl_private MicrofacetExtra *)closure_alloc_extra(sd, sizeof(MicrofacetExtra)) : - NULL; - - if (bsdf && extra) { - bsdf->N = clearcoat_normal; - bsdf->T = zero_float3(); - bsdf->ior = 1.5f; - bsdf->extra = extra; - - bsdf->alpha_x = clearcoat_roughness * clearcoat_roughness; - bsdf->alpha_y = clearcoat_roughness * clearcoat_roughness; - - bsdf->extra->color = zero_spectrum(); - bsdf->extra->cspec0 = make_spectrum(0.04f); - bsdf->extra->clearcoat = clearcoat; - - /* setup bsdf */ - sd->flag |= bsdf_microfacet_ggx_clearcoat_setup(bsdf, sd); - } - } -#ifdef __CAUSTICS_TRICKS__ - } -#endif - - break; - } case CLOSURE_BSDF_DIFFUSE_ID: { Spectrum weight = sd->svm_closure_weight * mix_weight; ccl_private OrenNayarBsdf *bsdf = (ccl_private OrenNayarBsdf *)bsdf_alloc( @@ -579,14 +199,8 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, sd->flag |= bsdf_microfacet_ggx_setup(bsdf); else if (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) { kernel_assert(stack_valid(data_node.w)); - bsdf->extra = (ccl_private MicrofacetExtra *)closure_alloc_extra(sd, - sizeof(MicrofacetExtra)); - if (bsdf->extra) { - bsdf->extra->color = rgb_to_spectrum(stack_load_float3(stack, data_node.w)); - bsdf->extra->cspec0 = zero_spectrum(); - bsdf->extra->clearcoat = 0.0f; - sd->flag |= bsdf_microfacet_multi_ggx_setup(bsdf); - } + Spectrum color = rgb_to_spectrum(stack_load_float3(stack, data_node.w)); + sd->flag |= bsdf_microfacet_multi_ggx_setup(kg, bsdf, sd, color); } else { sd->flag |= bsdf_ashikhmin_shirley_setup(bsdf); @@ -677,7 +291,8 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, if (kernel_data.integrator.caustics_refractive || (path_flag & PATH_RAY_DIFFUSE) == 0) #endif { - /* This is to prevent MNEE from receiving a null BSDF. */ + /* This is to prevent MNEE from receiving a null BSDF. + * TODO: Doesn't this always enable the closure? */ float refraction_fresnel = fmaxf(0.0001f, 1.0f - fresnel); ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( sd, sizeof(MicrofacetBsdf), weight * refraction_fresnel); @@ -705,14 +320,10 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, break; } - ccl_private MicrofacetExtra *extra = (ccl_private MicrofacetExtra *)closure_alloc_extra( - sd, sizeof(MicrofacetExtra)); - if (!extra) { - break; - } + /* TODO: Detect sharp, fallback. */ bsdf->N = N; - bsdf->extra = extra; + bsdf->extra = NULL; bsdf->T = zero_float3(); float roughness = sqr(param1); @@ -722,12 +333,10 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, bsdf->ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta; kernel_assert(stack_valid(data_node.z)); - bsdf->extra->color = rgb_to_spectrum(stack_load_float3(stack, data_node.z)); - bsdf->extra->cspec0 = zero_spectrum(); - bsdf->extra->clearcoat = 0.0f; + Spectrum color = rgb_to_spectrum(stack_load_float3(stack, data_node.z)); /* setup bsdf */ - sd->flag |= bsdf_microfacet_multi_ggx_glass_setup(bsdf); + sd->flag |= bsdf_microfacet_multi_ggx_glass_setup(kg, bsdf, sd, color); break; } case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: { diff --git a/intern/cycles/kernel/svm/closure_principled.h b/intern/cycles/kernel/svm/closure_principled.h new file mode 100644 index 00000000000..fd6df508e12 --- /dev/null +++ b/intern/cycles/kernel/svm/closure_principled.h @@ -0,0 +1,843 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +/* Principled v1 components */ + +ccl_device_inline void principled_v1_diffuse(ccl_private ShaderData *sd, + Spectrum weight, + Spectrum base_color, + float diffuse_weight, + float3 N, + float roughness) +{ + if (diffuse_weight <= CLOSURE_WEIGHT_CUTOFF) { + return; + } + + ccl_private PrincipledDiffuseBsdf *bsdf = (ccl_private PrincipledDiffuseBsdf *)bsdf_alloc( + sd, sizeof(PrincipledDiffuseBsdf), diffuse_weight * base_color * weight); + + if (bsdf == NULL) { + return; + } + + bsdf->N = N; + bsdf->roughness = roughness; + + /* setup bsdf */ + sd->flag |= bsdf_principled_diffuse_setup(bsdf, PRINCIPLED_DIFFUSE_FULL); +} + +ccl_device_inline void principled_v1_diffuse_sss(ccl_private ShaderData *sd, + ccl_private float *stack, + Spectrum weight, + int path_flag, + uint data_1, + uint data_2, + Spectrum base_color, + float diffuse_weight, + float3 N, + float roughness) +{ +#ifdef __SUBSURFACE__ + uint method, subsurface_offset, aniso_offset, radius_offset; + uint color_offset, ior_offset, dummy; + svm_unpack_node_uchar4(data_1, &method, &subsurface_offset, &aniso_offset, &radius_offset); + svm_unpack_node_uchar4(data_2, &color_offset, &ior_offset, &dummy, &dummy); + + float subsurface = stack_load_float(stack, subsurface_offset); + float subsurface_anisotropy = stack_load_float(stack, aniso_offset); + float subsurface_ior = stack_load_float(stack, ior_offset); + Spectrum subsurface_color = rgb_to_spectrum(stack_load_float3(stack, color_offset)); + Spectrum subsurface_radius = rgb_to_spectrum(stack_load_float3(stack, radius_offset)); + + Spectrum mixed_ss_base_color = mix(base_color, subsurface_color, subsurface); + + /* disable in case of diffuse ancestor, can't see it well then and + * adds considerably noise due to probabilities of continuing path + * getting lower and lower */ + if (path_flag & PATH_RAY_DIFFUSE_ANCESTOR) { + subsurface = 0.0f; + } + + /* diffuse */ + if (fabsf(average(mixed_ss_base_color)) > CLOSURE_WEIGHT_CUTOFF) { + if (subsurface > CLOSURE_WEIGHT_CUTOFF) { + Spectrum subsurf_weight = weight * mixed_ss_base_color * diffuse_weight; + ccl_private Bssrdf *bssrdf = bssrdf_alloc(sd, subsurf_weight); + + if (bssrdf == NULL) { + return; + } + + bssrdf->radius = subsurface_radius * subsurface; + bssrdf->albedo = mixed_ss_base_color; + bssrdf->N = N; + bssrdf->roughness = roughness; + + /* Clamps protecting against bad/extreme and non physical values. */ + subsurface_ior = clamp(subsurface_ior, 1.01f, 3.8f); + bssrdf->anisotropy = clamp(subsurface_anisotropy, 0.0f, 0.9f); + + /* setup bsdf */ + sd->flag |= bssrdf_setup(sd, bssrdf, (ClosureType)method, subsurface_ior); + } + else { + principled_v1_diffuse(sd, weight, mixed_ss_base_color, diffuse_weight, N, roughness); + } + } +#else + /* diffuse */ + principled_v1_diffuse(sd, weight, base_color, diffuse_weight, N, roughness); +#endif +} + +ccl_device_inline void principled_v1_specular(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private float *stack, + Spectrum weight, + int path_flag, + ClosureType distribution, + uint data, + Spectrum base_color, + float3 N, + float specular_weight, + float metallic, + float roughness, + float specular_tint) +{ +#ifdef __CAUSTICS_TRICKS__ + if (!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) { + return; + } +#endif + + uint specular_offset, aniso_offset, rotation_offset, tangent_offset; + svm_unpack_node_uchar4(data, &specular_offset, &aniso_offset, &rotation_offset, &tangent_offset); + + float specular = stack_load_float(stack, specular_offset); + + if ((specular_weight <= CLOSURE_WEIGHT_CUTOFF) || + (specular + metallic <= CLOSURE_WEIGHT_CUTOFF)) { + return; + } + + float anisotropic = stack_load_float(stack, aniso_offset); + float3 T = zero_float3(); + if (stack_valid(tangent_offset)) { + T = stack_load_float3(stack, tangent_offset); + T = rotate_around_axis(T, N, stack_load_float(stack, rotation_offset) * M_2PI_F); + } + + ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( + sd, sizeof(MicrofacetBsdf), specular_weight * weight); + if (bsdf == NULL) { + return; + } + ccl_private MicrofacetExtra *extra = (ccl_private MicrofacetExtra *)closure_alloc_extra( + sd, sizeof(MicrofacetExtra)); + if (extra == NULL) { + return; + } + + bsdf->N = N; + bsdf->ior = (2.0f / (1.0f - safe_sqrtf(0.08f * specular))) - 1.0f; + bsdf->T = T; + bsdf->extra = extra; + + float aspect = safe_sqrtf(1.0f - anisotropic * 0.9f); + + bsdf->alpha_x = sqr(roughness) / aspect; + bsdf->alpha_y = sqr(roughness) * aspect; + + // normalize lum. to isolate hue+sat + float m_cdlum = linear_rgb_to_gray(kg, base_color); + Spectrum m_ctint = m_cdlum > 0.0f ? base_color / m_cdlum : one_spectrum(); + Spectrum specular_color = mix(one_spectrum(), m_ctint, specular_tint); + + bsdf->extra->cspec0 = mix(specular * 0.08f * specular_color, base_color, metallic); + bsdf->extra->color = base_color; + + /* setup bsdf */ + if (distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID || + roughness <= 0.075f) /* use single-scatter GGX */ + sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf, sd); + else /* use multi-scatter GGX */ + sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(kg, bsdf, sd); +} + +ccl_device_inline void principled_v1_glass_refl(ccl_private ShaderData *sd, + Spectrum weight, + Spectrum base_color, + float reflection_weight, + float3 N, + float roughness, + float ior, + float specular_tint) +{ + if (reflection_weight <= CLOSURE_WEIGHT_CUTOFF) { + return; + } + + ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( + sd, sizeof(MicrofacetBsdf), reflection_weight * weight); + if (bsdf == NULL) { + return; + } + + ccl_private MicrofacetExtra *extra = (ccl_private MicrofacetExtra *)closure_alloc_extra( + sd, sizeof(MicrofacetExtra)); + if (extra == NULL) { + return; + } + + bsdf->N = N; + bsdf->T = make_float3(0.0f, 0.0f, 0.0f); + bsdf->extra = extra; + + bsdf->alpha_x = bsdf->alpha_y = sqr(roughness); + bsdf->ior = ior; + + bsdf->extra->color = base_color; + bsdf->extra->cspec0 = mix(one_spectrum(), base_color, specular_tint); + + /* setup bsdf */ + sd->flag |= bsdf_microfacet_ggx_fresnel_setup(bsdf, sd); +} + +ccl_device_inline void principled_v1_glass_refr(ccl_private ShaderData *sd, + Spectrum weight, + Spectrum base_color, + float refraction_weight, + float3 N, + float roughness, + float ior) +{ + if (refraction_weight <= CLOSURE_WEIGHT_CUTOFF) { + return; + } + + ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( + sd, sizeof(MicrofacetBsdf), base_color * weight * refraction_weight); + if (bsdf == NULL) { + return; + } + + bsdf->N = N; + bsdf->T = make_float3(0.0f, 0.0f, 0.0f); + bsdf->extra = NULL; + + bsdf->alpha_x = bsdf->alpha_y = sqr(roughness); + bsdf->ior = ior; + + /* setup bsdf */ + sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf); +} + +ccl_device_inline void principled_v1_glass_single(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private float *stack, + Spectrum weight, + int path_flag, + ClosureType distribution, + uint data, + Spectrum base_color, + float glass_weight, + float3 N, + float roughness, + float specular_tint) +{ + if (glass_weight <= CLOSURE_WEIGHT_CUTOFF) { + return; + } + + uint transmission_roughness_offset, eta_offset, dummy; + svm_unpack_node_uchar4(data, &eta_offset, &dummy, &dummy, &transmission_roughness_offset); + float transmission_roughness = stack_load_float(stack, transmission_roughness_offset); + float eta = fmaxf(stack_load_float(stack, eta_offset), 1e-5f); + + /* calculate ior */ + float ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta; + + // calculate fresnel for refraction + float fresnel = fresnel_dielectric_cos(dot(N, sd->I), ior); + + /* reflection */ + float reflection_weight = glass_weight * fresnel; +#ifdef __CAUSTICS_TRICKS__ + if (!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) { + reflection_weight = 0.0f; + } +#endif + principled_v1_glass_refl( + sd, weight, base_color, reflection_weight, N, roughness, ior, specular_tint); + + /* refraction */ + /* TODO: MNEE ensured that this is always >0, is that correct?? */ + float refraction_weight = glass_weight * (1.0f - fresnel); +#ifdef __CAUSTICS_TRICKS__ + if (!kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) { + refraction_weight = 0.0f; + } +#endif + if (distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID) + transmission_roughness = 1.0f - (1.0f - roughness) * (1.0f - transmission_roughness); + else + transmission_roughness = roughness; + principled_v1_glass_refr( + sd, weight, base_color, refraction_weight, N, transmission_roughness, ior); +} + +ccl_device_inline void principled_v1_glass_multi(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private float *stack, + Spectrum weight, + int path_flag, + uint data, + Spectrum base_color, + float glass_weight, + float3 N, + float roughness, + float specular_tint) +{ +#ifdef __CAUSTICS_TRICKS__ + if (!kernel_data.integrator.caustics_reflective && !kernel_data.integrator.caustics_refractive && + (path_flag & PATH_RAY_DIFFUSE)) { + return; + } +#endif + + if (glass_weight <= CLOSURE_WEIGHT_CUTOFF) { + return; + } + + uint eta_offset, dummy; + svm_unpack_node_uchar4(data, &eta_offset, &dummy, &dummy, &dummy); + float eta = fmaxf(stack_load_float(stack, eta_offset), 1e-5f); + + ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( + sd, sizeof(MicrofacetBsdf), glass_weight * weight); + if (bsdf == NULL) { + return; + } + ccl_private MicrofacetExtra *extra = (ccl_private MicrofacetExtra *)closure_alloc_extra( + sd, sizeof(MicrofacetExtra)); + if (extra == NULL) { + return; + } + + bsdf->N = N; + bsdf->extra = extra; + bsdf->T = make_float3(0.0f, 0.0f, 0.0f); + + bsdf->alpha_x = bsdf->alpha_y = sqr(roughness); + bsdf->ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta; + + bsdf->extra->color = base_color; + bsdf->extra->cspec0 = mix(one_spectrum(), base_color, specular_tint); + + /* setup bsdf */ + sd->flag |= bsdf_microfacet_multi_ggx_glass_fresnel_setup(kg, bsdf, sd); +} + +ccl_device_inline void principled_v1_sheen(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private float *stack, + Spectrum weight, + uint data, + Spectrum base_color, + float diffuse_weight, + float3 N) +{ + uint sheen_offset, sheen_tint_offset, dummy; + svm_unpack_node_uchar4(data, &dummy, &sheen_offset, &sheen_tint_offset, &dummy); + float sheen = stack_load_float(stack, sheen_offset); + + float sheen_weight = diffuse_weight * sheen; + if (sheen_weight <= CLOSURE_WEIGHT_CUTOFF) { + return; + } + + // normalize lum. to isolate hue+sat + float m_cdlum = linear_rgb_to_gray(kg, base_color); + Spectrum m_ctint = m_cdlum > 0.0f ? base_color / m_cdlum : one_spectrum(); + + /* color of the sheen component */ + float sheen_tint = stack_load_float(stack, sheen_tint_offset); + Spectrum sheen_color = mix(one_spectrum(), m_ctint, sheen_tint); + + ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)bsdf_alloc( + sd, sizeof(PrincipledSheenBsdf), sheen_weight * sheen_color * weight); + + if (bsdf == NULL) { + return; + } + + bsdf->N = N; + + /* setup bsdf */ + sd->flag |= bsdf_principled_sheen_setup(sd, bsdf); +} + +ccl_device_inline void principled_v1_clearcoat(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private float *stack, + Spectrum weight, + int path_flag, + uint data) +{ +#ifdef __CAUSTICS_TRICKS__ + if (!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) { + return; + } +#endif + + uint clearcoat_offset, roughness_offset, normal_offset, dummy; + svm_unpack_node_uchar4(data, &clearcoat_offset, &roughness_offset, &normal_offset, &dummy); + float clearcoat = stack_load_float(stack, clearcoat_offset); + + if (clearcoat <= CLOSURE_WEIGHT_CUTOFF) { + return; + } + + float roughness = stack_load_float(stack, roughness_offset); + float3 N = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N; + if (!(sd->type & PRIMITIVE_CURVE)) { + N = ensure_valid_reflection(sd->Ng, sd->I, N); + } + + ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( + sd, sizeof(MicrofacetBsdf), 0.25f * weight * clearcoat); + + if (bsdf == NULL) { + return; + } + + bsdf->N = N; + bsdf->T = make_float3(0.0f, 0.0f, 0.0f); + bsdf->ior = 1.5f; + bsdf->extra = NULL; + + bsdf->alpha_x = bsdf->alpha_y = sqr(roughness); + + /* setup bsdf */ + sd->flag |= bsdf_microfacet_ggx_clearcoat_setup(bsdf, sd); +} + +/* Principled v2 components */ + +ccl_device_inline void principled_v2_diffuse_sss(ccl_private ShaderData *sd, + ccl_private float *stack, + Spectrum weight, + int path_flag, + uint data, + Spectrum base_color, + float ior, + float3 N) +{ + if (reduce_max(weight * base_color) <= CLOSURE_WEIGHT_CUTOFF) { + return; + } + +#ifdef __SUBSURFACE__ + uint method, scale_offset, aniso_offset, radius_offset; + svm_unpack_node_uchar4(data, &scale_offset, &aniso_offset, &radius_offset, &method); + + float aniso = stack_load_float(stack, aniso_offset); + Spectrum radius = rgb_to_spectrum(stack_load_float3(stack, radius_offset)) * + stack_load_float(stack, scale_offset); + + /* Fall back to diffuse if there has been a diffuse bounce before or the radius is too small. */ + if ((path_flag & PATH_RAY_DIFFUSE_ANCESTOR) == 0 && reduce_max(radius) > 1e-7f) { + ccl_private Bssrdf *bssrdf = bssrdf_alloc(sd, base_color * weight); + + if (bssrdf == NULL) { + return; + } + + bssrdf->radius = radius; + bssrdf->albedo = base_color; + bssrdf->N = N; + bssrdf->roughness = FLT_MAX; + + /* Clamps protecting against bad/extreme and non physical values. */ + bssrdf->anisotropy = clamp(aniso, 0.0f, 0.9f); + + /* setup bsdf */ + sd->flag |= bssrdf_setup(sd, bssrdf, (ClosureType)method, clamp(ior, 1.01f, 3.8f)); + + return; + } +#endif + + ccl_private DiffuseBsdf *bsdf = (ccl_private DiffuseBsdf *)bsdf_alloc( + sd, sizeof(DiffuseBsdf), base_color * weight); + + if (bsdf == NULL) { + return; + } + + bsdf->N = N; + + /* setup bsdf */ + sd->flag |= bsdf_diffuse_setup(bsdf); +} + +ccl_device_inline Spectrum principled_v2_clearcoat(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private float *stack, + Spectrum weight, + int path_flag, + uint data) +{ + uint clearcoat_offset, roughness_offset, tint_offset, normal_offset; + svm_unpack_node_uchar4(data, &clearcoat_offset, &roughness_offset, &tint_offset, &normal_offset); + + float3 N = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N; + Spectrum tint = saturate(rgb_to_spectrum(stack_load_float3(stack, tint_offset))); + if (tint != one_spectrum()) { + /* Tint is normalized to perpendicular incidence. + * Therefore, if we define the coating thickness as length 1, the length along the ray is + * t = sqrt(1+tan^2(angle(N, I))) = sqrt(1+tan^2(acos(dotNI))) = 1 / dotNI. + * From Beer's law, we have T = exp(-sigma_e * t). + * Therefore, tint = exp(-sigma_e * 1) (per def.), so -sigma_e = log(tint). + * From this, T = exp(log(tint) * t) = exp(log(tint)) ^ t = tint ^ t; + * + * Note that this is only an approximation - in particular, the exit path of the + * light that bounces off the main layer is not accounted for. + * Ideally, we should be attenuating by sqrt(tint) both ways. Currently, the model + * is accurate for perfect mirrors since both entry and exit have the same cosNI there, + * but if e.g. the base is diffuse and we look at it from a grazing angle, in reality + * the cosNI of the exit bounce will be much higher on average, so the tint would be + * less extreme. + * TODO: Maybe account for this by setting + * OD := 0.5*OD + 0.5*mix(1.59, OD, metallic * (1 - roughness)), + * where 1.59 is the closest numerical fit for average optical depth on lambertian reflectors. + * That way, mirrors preserve their look, but diffuse-ish objects have a more natural behavior. + */ + float cosNI = dot(sd->I, N); + /* Refract incoming direction into clearcoat material, which has a fixed IOR of 1.5. + * TIR is no concern here since we're always coming from the outside. */ + float cosNT = sqrtf(1.0f - sqr(1.0f / 1.5f) * (1 - sqr(cosNI))); + float optical_depth = 1.0f / cosNT; + tint = pow(tint, optical_depth); + } + + float clearcoat = saturatef(stack_load_float(stack, clearcoat_offset)); + if (clearcoat <= CLOSURE_WEIGHT_CUTOFF) { + return tint; + } + +#ifdef __CAUSTICS_TRICKS__ + if (!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) { + return tint; + } +#endif + + float roughness = saturatef(stack_load_float(stack, roughness_offset)); + if (!(sd->type & PRIMITIVE_CURVE)) { + N = ensure_valid_reflection(sd->Ng, sd->I, N); + } + + ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( + sd, sizeof(MicrofacetBsdf), clearcoat * weight); + + if (bsdf == NULL) { + return tint; + } + + bsdf->N = N; + bsdf->T = make_float3(0.0f, 0.0f, 0.0f); + bsdf->ior = 1.5f; + bsdf->extra = NULL; + + bsdf->alpha_x = bsdf->alpha_y = sqr(roughness); + + /* setup bsdf */ + sd->flag |= bsdf_microfacet_ggx_clearcoat_v2_setup(kg, bsdf, sd); + + return tint * (1.0f - clearcoat_E(kg, dot(sd->I, N), roughness) * clearcoat); +} + +ccl_device_inline float principled_v2_sheen(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private float *stack, + Spectrum weight, + Spectrum N, + uint data) +{ + uint sheen_offset, sheen_tint_offset, sheen_roughness_offset, dummy; + svm_unpack_node_uchar4(data, &dummy, &sheen_offset, &sheen_tint_offset, &sheen_roughness_offset); + + float sheen = stack_load_float(stack, sheen_offset); + if (sheen <= CLOSURE_WEIGHT_CUTOFF) { + return 1.0f; + } + + float roughness = stack_load_float(stack, sheen_roughness_offset); + ccl_private PrincipledSheenBsdf *bsdf = (ccl_private PrincipledSheenBsdf *)bsdf_alloc( + sd, sizeof(PrincipledSheenBsdf), sheen * weight); // TODO include tint + + if (bsdf == NULL) { + return 1.0f; + } + + bsdf->N = N; + bsdf->roughness = sqr(roughness); + + /* setup bsdf */ + sd->flag |= bsdf_principled_sheen_v2_setup(kg, sd, bsdf); + + return 1.0f - sheen * bsdf->avg_value; // TODO include tint +} + +ccl_device_inline float principled_v2_specular(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private float *stack, + Spectrum weight, + Spectrum base_color, + float roughness, + float metallic, + float ior, + float transmission, + float3 N, + uint data1, + uint data2) +{ + // TODO Handle caustics flag + + if (metallic + (1.0f - transmission) <= CLOSURE_WEIGHT_CUTOFF) { + return 0.0f; + } + + uint edge_offset, dummy; + uint aniso_offset, rotation_offset, tangent_offset; + svm_unpack_node_uchar4(data1, &dummy, &edge_offset, &dummy, &dummy); + svm_unpack_node_uchar4(data2, &aniso_offset, &rotation_offset, &tangent_offset, &dummy); + + /* This function handles two specular components: + * 1. Metallic: The overall energy is given by the metallic input + * 2. Dielectric opaque: The overall energy is given by (1-metallic)*(1-transmission) + * Both of these are handled by one closure, which adds up two Fresnel terms. + * On top of that, there is also the transmissive component, that is handled by the glass code. + */ + + float anisotropic = stack_load_float(stack, aniso_offset); + float aspect = safe_sqrtf(1.0f - anisotropic * 0.9f); + float3 T = zero_float3(); + if (stack_valid(tangent_offset)) { + T = stack_load_float3(stack, tangent_offset); + T = rotate_around_axis(T, N, stack_load_float(stack, rotation_offset) * M_2PI_F); + } + Spectrum edge_color = rgb_to_spectrum(stack_load_float3(stack, edge_offset)); + + ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( + sd, sizeof(MicrofacetBsdf), weight); + if (bsdf == NULL) { + return 0.0f; + } + ccl_private MicrofacetExtrav2 *extra = (ccl_private MicrofacetExtrav2 *)closure_alloc_extra( + sd, sizeof(MicrofacetExtrav2)); + if (extra == NULL) { + return 0.0f; + } + + bsdf->N = N; + bsdf->ior = ior; + bsdf->T = T; + bsdf->extra = (MicrofacetExtra *)extra; + + bsdf->alpha_x = sqr(roughness) / aspect; + bsdf->alpha_y = sqr(roughness) * aspect; + + extra->metal_base = base_color; + extra->metal_edge_factor = metallic_edge_factor(base_color, edge_color); + + float dielectric = (1.0f - metallic) * (1.0f - transmission); + sd->flag |= bsdf_microfacet_ggx_fresnel_v2_setup(kg, bsdf, sd, metallic, dielectric); + + return microfacet_ggx_dielectric_E(kg, dot(sd->I, N), roughness, ior); +} + +ccl_device_inline void principled_v2_glass(KernelGlobals kg, + ccl_private ShaderData *sd, + Spectrum weight, + float transmission, + float roughness, + float ior, + float3 N) +{ + ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( + sd, sizeof(MicrofacetBsdf), transmission * weight); + if (bsdf == NULL) { + return; + } + + bsdf->N = N; + bsdf->T = make_float3(0.0f, 0.0f, 0.0f); + + bsdf->alpha_x = bsdf->alpha_y = sqr(roughness); + bsdf->ior = (sd->flag & SD_BACKFACING) ? 1.0f / ior : ior; + + /* setup bsdf */ + sd->flag |= bsdf_microfacet_multi_ggx_glass_setup(kg, bsdf, sd, one_spectrum()); +} + +ccl_device void svm_node_closure_principled_v2(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private float *stack, + uint4 node_1, + uint4 node_2, + float mix_weight, + int path_flag, + int *offset) +{ + Spectrum weight = sd->svm_closure_weight * mix_weight; + + /* Load shared parameter data. */ + uint base_color_offset, normal_offset, dummy; + uint roughness_offset, metallic_offset, ior_offset, transmission_offset; + svm_unpack_node_uchar4(node_1.y, &dummy, &base_color_offset, &normal_offset, &dummy); + svm_unpack_node_uchar4( + node_1.z, &roughness_offset, &metallic_offset, &ior_offset, &transmission_offset); + + Spectrum base_color = rgb_to_spectrum(stack_load_float3(stack, base_color_offset)); + float3 N = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N; + if (!(sd->type & PRIMITIVE_CURVE)) { + N = ensure_valid_reflection(sd->Ng, sd->I, N); + } + float roughness = saturatef(stack_load_float(stack, roughness_offset)); + float metallic = saturatef(stack_load_float(stack, metallic_offset)); + float ior = fmaxf(stack_load_float(stack, ior_offset), 1e-5f); + float transmission = saturatef(stack_load_float(stack, transmission_offset)); + + weight *= principled_v2_clearcoat(kg, sd, stack, weight, path_flag, node_2.w); + weight *= principled_v2_sheen(kg, sd, stack, weight, N, node_2.z); + + float dielectric_albedo = principled_v2_specular(kg, + sd, + stack, + weight, + base_color, + roughness, + metallic, + ior, + transmission, + N, + node_2.x, + node_2.y); + weight *= 1.0f - metallic; + + principled_v2_glass(kg, sd, weight, transmission, roughness, ior, N); + + weight *= (1.0f - transmission) * (1.0f - dielectric_albedo); + + principled_v2_diffuse_sss(sd, stack, weight, path_flag, node_1.w, base_color, ior, N); +} + +ccl_device void svm_node_closure_principled(KernelGlobals kg, + ccl_private ShaderData *sd, + ccl_private float *stack, + uint4 node_1, + uint4 node_2, + float mix_weight, + int path_flag, + int *offset) +{ + /* Load distribution type. */ + uint packed_distribution, dummy; + svm_unpack_node_uchar4(node_2.x, &dummy, &dummy, &dummy, &packed_distribution); + ClosureType distribution = (ClosureType)packed_distribution; + + if (distribution == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) { + svm_node_closure_principled_v2(kg, sd, stack, node_1, node_2, mix_weight, path_flag, offset); + return; + } + + /* Load shared parameter data. */ + uint base_color_offset, normal_offset; + uint roughness_offset, metallic_offset, transmission_offset, specular_tint_offset; + svm_unpack_node_uchar4(node_1.y, &dummy, &base_color_offset, &normal_offset, &dummy); + svm_unpack_node_uchar4( + node_1.z, &roughness_offset, &metallic_offset, &transmission_offset, &specular_tint_offset); + + Spectrum base_color = rgb_to_spectrum(stack_load_float3(stack, base_color_offset)); + float3 N = stack_valid(normal_offset) ? stack_load_float3(stack, normal_offset) : sd->N; + if (!(sd->type & PRIMITIVE_CURVE)) { + N = ensure_valid_reflection(sd->Ng, sd->I, N); + } + float roughness = saturatef(stack_load_float(stack, roughness_offset)); + float metallic = saturatef(stack_load_float(stack, metallic_offset)); + float transmission = saturatef(stack_load_float(stack, transmission_offset)); + float specular_tint = saturatef(stack_load_float(stack, specular_tint_offset)); + + /* Calculate closure mix weights. + * The combined BSDF is mix(mix(Diffuse+SSS, Glass, transmission), Metal, metallic). */ + float diffuse_weight = (1.0f - metallic) * (1.0f - transmission); + transmission *= 1.0f - metallic; + /* NOTE: The mixing here is incorrect, the specular lobe should be metallic + (1 - transmission) + * since it models both the metallic specular as well as the non-glass dielectric specular. + * This only affects materials mixing diffuse, glass AND metal though. */ + float specular_weight = (1.0f - transmission); + Spectrum weight = sd->svm_closure_weight * mix_weight; + + /* Diffuse and subsurface */ + principled_v1_diffuse_sss( + sd, stack, weight, path_flag, node_1.w, node_2.x, base_color, diffuse_weight, N, roughness); + + /* sheen */ + principled_v1_sheen(kg, sd, stack, weight, node_2.z, base_color, diffuse_weight, N); + + /* specular reflection */ + principled_v1_specular(kg, + sd, + stack, + weight, + path_flag, + distribution, + node_2.y, + base_color, + N, + specular_weight, + metallic, + roughness, + specular_tint); + + /* glass */ + if (roughness <= 5e-2f || distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID) { + principled_v1_glass_single(kg, + sd, + stack, + weight, + path_flag, + distribution, + node_2.z, + base_color, + transmission, + N, + roughness, + specular_tint); + } + else { + principled_v1_glass_multi(kg, + sd, + stack, + weight, + path_flag, + node_2.z, + base_color, + transmission, + N, + roughness, + specular_tint); + } + + /* clearcoat */ + principled_v1_clearcoat(kg, sd, stack, weight, path_flag, node_2.w); +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/types.h b/intern/cycles/kernel/svm/types.h index 9dd8f196e0f..bce403a2df5 100644 --- a/intern/cycles/kernel/svm/types.h +++ b/intern/cycles/kernel/svm/types.h @@ -414,17 +414,25 @@ typedef enum ClosureType { CLOSURE_BSDF_DIFFUSE_RAMP_ID, CLOSURE_BSDF_PRINCIPLED_DIFFUSE_ID, CLOSURE_BSDF_PRINCIPLED_SHEEN_ID, + CLOSURE_BSDF_PRINCIPLED_SHEEN_V2_ID, CLOSURE_BSDF_DIFFUSE_TOON_ID, CLOSURE_BSDF_TRANSLUCENT_ID, /* Glossy */ CLOSURE_BSDF_REFLECTION_ID, + /* GGX without Fresnel term (baked into closure weight) */ CLOSURE_BSDF_MICROFACET_GGX_ID, + /* GGX with legacy Principled Fresnel term */ CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID, + /* GGX with v2 Principled Fresnel term */ + CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_V2_ID, + /* GTR1 for Clearcoat (TODO: Rename, is not really GGX) */ CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID, - CLOSURE_BSDF_MICROFACET_BECKMANN_ID, + /* GGX with dielectric Fresnel term (used for Clearcoat for v2) */ + CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_V2_ID, + /* Virtual closure, gets turned into regular GGX with adjusted weight */ CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID, - CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID, + CLOSURE_BSDF_MICROFACET_BECKMANN_ID, CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID, CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, CLOSURE_BSDF_PHONG_RAMP_ID, @@ -434,11 +442,15 @@ typedef enum ClosureType { /* Transmission */ CLOSURE_BSDF_REFRACTION_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID, + /* GGX without Fresnel term (baked into closure weight) */ CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID, + /* GGX with microfacet-Fresnel-based reflection and refraction */ CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, + /* Same as above, but with additional legacy Principled Fresnel term */ + CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID, + /* Virtual closure, gets turned into reflection and refraction closures */ CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID, - CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID, CLOSURE_BSDF_SHARP_GLASS_ID, CLOSURE_BSDF_HAIR_PRINCIPLED_ID, CLOSURE_BSDF_HAIR_TRANSMISSION_ID, @@ -477,19 +489,16 @@ typedef enum ClosureType { (type == CLOSURE_BSDF_REFLECTION_ID || type == CLOSURE_BSDF_REFRACTION_ID || \ type == CLOSURE_BSDF_TRANSPARENT_ID) #define CLOSURE_IS_BSDF_TRANSPARENT(type) (type == CLOSURE_BSDF_TRANSPARENT_ID) -#define CLOSURE_IS_BSDF_MULTISCATTER(type) \ - (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID || \ - type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) #define CLOSURE_IS_BSDF_MICROFACET(type) \ ((type >= CLOSURE_BSDF_MICROFACET_GGX_ID && type <= CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) || \ (type >= CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID && \ - type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) || \ - (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID)) + type <= CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID)) #define CLOSURE_IS_BSDF_MICROFACET_FRESNEL(type) \ - (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_FRESNEL_ID || \ - type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID || \ - type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID || \ - type == CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID) + (type == CLOSURE_BSDF_MICROFACET_GGX_FRESNEL_ID || \ + type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID) +// TODO Fresnel v2 +#define CLOSURE_IS_BSDF_SHEEN(type) \ + (type == CLOSURE_BSDF_PRINCIPLED_SHEEN_ID || type == CLOSURE_BSDF_PRINCIPLED_SHEEN_V2_ID) #define CLOSURE_IS_BSDF_OR_BSSRDF(type) (type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID) #define CLOSURE_IS_BSSRDF(type) \ (type >= CLOSURE_BSSRDF_BURLEY_ID && type <= CLOSURE_BSSRDF_RANDOM_WALK_FIXED_RADIUS_ID) diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 24c5a6a4540..b0d1992738d 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -1153,6 +1153,14 @@ typedef enum KernelBVHLayout { typedef struct KernelTables { int beckmann_offset; int filter_table_offset; + int ggx_E_offset; + int ggx_E_avg_offset; + int ggx_clearcoat_E_offset; + int ggx_glass_E_offset; + int ggx_glass_inv_E_offset; + int ggx_dielectric_E_offset; + int ggx_dielectric_inv_E_offset; + int sheen_E_offset; int pad1, pad2; } KernelTables; static_assert_align(KernelTables, 16); diff --git a/intern/cycles/kernel/util/lookup_table.h b/intern/cycles/kernel/util/lookup_table.h index 4db4dadab0e..d090626ab94 100644 --- a/intern/cycles/kernel/util/lookup_table.h +++ b/intern/cycles/kernel/util/lookup_table.h @@ -9,7 +9,7 @@ CCL_NAMESPACE_BEGIN ccl_device float lookup_table_read(KernelGlobals kg, float x, int offset, int size) { - x = saturatef(x) * (size - 1); + x = clamp(x * size - 0.5f, 0.0f, (float)size); int index = min(float_to_int(x), size - 1); int nindex = min(index + 1, size - 1); @@ -20,13 +20,13 @@ ccl_device float lookup_table_read(KernelGlobals kg, float x, int offset, int si return data0; float data1 = kernel_data_fetch(lookup_table, nindex + offset); - return (1.0f - t) * data0 + t * data1; + return mix(data0, data1, t); } ccl_device float lookup_table_read_2D( KernelGlobals kg, float x, float y, int offset, int xsize, int ysize) { - y = saturatef(y) * (ysize - 1); + y = clamp(y * ysize - 0.5f, 0.0f, (float)ysize); int index = min(float_to_int(y), ysize - 1); int nindex = min(index + 1, ysize - 1); @@ -37,7 +37,24 @@ ccl_device float lookup_table_read_2D( return data0; float data1 = lookup_table_read(kg, x, offset + xsize * nindex, xsize); - return (1.0f - t) * data0 + t * data1; + return mix(data0, data1, t); +} + +ccl_device float lookup_table_read_3D( + KernelGlobals kg, float x, float y, float z, int offset, int xsize, int ysize, int zsize) +{ + z = clamp(z * zsize - 0.5f, 0.0f, (float)zsize); + + int index = min(float_to_int(z), zsize - 1); + int nindex = min(index + 1, zsize - 1); + float t = z - index; + + float data0 = lookup_table_read_2D(kg, x, y, offset + xsize * ysize * index, xsize, ysize); + if (t == 0.0f) + return data0; + + float data1 = lookup_table_read_2D(kg, x, y, offset + xsize * ysize * nindex, xsize, ysize); + return mix(data0, data1, t); } CCL_NAMESPACE_END diff --git a/intern/cycles/scene/shader.cpp b/intern/cycles/scene/shader.cpp index 56670c6e4e3..bef1ce0df4b 100644 --- a/intern/cycles/scene/shader.cpp +++ b/intern/cycles/scene/shader.cpp @@ -31,6 +31,8 @@ namespace OCIO = OCIO_NAMESPACE; CCL_NAMESPACE_BEGIN +#include "scene/shader.tables" + thread_mutex ShaderManager::lookup_table_mutex; vector<float> ShaderManager::beckmann_table; bool ShaderManager::beckmann_table_ready = false; @@ -566,6 +568,33 @@ void ShaderManager::device_update_common(Device * /*device*/, } ktables->beckmann_offset = (int)beckmann_table_offset; + auto bsdf_table = [&](int *offset_entry, const float *data, size_t size, string name) { + if (!(bsdf_lookup_tables.count(name))) { + vector<float> entries(data, data + size); + bsdf_lookup_tables[name] = scene->lookup_tables->add_table(dscene, entries); + } + *offset_entry = bsdf_lookup_tables[name]; + }; + bsdf_table(&ktables->ggx_E_offset, &table_ggx_E[0][0], 32 * 32, "ggx_E"); + bsdf_table(&ktables->ggx_E_avg_offset, &table_ggx_E_avg[0], 32, "ggx_E_avg"); + bsdf_table( + &ktables->ggx_clearcoat_E_offset, &table_clearcoat_E[0][0], 16 * 16, "ggx_clearcoat_E"); + bsdf_table( + &ktables->ggx_glass_E_offset, &table_ggx_glass_E[0][0][0], 16 * 16 * 16, "ggx_glass_E"); + bsdf_table(&ktables->ggx_glass_inv_E_offset, + &table_ggx_glass_inv_E[0][0][0], + 16 * 16 * 16, + "ggx_glass_inv_E"); + bsdf_table(&ktables->ggx_dielectric_E_offset, + &table_ggx_dielectric_E[0][0][0], + 16 * 16 * 16, + "ggx_dielectric_E"); + bsdf_table(&ktables->ggx_dielectric_inv_E_offset, + &table_ggx_dielectric_inv_E[0][0][0], + 16 * 16 * 16, + "ggx_dielectric_inv_E"); + bsdf_table(&ktables->sheen_E_offset, &table_sheen_E[0][0], 32 * 32, "sheen_E"); + /* integrator */ KernelIntegrator *kintegrator = &dscene->data.integrator; kintegrator->use_volumes = has_volumes; @@ -588,6 +617,10 @@ void ShaderManager::device_update_common(Device * /*device*/, void ShaderManager::device_free_common(Device *, DeviceScene *dscene, Scene *scene) { scene->lookup_tables->remove_table(&beckmann_table_offset); + for (auto &entry : bsdf_lookup_tables) { + scene->lookup_tables->remove_table(&entry.second); + } + bsdf_lookup_tables.clear(); dscene->shaders.free(); } diff --git a/intern/cycles/scene/shader.h b/intern/cycles/scene/shader.h index 2670776aca4..6f48c2da618 100644 --- a/intern/cycles/scene/shader.h +++ b/intern/cycles/scene/shader.h @@ -231,6 +231,7 @@ class ShaderManager { static bool beckmann_table_ready; size_t beckmann_table_offset; + unordered_map<string, size_t> bsdf_lookup_tables; uint get_graph_kernel_features(ShaderGraph *graph); diff --git a/intern/cycles/scene/shader.tables b/intern/cycles/scene/shader.tables new file mode 100644 index 00000000000..9a2d97a40af --- /dev/null +++ b/intern/cycles/scene/shader.tables @@ -0,0 +1,1264 @@ +/* SPDX-License-Identifier: Apache-2.0 + * Copyright 2011-2022 Blender Foundation */ + +/* Note: this file has a non-standard extension so it is skipped by clang-format. */ + +/* Precomputed BSDF albedo tables for various microfacet distributions. */ + +static const float table_ggx_E[32][32] = { + {0.938993f, 0.858736f, 0.800571f, 0.753374f, 0.713238f, 0.678442f, 0.647723f, 0.620302f, 0.595405f, 0.573038f, 0.552392f, 0.533285f, 0.515945f, 0.499677f, 0.484473f, 0.470426f, 0.457164f, 0.444816f, 0.433116f, 0.422004f, 0.411722f, 0.401847f, 0.392444f, 0.383611f, 0.375193f, 0.367147f, 0.359387f, 0.352163f, 0.345223f, 0.338525f, 0.332036f, 0.325866f}, + {0.942738f, 0.866279f, 0.811134f, 0.766195f, 0.727883f, 0.694788f, 0.665388f, 0.639283f, 0.615624f, 0.594017f, 0.574515f, 0.556419f, 0.539656f, 0.524166f, 0.509889f, 0.496369f, 0.483729f, 0.471968f, 0.460875f, 0.450365f, 0.440542f, 0.431178f, 0.422252f, 0.41389f, 0.405924f, 0.398354f, 0.391047f, 0.384224f, 0.377665f, 0.371384f, 0.365363f, 0.359468f}, + {0.946178f, 0.873743f, 0.821452f, 0.778574f, 0.742257f, 0.710809f, 0.682893f, 0.657944f, 0.635623f, 0.615179f, 0.596415f, 0.579404f, 0.56365f, 0.548923f, 0.535197f, 0.522582f, 0.510837f, 0.499666f, 0.489196f, 0.479435f, 0.470211f, 0.461503f, 0.4532f, 0.445456f, 0.438062f, 0.431058f, 0.424383f, 0.418092f, 0.412088f, 0.406399f, 0.40087f, 0.39569f}, + {0.949756f, 0.881149f, 0.831485f, 0.790608f, 0.756361f, 0.726391f, 0.7001f, 0.676466f, 0.655176f, 0.636031f, 0.618395f, 0.602169f, 0.587374f, 0.573694f, 0.560934f, 0.549078f, 0.537966f, 0.52764f, 0.518107f, 0.509184f, 0.500732f, 0.492642f, 0.485138f, 0.478096f, 0.471514f, 0.465218f, 0.459228f, 0.453642f, 0.448353f, 0.443399f, 0.438603f, 0.434138f}, + {0.953417f, 0.888246f, 0.840978f, 0.802406f, 0.770036f, 0.741652f, 0.716727f, 0.694556f, 0.674474f, 0.656312f, 0.639932f, 0.624841f, 0.610947f, 0.598109f, 0.586429f, 0.575584f, 0.565512f, 0.556085f, 0.547336f, 0.539137f, 0.531419f, 0.524487f, 0.517923f, 0.511844f, 0.506034f, 0.500635f, 0.495476f, 0.49075f, 0.486239f, 0.482136f, 0.478268f, 0.474605f}, + {0.956708f, 0.895075f, 0.849858f, 0.813821f, 0.783021f, 0.756452f, 0.732847f, 0.711996f, 0.6933f, 0.67629f, 0.660854f, 0.646985f, 0.634265f, 0.622532f, 0.61175f, 0.601824f, 0.592715f, 0.584454f, 0.576767f, 0.569631f, 0.563046f, 0.556973f, 0.551345f, 0.546069f, 0.541248f, 0.536783f, 0.532655f, 0.528942f, 0.525551f, 0.52244f, 0.519561f, 0.516886f}, + {0.959787f, 0.901339f, 0.858526f, 0.824767f, 0.795491f, 0.770587f, 0.748376f, 0.728728f, 0.71134f, 0.695646f, 0.681395f, 0.6685f, 0.656868f, 0.646354f, 0.636793f, 0.628025f, 0.620035f, 0.612715f, 0.606052f, 0.599955f, 0.594453f, 0.589562f, 0.585089f, 0.581059f, 0.577338f, 0.574072f, 0.5711f, 0.568439f, 0.566075f, 0.563943f, 0.562054f, 0.560442f}, + {0.962795f, 0.906868f, 0.866905f, 0.835062f, 0.807402f, 0.783716f, 0.763213f, 0.744831f, 0.728521f, 0.714133f, 0.701219f, 0.689528f, 0.679048f, 0.669662f, 0.661165f, 0.653617f, 0.646934f, 0.640853f, 0.635463f, 0.630651f, 0.626301f, 0.622531f, 0.619196f, 0.616271f, 0.613734f, 0.611499f, 0.609711f, 0.608151f, 0.606875f, 0.605871f, 0.605133f, 0.604569f}, + {0.965348f, 0.911877f, 0.87486f, 0.844371f, 0.818636f, 0.796204f, 0.77703f, 0.760093f, 0.745008f, 0.731726f, 0.719978f, 0.709726f, 0.700525f, 0.692423f, 0.68525f, 0.678907f, 0.673372f, 0.668563f, 0.664407f, 0.660819f, 0.657808f, 0.655239f, 0.653235f, 0.651498f, 0.65022f, 0.649273f, 0.648646f, 0.648209f, 0.648093f, 0.648143f, 0.648444f, 0.648997f}, + {0.967272f, 0.916721f, 0.882236f, 0.852898f, 0.829009f, 0.807843f, 0.789712f, 0.774205f, 0.76051f, 0.748502f, 0.738002f, 0.728893f, 0.721084f, 0.714364f, 0.708633f, 0.703726f, 0.699584f, 0.696126f, 0.693243f, 0.691071f, 0.689301f, 0.688063f, 0.687214f, 0.686732f, 0.686602f, 0.686769f, 0.68723f, 0.687961f, 0.688866f, 0.689989f, 0.691226f, 0.692645f}, + {0.968586f, 0.921257f, 0.88888f, 0.860793f, 0.838269f, 0.81852f, 0.80152f, 0.787156f, 0.77494f, 0.764349f, 0.755223f, 0.747519f, 0.741015f, 0.735657f, 0.731289f, 0.727743f, 0.725038f, 0.722978f, 0.721559f, 0.720651f, 0.720252f, 0.720234f, 0.720618f, 0.721337f, 0.722343f, 0.723618f, 0.725022f, 0.726747f, 0.728463f, 0.730413f, 0.732549f, 0.734727f}, + {0.96923f, 0.925381f, 0.894794f, 0.867815f, 0.846234f, 0.828091f, 0.812338f, 0.799121f, 0.788072f, 0.779052f, 0.77153f, 0.765368f, 0.760397f, 0.756556f, 0.753644f, 0.751631f, 0.750357f, 0.749694f, 0.749655f, 0.750052f, 0.75089f, 0.7521f, 0.75363f, 0.755437f, 0.757483f, 0.759655f, 0.762073f, 0.764543f, 0.767111f, 0.769751f, 0.772424f, 0.775168f}, + {0.969888f, 0.929051f, 0.899625f, 0.873925f, 0.853099f, 0.8364f, 0.822071f, 0.810155f, 0.800452f, 0.792754f, 0.786807f, 0.782287f, 0.779027f, 0.776843f, 0.775539f, 0.775069f, 0.775222f, 0.775969f, 0.777249f, 0.778874f, 0.78081f, 0.783044f, 0.785524f, 0.78813f, 0.790932f, 0.793787f, 0.79679f, 0.799823f, 0.802886f, 0.806013f, 0.809039f, 0.812126f}, + {0.970458f, 0.93208f, 0.903415f, 0.878958f, 0.858946f, 0.843321f, 0.830534f, 0.82017f, 0.812067f, 0.806002f, 0.801686f, 0.798794f, 0.797162f, 0.796612f, 0.796887f, 0.797904f, 0.799518f, 0.801557f, 0.804076f, 0.806862f, 0.809902f, 0.813101f, 0.816464f, 0.819846f, 0.823393f, 0.826865f, 0.830303f, 0.833696f, 0.837071f, 0.840289f, 0.843405f, 0.846271f}, + {0.97093f, 0.934339f, 0.906008f, 0.882733f, 0.863623f, 0.849053f, 0.837939f, 0.829376f, 0.823131f, 0.818944f, 0.816482f, 0.815457f, 0.815624f, 0.816719f, 0.818588f, 0.8211f, 0.824063f, 0.827308f, 0.830801f, 0.83448f, 0.838211f, 0.841892f, 0.845532f, 0.849179f, 0.852736f, 0.856301f, 0.859794f, 0.863242f, 0.866589f, 0.869835f, 0.872989f, 0.87607f}, + {0.97133f, 0.935814f, 0.907571f, 0.885251f, 0.867183f, 0.853836f, 0.844417f, 0.837916f, 0.833826f, 0.831748f, 0.83136f, 0.832276f, 0.834192f, 0.836898f, 0.840127f, 0.843696f, 0.847553f, 0.851545f, 0.855775f, 0.85999f, 0.864261f, 0.868476f, 0.872636f, 0.876703f, 0.880618f, 0.884471f, 0.888169f, 0.891631f, 0.894991f, 0.898211f, 0.90118f, 0.903876f}, + {0.971498f, 0.936194f, 0.907977f, 0.886424f, 0.869635f, 0.857961f, 0.850455f, 0.846173f, 0.844434f, 0.844569f, 0.846203f, 0.84897f, 0.852535f, 0.856708f, 0.861232f, 0.866047f, 0.870964f, 0.875868f, 0.880772f, 0.885482f, 0.890095f, 0.894455f, 0.89851f, 0.902212f, 0.905444f, 0.908352f, 0.911154f, 0.91382f, 0.916322f, 0.918733f, 0.921009f, 0.923178f}, + {0.971515f, 0.935335f, 0.907242f, 0.886387f, 0.871259f, 0.861767f, 0.856719f, 0.855001f, 0.855742f, 0.858309f, 0.862141f, 0.866832f, 0.872116f, 0.877706f, 0.883307f, 0.888897f, 0.894213f, 0.899182f, 0.903721f, 0.907694f, 0.911501f, 0.915135f, 0.9186f, 0.921904f, 0.92507f, 0.927995f, 0.93078f, 0.933424f, 0.935897f, 0.938226f, 0.940385f, 0.942486f}, + {0.971233f, 0.933273f, 0.90534f, 0.885326f, 0.872522f, 0.865959f, 0.863968f, 0.865225f, 0.868804f, 0.873881f, 0.879788f, 0.886066f, 0.892447f, 0.898536f, 0.904109f, 0.909139f, 0.914005f, 0.918666f, 0.923149f, 0.927344f, 0.93132f, 0.935081f, 0.938582f, 0.941808f, 0.944912f, 0.947718f, 0.950344f, 0.952816f, 0.95506f, 0.957285f, 0.959182f, 0.961045f}, + {0.970675f, 0.929771f, 0.902079f, 0.883688f, 0.874158f, 0.871353f, 0.873055f, 0.877692f, 0.883998f, 0.891128f, 0.898349f, 0.90501f, 0.911219f, 0.917302f, 0.923128f, 0.928714f, 0.933918f, 0.93875f, 0.943234f, 0.947359f, 0.951162f, 0.954644f, 0.957807f, 0.960532f, 0.963028f, 0.96502f, 0.966619f, 0.967709f, 0.968388f, 0.968743f, 0.968939f, 0.969107f}, + {0.969797f, 0.924729f, 0.89772f, 0.882373f, 0.877356f, 0.879119f, 0.884863f, 0.892627f, 0.900849f, 0.908641f, 0.916223f, 0.923627f, 0.930675f, 0.937267f, 0.943249f, 0.948668f, 0.953548f, 0.957771f, 0.961262f, 0.963879f, 0.965795f, 0.967087f, 0.967986f, 0.968618f, 0.969112f, 0.969598f, 0.97003f, 0.970412f, 0.970806f, 0.971111f, 0.971429f, 0.971676f}, + {0.968571f, 0.918364f, 0.892897f, 0.882602f, 0.883448f, 0.890303f, 0.899597f, 0.908982f, 0.91838f, 0.92749f, 0.936094f, 0.943872f, 0.950714f, 0.956491f, 0.96096f, 0.964088f, 0.966142f, 0.967554f, 0.968578f, 0.969451f, 0.970231f, 0.970983f, 0.971692f, 0.972324f, 0.972884f, 0.973405f, 0.973905f, 0.974357f, 0.974748f, 0.975061f, 0.975408f, 0.975663f}, + {0.965173f, 0.910926f, 0.889046f, 0.886257f, 0.893902f, 0.905002f, 0.916487f, 0.928009f, 0.93872f, 0.948183f, 0.95588f, 0.961395f, 0.964914f, 0.967118f, 0.968655f, 0.969977f, 0.97117f, 0.9723f, 0.973341f, 0.97427f, 0.975106f, 0.975873f, 0.976565f, 0.977188f, 0.977768f, 0.978231f, 0.978716f, 0.979142f, 0.97947f, 0.979811f, 0.980083f, 0.980371f}, + {0.958495f, 0.903049f, 0.888471f, 0.895308f, 0.908717f, 0.923329f, 0.937428f, 0.949533f, 0.95859f, 0.964045f, 0.967168f, 0.96929f, 0.971163f, 0.97285f, 0.974399f, 0.97577f, 0.976987f, 0.978069f, 0.979037f, 0.97987f, 0.980611f, 0.9813f, 0.981886f, 0.982413f, 0.982955f, 0.983354f, 0.983723f, 0.984063f, 0.984398f, 0.984652f, 0.984856f, 0.985063f}, + {0.948964f, 0.895629f, 0.894262f, 0.910481f, 0.929203f, 0.946257f, 0.958732f, 0.965248f, 0.968749f, 0.971476f, 0.973909f, 0.976056f, 0.977916f, 0.979486f, 0.980913f, 0.982035f, 0.983087f, 0.983982f, 0.984791f, 0.985417f, 0.986015f, 0.98649f, 0.987023f, 0.987391f, 0.98782f, 0.988115f, 0.988375f, 0.988643f, 0.988798f, 0.989001f, 0.98932f, 0.989353f}, + {0.937118f, 0.893165f, 0.908694f, 0.93326f, 0.954062f, 0.964852f, 0.969648f, 0.973401f, 0.976567f, 0.979253f, 0.981432f, 0.983268f, 0.984715f, 0.985961f, 0.98706f, 0.987867f, 0.988676f, 0.989308f, 0.989769f, 0.990333f, 0.990721f, 0.991062f, 0.991439f, 0.9917f, 0.991872f, 0.992123f, 0.992216f, 0.99251f, 0.992717f, 0.992757f, 0.9929f, 0.993009f}, + {0.924708f, 0.901613f, 0.933658f, 0.959845f, 0.969049f, 0.974478f, 0.978882f, 0.982268f, 0.984778f, 0.986833f, 0.988426f, 0.989638f, 0.990686f, 0.991441f, 0.99211f, 0.992683f, 0.993142f, 0.993536f, 0.993918f, 0.994134f, 0.994405f, 0.994602f, 0.994731f, 0.994885f, 0.995065f, 0.995196f, 0.995408f, 0.995475f, 0.995622f, 0.995727f, 0.995661f, 0.995728f}, + {0.915237f, 0.924971f, 0.962986f, 0.973159f, 0.979981f, 0.984688f, 0.987889f, 0.989996f, 0.991679f, 0.992878f, 0.993788f, 0.994514f, 0.994998f, 0.995501f, 0.995976f, 0.996148f, 0.996387f, 0.996635f, 0.996847f, 0.996874f, 0.997059f, 0.997253f, 0.997307f, 0.997327f, 0.99745f, 0.9975f, 0.997533f, 0.997708f, 0.997762f, 0.997759f, 0.997849f, 0.997848f}, + {0.916255f, 0.96181f, 0.977531f, 0.985756f, 0.990294f, 0.992823f, 0.994433f, 0.99559f, 0.996311f, 0.996834f, 0.997191f, 0.997456f, 0.997787f, 0.997998f, 0.998229f, 0.998384f, 0.998457f, 0.998433f, 0.998494f, 0.998608f, 0.998846f, 0.998789f, 0.998969f, 0.998877f, 0.999104f, 0.999046f, 0.99894f, 0.998958f, 0.998896f, 0.999038f, 0.99902f, 0.999228f}, + {0.938232f, 0.980496f, 0.99117f, 0.995037f, 0.996819f, 0.997623f, 0.998332f, 0.99847f, 0.998858f, 0.999061f, 0.99919f, 0.999076f, 0.999342f, 0.999446f, 0.999543f, 0.99948f, 0.999434f, 0.999576f, 0.999513f, 0.999568f, 0.999704f, 0.999605f, 0.999723f, 0.999585f, 0.999633f, 0.999681f, 0.999639f, 0.999761f, 0.999682f, 0.999801f, 0.999803f, 0.999778f}, + {0.969782f, 0.995572f, 0.998327f, 0.999031f, 0.999409f, 0.999456f, 0.999751f, 0.999859f, 0.999893f, 0.999819f, 0.999782f, 0.999831f, 0.999837f, 0.999896f, 0.999957f, 0.999955f, 0.999955f, 0.999942f, 0.999964f, 0.999976f, 0.999957f, 0.999954f, 0.999962f, 0.999964f, 0.999982f, 0.999974f, 0.999968f, 0.999979f, 0.999807f, 0.999926f, 0.999962f, 0.99998f}, + {0.989677f, 0.999757f, 0.999788f, 0.999983f, 0.999994f, 0.999992f, 0.999994f, 0.999994f, 0.999999f, 0.999993f, 1.0f, 1.0f, 1.0f, 1.0f, 0.999998f, 0.999998f, 1.0f, 1.0f, 1.0f, 1.0f, 0.999996f, 0.999996f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f} +}; + +static const float table_ggx_E_avg[32] = { + 0.422975f, 0.451614f, 0.481159f, 0.511595f, 0.543123f, 0.575053f, 0.60744f, 0.640006f, 0.672404f, 0.704199f, 0.735225f, 0.765683f, 0.794568f, 0.821832f, 0.847303f, 0.871297f, 0.892859f, 0.912368f, 0.929627f, 0.944333f, 0.957303f, 0.968517f, 0.976663f, 0.98424f, 0.989949f, 0.993637f, 0.996464f, 0.99818f, 0.999062f, 1.00023f, 1.00014f, 1.00005f +}; + +static const float table_ggx_glass_E[16][16][16] = { + { + {0.546145f, 0.554928f, 0.585355f, 0.617174f, 0.649281f, 0.681332f, 0.713313f, 0.744976f, 0.776317f, 0.807153f, 0.837756f, 0.867865f, 0.897538f, 0.926556f, 0.955152f, 0.983269f}, + {0.551645f, 0.562942f, 0.597396f, 0.633016f, 0.668497f, 0.703397f, 0.737332f, 0.77021f, 0.801938f, 0.832256f, 0.861463f, 0.889042f, 0.915358f, 0.940463f, 0.964068f, 0.986394f}, + {0.558163f, 0.572828f, 0.611968f, 0.651944f, 0.691117f, 0.728661f, 0.764305f, 0.797737f, 0.828922f, 0.857906f, 0.88465f, 0.909353f, 0.932072f, 0.952713f, 0.971759f, 0.989101f}, + {0.565942f, 0.584818f, 0.629791f, 0.67474f, 0.717467f, 0.757342f, 0.793846f, 0.826921f, 0.856543f, 0.883185f, 0.906937f, 0.928087f, 0.946762f, 0.963324f, 0.978089f, 0.991121f}, + {0.575588f, 0.600003f, 0.651733f, 0.701856f, 0.748046f, 0.789334f, 0.825551f, 0.857055f, 0.884071f, 0.907377f, 0.927335f, 0.944636f, 0.959475f, 0.972171f, 0.983223f, 0.992751f}, + {0.587534f, 0.619243f, 0.678746f, 0.734276f, 0.782725f, 0.823985f, 0.858453f, 0.886872f, 0.910116f, 0.929464f, 0.945487f, 0.958873f, 0.970007f, 0.979376f, 0.987371f, 0.994102f}, + {0.602621f, 0.644047f, 0.712131f, 0.771979f, 0.821102f, 0.860106f, 0.890869f, 0.914867f, 0.933558f, 0.948679f, 0.960717f, 0.97046f, 0.978469f, 0.985064f, 0.990606f, 0.995082f}, + {0.622241f, 0.675982f, 0.752631f, 0.814525f, 0.861237f, 0.89565f, 0.920899f, 0.939713f, 0.953529f, 0.964417f, 0.972942f, 0.979727f, 0.98495f, 0.989355f, 0.992982f, 0.99591f}, + {0.647882f, 0.717283f, 0.800443f, 0.860146f, 0.900533f, 0.928044f, 0.946791f, 0.960059f, 0.969236f, 0.976488f, 0.981957f, 0.986275f, 0.989738f, 0.992396f, 0.99457f, 0.996447f}, + {0.68242f, 0.76935f, 0.853133f, 0.904615f, 0.935514f, 0.954804f, 0.967174f, 0.975482f, 0.980791f, 0.985194f, 0.988401f, 0.990902f, 0.992909f, 0.994567f, 0.995782f, 0.996746f}, + {0.729096f, 0.830817f, 0.905183f, 0.943073f, 0.963073f, 0.974575f, 0.981729f, 0.986219f, 0.988659f, 0.990971f, 0.992639f, 0.993905f, 0.995049f, 0.995809f, 0.996428f, 0.996998f}, + {0.789156f, 0.895256f, 0.948956f, 0.971336f, 0.981801f, 0.987517f, 0.990816f, 0.99266f, 0.993256f, 0.994337f, 0.995166f, 0.995713f, 0.99628f, 0.99667f, 0.996902f, 0.997157f}, + {0.859066f, 0.949326f, 0.978616f, 0.988459f, 0.99247f, 0.99464f, 0.995801f, 0.99628f, 0.995737f, 0.996129f, 0.996486f, 0.996763f, 0.996855f, 0.997043f, 0.997051f, 0.997208f}, + {0.923198f, 0.983437f, 0.99374f, 0.996554f, 0.997289f, 0.997815f, 0.998037f, 0.997932f, 0.996729f, 0.99701f, 0.997112f, 0.997122f, 0.997151f, 0.997181f, 0.99723f, 0.997244f}, + {0.967523f, 0.997301f, 0.998877f, 0.999232f, 0.998936f, 0.99887f, 0.998817f, 0.998544f, 0.997149f, 0.99719f, 0.997292f, 0.997176f, 0.997165f, 0.997177f, 0.997329f, 0.99722f}, + {0.993657f, 0.999821f, 0.999725f, 0.999639f, 0.999132f, 0.998963f, 0.998883f, 0.998629f, 0.997223f, 0.997127f, 0.997255f, 0.997299f, 0.997234f, 0.997171f, 0.997179f, 0.997287f} + }, + { + {0.631613f, 0.585535f, 0.60389f, 0.63012f, 0.658841f, 0.688715f, 0.719004f, 0.749476f, 0.779917f, 0.810074f, 0.839943f, 0.869533f, 0.898583f, 0.927148f, 0.955291f, 0.982522f}, + {0.643297f, 0.597422f, 0.618572f, 0.647969f, 0.679661f, 0.71191f, 0.743979f, 0.775505f, 0.806121f, 0.835601f, 0.863966f, 0.891141f, 0.917079f, 0.941526f, 0.9647f, 0.98657f}, + {0.656436f, 0.611642f, 0.636216f, 0.668916f, 0.703763f, 0.738348f, 0.771739f, 0.803497f, 0.8336f, 0.861669f, 0.887586f, 0.911674f, 0.933799f, 0.954275f, 0.97294f, 0.989745f}, + {0.671787f, 0.628907f, 0.657412f, 0.69396f, 0.731665f, 0.767909f, 0.801987f, 0.83317f, 0.861465f, 0.887144f, 0.910067f, 0.930601f, 0.948912f, 0.965124f, 0.979652f, 0.992398f}, + {0.689418f, 0.649953f, 0.683015f, 0.723425f, 0.763416f, 0.800574f, 0.833967f, 0.863372f, 0.889006f, 0.911341f, 0.930665f, 0.947338f, 0.961831f, 0.974299f, 0.985131f, 0.994478f}, + {0.710308f, 0.675785f, 0.713876f, 0.757741f, 0.79883f, 0.835433f, 0.866612f, 0.892936f, 0.914899f, 0.933343f, 0.948684f, 0.961643f, 0.972544f, 0.981751f, 0.989502f, 0.996116f}, + {0.734531f, 0.707423f, 0.750347f, 0.796438f, 0.836942f, 0.870809f, 0.898257f, 0.920374f, 0.938042f, 0.952242f, 0.963848f, 0.973335f, 0.981043f, 0.987507f, 0.992916f, 0.99742f}, + {0.763463f, 0.745538f, 0.792477f, 0.83811f, 0.875748f, 0.904854f, 0.927199f, 0.944194f, 0.957484f, 0.967775f, 0.975886f, 0.982365f, 0.987617f, 0.991907f, 0.995436f, 0.998383f}, + {0.797243f, 0.790409f, 0.838764f, 0.880622f, 0.912262f, 0.935119f, 0.951644f, 0.96379f, 0.972864f, 0.979631f, 0.984944f, 0.989097f, 0.992341f, 0.995011f, 0.997214f, 0.998982f}, + {0.835707f, 0.839576f, 0.884783f, 0.919588f, 0.943649f, 0.959666f, 0.970729f, 0.978468f, 0.984043f, 0.98819f, 0.991292f, 0.993741f, 0.995631f, 0.99718f, 0.998433f, 0.9994f}, + {0.87631f, 0.887301f, 0.926002f, 0.951959f, 0.967963f, 0.977871f, 0.984215f, 0.988547f, 0.991591f, 0.993787f, 0.995463f, 0.996735f, 0.997747f, 0.998521f, 0.999191f, 0.999696f}, + {0.911712f, 0.927518f, 0.958425f, 0.975578f, 0.984504f, 0.989532f, 0.992666f, 0.994708f, 0.996143f, 0.997182f, 0.997949f, 0.998526f, 0.998986f, 0.999337f, 0.999623f, 0.999866f}, + {0.933586f, 0.957793f, 0.981399f, 0.990218f, 0.994028f, 0.996008f, 0.997254f, 0.998024f, 0.998572f, 0.998947f, 0.999234f, 0.999449f, 0.999618f, 0.999754f, 0.999868f, 0.999953f}, + {0.943785f, 0.982754f, 0.994593f, 0.997301f, 0.998376f, 0.998932f, 0.999247f, 0.999475f, 0.999609f, 0.999713f, 0.999788f, 0.999845f, 0.999898f, 0.999926f, 0.999963f, 0.999987f}, + {0.963548f, 0.997089f, 0.999224f, 0.999595f, 0.999763f, 0.999841f, 0.99989f, 0.999923f, 0.999943f, 0.999958f, 0.99997f, 0.999978f, 0.999985f, 0.99999f, 0.999994f, 0.999997f}, + {0.992398f, 0.999883f, 0.999938f, 0.99995f, 0.99995f, 0.999961f, 0.999968f, 0.999957f, 0.999972f, 0.999978f, 0.999969f, 0.999965f, 0.999976f, 0.999972f, 0.999972f, 0.999975f} + }, + { + {0.7033f, 0.624366f, 0.628578f, 0.647018f, 0.670764f, 0.697179f, 0.724674f, 0.752952f, 0.781676f, 0.810399f, 0.838951f, 0.867394f, 0.895481f, 0.923f, 0.950124f, 0.975904f}, + {0.71783f, 0.640314f, 0.646483f, 0.667403f, 0.693574f, 0.721948f, 0.750909f, 0.779952f, 0.808798f, 0.836672f, 0.863665f, 0.889655f, 0.914717f, 0.938198f, 0.960705f, 0.981332f}, + {0.73379f, 0.658809f, 0.667588f, 0.691082f, 0.719766f, 0.749734f, 0.779826f, 0.808921f, 0.83682f, 0.863278f, 0.887645f, 0.910721f, 0.932106f, 0.951828f, 0.969822f, 0.985843f}, + {0.751787f, 0.680693f, 0.692507f, 0.718771f, 0.749456f, 0.780616f, 0.810739f, 0.838952f, 0.864925f, 0.888953f, 0.910546f, 0.929958f, 0.947602f, 0.963301f, 0.977202f, 0.989426f}, + {0.771632f, 0.706199f, 0.721422f, 0.750329f, 0.782343f, 0.813589f, 0.842857f, 0.869098f, 0.892508f, 0.913093f, 0.931231f, 0.947079f, 0.960913f, 0.972917f, 0.983348f, 0.992309f}, + {0.794009f, 0.736069f, 0.754824f, 0.785859f, 0.817909f, 0.848151f, 0.874727f, 0.898082f, 0.917887f, 0.934733f, 0.949146f, 0.9615f, 0.971885f, 0.980801f, 0.988265f, 0.994553f}, + {0.81858f, 0.770343f, 0.792317f, 0.823838f, 0.854519f, 0.882076f, 0.905208f, 0.924371f, 0.940351f, 0.953406f, 0.964235f, 0.973197f, 0.980488f, 0.986779f, 0.992066f, 0.996382f}, + {0.84565f, 0.808161f, 0.832237f, 0.862468f, 0.890477f, 0.91359f, 0.93242f, 0.947124f, 0.959126f, 0.96853f, 0.976047f, 0.982215f, 0.987344f, 0.991477f, 0.994879f, 0.997734f}, + {0.874026f, 0.847531f, 0.872048f, 0.89919f, 0.922681f, 0.940799f, 0.954911f, 0.96549f, 0.973778f, 0.980043f, 0.985121f, 0.988998f, 0.992127f, 0.994722f, 0.996887f, 0.998578f}, + {0.901745f, 0.88446f, 0.90746f, 0.930681f, 0.949353f, 0.962582f, 0.972388f, 0.979433f, 0.984484f, 0.988402f, 0.991401f, 0.993684f, 0.995532f, 0.997017f, 0.998276f, 0.999172f}, + {0.92477f, 0.913415f, 0.936122f, 0.956473f, 0.970167f, 0.979084f, 0.985043f, 0.989036f, 0.99183f, 0.993909f, 0.995522f, 0.996708f, 0.997708f, 0.998436f, 0.999098f, 0.999583f}, + {0.937524f, 0.934214f, 0.959427f, 0.976221f, 0.985122f, 0.990088f, 0.993034f, 0.994956f, 0.996266f, 0.997246f, 0.997978f, 0.998526f, 0.998961f, 0.999307f, 0.999597f, 0.999814f}, + {0.938082f, 0.95327f, 0.979643f, 0.99008f, 0.994165f, 0.996258f, 0.997424f, 0.998121f, 0.99862f, 0.998978f, 0.999263f, 0.999442f, 0.999613f, 0.999743f, 0.999853f, 0.999932f}, + {0.937776f, 0.978551f, 0.993783f, 0.997285f, 0.998457f, 0.998989f, 0.999303f, 0.999512f, 0.999633f, 0.999719f, 0.999798f, 0.999849f, 0.999891f, 0.999916f, 0.999962f, 0.999985f}, + {0.959602f, 0.996313f, 0.999131f, 0.999611f, 0.999778f, 0.999847f, 0.9999f, 0.999932f, 0.999941f, 0.999959f, 0.999973f, 0.999979f, 0.999985f, 0.999988f, 0.999993f, 0.999997f}, + {0.992047f, 0.999866f, 0.999938f, 0.999952f, 0.99995f, 0.999963f, 0.999969f, 0.999957f, 0.999972f, 0.999977f, 0.999969f, 0.999965f, 0.999976f, 0.999972f, 0.999972f, 0.999975f} + }, + { + {0.755135f, 0.661173f, 0.653773f, 0.664733f, 0.683312f, 0.705748f, 0.730117f, 0.755903f, 0.782496f, 0.809353f, 0.836357f, 0.863372f, 0.889953f, 0.916305f, 0.942201f, 0.966181f}, + {0.770474f, 0.680031f, 0.674374f, 0.68761f, 0.708103f, 0.732226f, 0.757874f, 0.784137f, 0.810612f, 0.836641f, 0.862026f, 0.886647f, 0.910527f, 0.932779f, 0.954265f, 0.973625f}, + {0.787016f, 0.701255f, 0.698294f, 0.713503f, 0.736268f, 0.761355f, 0.787675f, 0.813929f, 0.839407f, 0.863906f, 0.886723f, 0.90856f, 0.928769f, 0.94772f, 0.964805f, 0.979988f}, + {0.805089f, 0.725584f, 0.725517f, 0.743068f, 0.767051f, 0.79318f, 0.819282f, 0.84439f, 0.867851f, 0.890054f, 0.910067f, 0.928265f, 0.945076f, 0.960184f, 0.973426f, 0.984878f}, + {0.824429f, 0.75299f, 0.756091f, 0.775729f, 0.800469f, 0.826213f, 0.851312f, 0.874399f, 0.895384f, 0.914253f, 0.931078f, 0.945795f, 0.95901f, 0.970548f, 0.980428f, 0.989062f}, + {0.845338f, 0.783391f, 0.789807f, 0.810953f, 0.83533f, 0.859928f, 0.882298f, 0.902505f, 0.920366f, 0.935538f, 0.948974f, 0.9606f, 0.970496f, 0.979028f, 0.986278f, 0.992331f}, + {0.867308f, 0.816128f, 0.825491f, 0.846774f, 0.869557f, 0.891891f, 0.911074f, 0.92777f, 0.942154f, 0.953901f, 0.964055f, 0.97258f, 0.97956f, 0.98555f, 0.99069f, 0.99478f}, + {0.889951f, 0.84958f, 0.86063f, 0.880855f, 0.901829f, 0.920435f, 0.936239f, 0.94922f, 0.960077f, 0.968704f, 0.97578f, 0.981723f, 0.9867f, 0.990652f, 0.993934f, 0.996712f}, + {0.911502f, 0.880738f, 0.892697f, 0.911203f, 0.929411f, 0.944558f, 0.956842f, 0.966517f, 0.974198f, 0.980015f, 0.984958f, 0.988685f, 0.991689f, 0.994284f, 0.99634f, 0.99798f}, + {0.929911f, 0.906006f, 0.918487f, 0.936132f, 0.952085f, 0.963857f, 0.973151f, 0.979774f, 0.984648f, 0.988398f, 0.991266f, 0.993529f, 0.995307f, 0.996735f, 0.997922f, 0.99883f}, + {0.941852f, 0.922287f, 0.938595f, 0.956946f, 0.970284f, 0.979251f, 0.985269f, 0.989209f, 0.991919f, 0.993943f, 0.995489f, 0.996642f, 0.997589f, 0.998321f, 0.99894f, 0.999411f}, + {0.943856f, 0.932884f, 0.956896f, 0.974835f, 0.98458f, 0.990057f, 0.993057f, 0.995044f, 0.996328f, 0.997257f, 0.997959f, 0.998468f, 0.998932f, 0.999239f, 0.999538f, 0.99973f}, + {0.936692f, 0.948081f, 0.976888f, 0.989024f, 0.993894f, 0.996212f, 0.997452f, 0.998183f, 0.998637f, 0.999004f, 0.999262f, 0.999414f, 0.999597f, 0.999716f, 0.999827f, 0.999902f}, + {0.933786f, 0.975358f, 0.99277f, 0.997021f, 0.998414f, 0.999009f, 0.999327f, 0.999521f, 0.999655f, 0.99972f, 0.999794f, 0.999843f, 0.999884f, 0.999913f, 0.999955f, 0.999978f}, + {0.957595f, 0.99572f, 0.998989f, 0.999584f, 0.999779f, 0.999853f, 0.999905f, 0.999931f, 0.999945f, 0.999959f, 0.999972f, 0.999978f, 0.999982f, 0.999987f, 0.999992f, 0.999997f}, + {0.991893f, 0.999849f, 0.999935f, 0.999951f, 0.999951f, 0.999963f, 0.99997f, 0.999957f, 0.999972f, 0.999978f, 0.999969f, 0.999965f, 0.999976f, 0.999972f, 0.999972f, 0.999975f} + }, + { + {0.791906f, 0.69219f, 0.676114f, 0.680855f, 0.694521f, 0.713153f, 0.73442f, 0.757596f, 0.78181f, 0.806742f, 0.831895f, 0.85727f, 0.882394f, 0.907418f, 0.931743f, 0.95388f}, + {0.807178f, 0.7128f, 0.698837f, 0.7056f, 0.721143f, 0.741125f, 0.763599f, 0.78701f, 0.811022f, 0.835147f, 0.858726f, 0.881888f, 0.904514f, 0.925531f, 0.945875f, 0.963777f}, + {0.823371f, 0.735468f, 0.724418f, 0.733205f, 0.750747f, 0.771528f, 0.794286f, 0.81766f, 0.840677f, 0.863166f, 0.884389f, 0.904885f, 0.923826f, 0.941856f, 0.958073f, 0.972386f}, + {0.840628f, 0.760701f, 0.752903f, 0.763847f, 0.782368f, 0.803786f, 0.826433f, 0.848464f, 0.869604f, 0.890026f, 0.908455f, 0.92551f, 0.941246f, 0.955699f, 0.968406f, 0.979107f}, + {0.858634f, 0.788152f, 0.783764f, 0.796474f, 0.815666f, 0.836682f, 0.858106f, 0.878444f, 0.897133f, 0.914273f, 0.929764f, 0.943545f, 0.956074f, 0.967169f, 0.976656f, 0.984778f}, + {0.877468f, 0.817314f, 0.81627f, 0.830435f, 0.849078f, 0.869064f, 0.888216f, 0.905613f, 0.921754f, 0.935558f, 0.948009f, 0.95891f, 0.968269f, 0.976576f, 0.98354f, 0.989235f}, + {0.896459f, 0.847072f, 0.848977f, 0.863348f, 0.880767f, 0.89896f, 0.915259f, 0.930031f, 0.942873f, 0.953876f, 0.963239f, 0.971341f, 0.977941f, 0.983842f, 0.988733f, 0.99273f}, + {0.914979f, 0.875448f, 0.879065f, 0.892873f, 0.909259f, 0.92472f, 0.938542f, 0.950336f, 0.960267f, 0.968481f, 0.975098f, 0.980933f, 0.985738f, 0.989508f, 0.992699f, 0.995372f}, + {0.931148f, 0.899453f, 0.904363f, 0.91789f, 0.932976f, 0.94634f, 0.957716f, 0.966746f, 0.974081f, 0.979724f, 0.984545f, 0.988115f, 0.991066f, 0.993629f, 0.995614f, 0.997218f}, + {0.943403f, 0.916273f, 0.923181f, 0.937849f, 0.952534f, 0.963889f, 0.972977f, 0.979645f, 0.984447f, 0.988114f, 0.990997f, 0.993144f, 0.994956f, 0.996364f, 0.997543f, 0.998404f}, + {0.948976f, 0.92477f, 0.93797f, 0.955598f, 0.969266f, 0.978649f, 0.984972f, 0.988992f, 0.991794f, 0.993823f, 0.995345f, 0.996493f, 0.997425f, 0.998145f, 0.99875f, 0.999192f}, + {0.945591f, 0.930181f, 0.953883f, 0.972831f, 0.983563f, 0.989624f, 0.992798f, 0.995004f, 0.996312f, 0.99721f, 0.997915f, 0.99841f, 0.998874f, 0.999167f, 0.999462f, 0.999627f}, + {0.935111f, 0.944096f, 0.974462f, 0.987866f, 0.993441f, 0.996016f, 0.997409f, 0.998169f, 0.998633f, 0.998991f, 0.999237f, 0.999409f, 0.999569f, 0.999698f, 0.99979f, 0.999856f}, + {0.931369f, 0.973258f, 0.991863f, 0.996672f, 0.99832f, 0.998987f, 0.999325f, 0.999515f, 0.999664f, 0.999726f, 0.999793f, 0.999838f, 0.999886f, 0.99991f, 0.99995f, 0.999968f}, + {0.956476f, 0.995341f, 0.998866f, 0.999534f, 0.999764f, 0.999849f, 0.999913f, 0.99993f, 0.999946f, 0.999962f, 0.999972f, 0.999976f, 0.999982f, 0.999986f, 0.999991f, 0.999997f}, + {0.991809f, 0.999835f, 0.999933f, 0.999951f, 0.999952f, 0.999964f, 0.99997f, 0.999957f, 0.999972f, 0.999978f, 0.999969f, 0.999965f, 0.999976f, 0.999972f, 0.999972f, 0.999975f} + }, + { + {0.818297f, 0.717114f, 0.694785f, 0.694342f, 0.703768f, 0.718837f, 0.73701f, 0.757527f, 0.779494f, 0.802509f, 0.825628f, 0.849226f, 0.872765f, 0.896291f, 0.918974f, 0.939604f}, + {0.833133f, 0.73869f, 0.718909f, 0.720566f, 0.731697f, 0.748196f, 0.767401f, 0.788233f, 0.809931f, 0.831982f, 0.853779f, 0.875361f, 0.896604f, 0.916442f, 0.935584f, 0.952167f}, + {0.848657f, 0.762005f, 0.745546f, 0.74926f, 0.762459f, 0.77941f, 0.799137f, 0.819719f, 0.8407f, 0.861063f, 0.880752f, 0.899775f, 0.91747f, 0.934615f, 0.949879f, 0.963377f}, + {0.8649f, 0.787208f, 0.774337f, 0.780339f, 0.79444f, 0.812079f, 0.831559f, 0.850965f, 0.869981f, 0.888585f, 0.905668f, 0.921563f, 0.936315f, 0.950173f, 0.961989f, 0.972198f}, + {0.881461f, 0.813868f, 0.804703f, 0.812521f, 0.827306f, 0.844582f, 0.862949f, 0.880905f, 0.897513f, 0.913121f, 0.927539f, 0.940462f, 0.952246f, 0.962898f, 0.971853f, 0.979696f}, + {0.898292f, 0.841163f, 0.835515f, 0.844687f, 0.859203f, 0.875685f, 0.892135f, 0.907546f, 0.922038f, 0.934734f, 0.946206f, 0.956606f, 0.965452f, 0.973447f, 0.980231f, 0.985548f}, + {0.914692f, 0.867788f, 0.865073f, 0.874899f, 0.88842f, 0.903681f, 0.917781f, 0.930989f, 0.942727f, 0.953001f, 0.961885f, 0.969526f, 0.975935f, 0.981647f, 0.986401f, 0.990233f}, + {0.929949f, 0.891663f, 0.890753f, 0.900625f, 0.913808f, 0.927174f, 0.939617f, 0.950495f, 0.959815f, 0.967745f, 0.97412f, 0.979688f, 0.984353f, 0.988026f, 0.991205f, 0.99376f}, + {0.942335f, 0.910169f, 0.911015f, 0.921508f, 0.934511f, 0.946868f, 0.957644f, 0.96641f, 0.973551f, 0.979036f, 0.983774f, 0.987343f, 0.990262f, 0.992766f, 0.994742f, 0.9963f}, + {0.950568f, 0.921421f, 0.925018f, 0.937993f, 0.95199f, 0.963241f, 0.97238f, 0.979133f, 0.983967f, 0.987701f, 0.990597f, 0.992658f, 0.99448f, 0.99588f, 0.997082f, 0.997929f}, + {0.952355f, 0.925186f, 0.936368f, 0.953857f, 0.967893f, 0.977715f, 0.98436f, 0.988623f, 0.991479f, 0.993643f, 0.995152f, 0.996288f, 0.9972f, 0.997897f, 0.998529f, 0.998941f}, + {0.94611f, 0.927807f, 0.951216f, 0.970995f, 0.982455f, 0.98904f, 0.992455f, 0.994849f, 0.996185f, 0.997122f, 0.997852f, 0.998356f, 0.998788f, 0.9991f, 0.999364f, 0.999519f}, + {0.933846f, 0.941313f, 0.972597f, 0.986844f, 0.992965f, 0.995775f, 0.997297f, 0.998112f, 0.998611f, 0.998967f, 0.99921f, 0.999397f, 0.999559f, 0.999665f, 0.999759f, 0.999818f}, + {0.929792f, 0.971804f, 0.9912f, 0.996412f, 0.998198f, 0.998926f, 0.999303f, 0.999503f, 0.999663f, 0.999722f, 0.999787f, 0.999828f, 0.999879f, 0.999902f, 0.999943f, 0.999962f}, + {0.955791f, 0.995089f, 0.998764f, 0.999497f, 0.999757f, 0.99984f, 0.999911f, 0.999932f, 0.999947f, 0.999961f, 0.999973f, 0.999977f, 0.999981f, 0.999986f, 0.999991f, 0.999997f}, + {0.991759f, 0.999829f, 0.99993f, 0.999949f, 0.999952f, 0.999964f, 0.99997f, 0.999957f, 0.999973f, 0.999978f, 0.999969f, 0.999965f, 0.999976f, 0.999972f, 0.999972f, 0.999975f} + }, + { + {0.837568f, 0.736764f, 0.709849f, 0.705015f, 0.710682f, 0.722521f, 0.737955f, 0.755885f, 0.775532f, 0.796539f, 0.817642f, 0.839382f, 0.861295f, 0.883276f, 0.90439f, 0.923577f}, + {0.851897f, 0.758842f, 0.734871f, 0.73241f, 0.739817f, 0.753067f, 0.769543f, 0.787812f, 0.807201f, 0.827387f, 0.847468f, 0.867395f, 0.887248f, 0.905785f, 0.92365f, 0.939144f}, + {0.866683f, 0.782236f, 0.762028f, 0.761779f, 0.771356f, 0.785082f, 0.802074f, 0.820286f, 0.839085f, 0.857472f, 0.875618f, 0.893432f, 0.909954f, 0.925939f, 0.940416f, 0.953019f}, + {0.881964f, 0.80704f, 0.7908f, 0.792982f, 0.803513f, 0.81806f, 0.834788f, 0.851956f, 0.868991f, 0.886045f, 0.901641f, 0.916558f, 0.930315f, 0.943545f, 0.954579f, 0.964278f}, + {0.89721f, 0.832614f, 0.820307f, 0.824408f, 0.835767f, 0.850102f, 0.865923f, 0.881883f, 0.896692f, 0.911183f, 0.924448f, 0.936468f, 0.947692f, 0.957893f, 0.966472f, 0.97384f}, + {0.91236f, 0.858027f, 0.849325f, 0.855072f, 0.866327f, 0.880159f, 0.894367f, 0.908095f, 0.921258f, 0.932981f, 0.943819f, 0.953623f, 0.962047f, 0.969655f, 0.976175f, 0.981335f}, + {0.926661f, 0.881858f, 0.876134f, 0.882654f, 0.893459f, 0.906491f, 0.919034f, 0.930944f, 0.941911f, 0.951492f, 0.960017f, 0.967281f, 0.973553f, 0.979014f, 0.983618f, 0.987414f}, + {0.939432f, 0.902195f, 0.898327f, 0.905337f, 0.916347f, 0.928334f, 0.939728f, 0.950069f, 0.958818f, 0.966544f, 0.97279f, 0.978102f, 0.982752f, 0.986367f, 0.989486f, 0.991995f}, + {0.94915f, 0.916778f, 0.914804f, 0.923318f, 0.934978f, 0.946658f, 0.957017f, 0.965635f, 0.972581f, 0.978128f, 0.98279f, 0.986356f, 0.989299f, 0.991747f, 0.993668f, 0.995274f}, + {0.954756f, 0.924187f, 0.925547f, 0.937439f, 0.950997f, 0.962317f, 0.971588f, 0.978375f, 0.983398f, 0.987116f, 0.99004f, 0.992146f, 0.993989f, 0.995358f, 0.996568f, 0.997328f}, + {0.954147f, 0.925019f, 0.934841f, 0.952223f, 0.966499f, 0.976747f, 0.983714f, 0.988143f, 0.991088f, 0.993349f, 0.994842f, 0.996048f, 0.99692f, 0.997617f, 0.998236f, 0.998646f}, + {0.946214f, 0.925955f, 0.94916f, 0.969447f, 0.981469f, 0.988432f, 0.992094f, 0.994611f, 0.995991f, 0.99696f, 0.997723f, 0.998246f, 0.998684f, 0.999001f, 0.99924f, 0.999398f}, + {0.932942f, 0.939385f, 0.971199f, 0.986025f, 0.99254f, 0.995547f, 0.997144f, 0.998025f, 0.998559f, 0.998917f, 0.999172f, 0.999366f, 0.999509f, 0.999617f, 0.999716f, 0.99978f}, + {0.928768f, 0.970817f, 0.990749f, 0.996191f, 0.998091f, 0.998875f, 0.999269f, 0.999488f, 0.999653f, 0.99972f, 0.999775f, 0.999821f, 0.999874f, 0.999901f, 0.99993f, 0.999951f}, + {0.955373f, 0.994929f, 0.998696f, 0.999463f, 0.999746f, 0.999838f, 0.999911f, 0.999931f, 0.999944f, 0.999957f, 0.999974f, 0.999975f, 0.99998f, 0.999981f, 0.99999f, 0.999995f}, + {0.991732f, 0.999822f, 0.999925f, 0.999948f, 0.999952f, 0.999963f, 0.99997f, 0.999956f, 0.999973f, 0.999978f, 0.999969f, 0.999965f, 0.999976f, 0.999972f, 0.999972f, 0.999975f} + }, + { + {0.85191f, 0.752165f, 0.721625f, 0.713215f, 0.715498f, 0.724355f, 0.737179f, 0.752576f, 0.77016f, 0.788946f, 0.808239f, 0.828107f, 0.84855f, 0.868878f, 0.88846f, 0.906357f}, + {0.865727f, 0.774365f, 0.747303f, 0.741452f, 0.745659f, 0.755961f, 0.76993f, 0.785771f, 0.803074f, 0.82141f, 0.839566f, 0.857874f, 0.876447f, 0.893873f, 0.910485f, 0.92501f}, + {0.879868f, 0.797708f, 0.774755f, 0.771317f, 0.777804f, 0.788724f, 0.803228f, 0.8192f, 0.836097f, 0.852658f, 0.869432f, 0.885904f, 0.901257f, 0.916297f, 0.929892f, 0.941638f}, + {0.894244f, 0.821913f, 0.803222f, 0.802407f, 0.810018f, 0.8219f, 0.836243f, 0.851391f, 0.866821f, 0.882399f, 0.89684f, 0.91055f, 0.923487f, 0.935716f, 0.946383f, 0.955528f}, + {0.908373f, 0.846412f, 0.831867f, 0.833086f, 0.841702f, 0.853661f, 0.867427f, 0.881556f, 0.894904f, 0.908275f, 0.920452f, 0.931773f, 0.942417f, 0.952063f, 0.960263f, 0.967193f}, + {0.92214f, 0.870102f, 0.859242f, 0.862387f, 0.871067f, 0.882995f, 0.895399f, 0.90759f, 0.919726f, 0.930629f, 0.940753f, 0.950036f, 0.958083f, 0.965459f, 0.971662f, 0.976646f}, + {0.934798f, 0.891635f, 0.883776f, 0.887833f, 0.89659f, 0.90792f, 0.919242f, 0.93025f, 0.940464f, 0.949541f, 0.957803f, 0.964716f, 0.970839f, 0.976081f, 0.980542f, 0.984205f}, + {0.945751f, 0.909202f, 0.903245f, 0.908314f, 0.917707f, 0.928643f, 0.939202f, 0.949014f, 0.95737f, 0.965008f, 0.971122f, 0.976303f, 0.980901f, 0.984408f, 0.98755f, 0.989931f}, + {0.953568f, 0.920956f, 0.917039f, 0.92407f, 0.934846f, 0.946049f, 0.956046f, 0.964541f, 0.97153f, 0.977085f, 0.981669f, 0.985233f, 0.988217f, 0.990532f, 0.992517f, 0.994095f}, + {0.95738f, 0.925791f, 0.925588f, 0.936673f, 0.949962f, 0.961212f, 0.970718f, 0.977523f, 0.98271f, 0.986362f, 0.989429f, 0.991495f, 0.993414f, 0.994776f, 0.995943f, 0.996728f}, + {0.955269f, 0.924717f, 0.933603f, 0.950835f, 0.965321f, 0.975741f, 0.983004f, 0.987605f, 0.990657f, 0.993001f, 0.994559f, 0.995741f, 0.99661f, 0.997318f, 0.997923f, 0.998364f}, + {0.946206f, 0.924639f, 0.947637f, 0.968275f, 0.980654f, 0.987918f, 0.991721f, 0.994359f, 0.995761f, 0.996839f, 0.997585f, 0.998139f, 0.998558f, 0.998847f, 0.999114f, 0.999243f}, + {0.93236f, 0.938071f, 0.970254f, 0.985425f, 0.992197f, 0.995335f, 0.997029f, 0.997938f, 0.998507f, 0.998883f, 0.999142f, 0.999319f, 0.999465f, 0.999566f, 0.999677f, 0.999732f}, + {0.928146f, 0.970182f, 0.990407f, 0.996019f, 0.997988f, 0.998821f, 0.99923f, 0.999469f, 0.99964f, 0.999708f, 0.999764f, 0.999811f, 0.999852f, 0.999895f, 0.999915f, 0.999942f}, + {0.955102f, 0.994825f, 0.998663f, 0.999436f, 0.999734f, 0.999831f, 0.99991f, 0.999931f, 0.999941f, 0.999956f, 0.999968f, 0.999977f, 0.999979f, 0.999978f, 0.999989f, 0.999994f}, + {0.991717f, 0.999819f, 0.999924f, 0.999948f, 0.999952f, 0.999963f, 0.99997f, 0.999956f, 0.999973f, 0.999978f, 0.999969f, 0.999965f, 0.999976f, 0.999972f, 0.999972f, 0.999975f} + }, + { + {0.862765f, 0.764131f, 0.730767f, 0.71916f, 0.718559f, 0.724679f, 0.734864f, 0.747932f, 0.763527f, 0.780125f, 0.797611f, 0.815649f, 0.834437f, 0.853295f, 0.871492f, 0.888073f}, + {0.876161f, 0.786441f, 0.7568f, 0.748214f, 0.749576f, 0.757164f, 0.768726f, 0.782487f, 0.797808f, 0.814241f, 0.830614f, 0.847528f, 0.864641f, 0.880858f, 0.896205f, 0.909985f}, + {0.889704f, 0.809539f, 0.784458f, 0.77839f, 0.78223f, 0.790624f, 0.802965f, 0.816864f, 0.831972f, 0.846996f, 0.862222f, 0.87733f, 0.891487f, 0.905617f, 0.918321f, 0.9293f}, + {0.903333f, 0.833197f, 0.812552f, 0.809429f, 0.81449f, 0.824023f, 0.836431f, 0.849617f, 0.863587f, 0.877736f, 0.890918f, 0.903733f, 0.915767f, 0.927275f, 0.937303f, 0.945977f}, + {0.916547f, 0.856672f, 0.840394f, 0.839349f, 0.845756f, 0.855676f, 0.867619f, 0.880224f, 0.892195f, 0.904545f, 0.915742f, 0.926409f, 0.936397f, 0.94549f, 0.953309f, 0.960093f}, + {0.929187f, 0.878868f, 0.866405f, 0.867496f, 0.874109f, 0.884379f, 0.895274f, 0.906445f, 0.917646f, 0.927798f, 0.937218f, 0.945975f, 0.953684f, 0.960716f, 0.966682f, 0.971462f}, + {0.940571f, 0.898566f, 0.889132f, 0.891334f, 0.898481f, 0.908476f, 0.918869f, 0.929053f, 0.938655f, 0.947249f, 0.955117f, 0.961841f, 0.967646f, 0.972712f, 0.977213f, 0.980699f}, + {0.950149f, 0.914091f, 0.906597f, 0.910123f, 0.918333f, 0.928365f, 0.938377f, 0.947729f, 0.955746f, 0.963175f, 0.969199f, 0.974311f, 0.978849f, 0.982284f, 0.98537f, 0.987785f}, + {0.956598f, 0.923775f, 0.918477f, 0.924327f, 0.93444f, 0.945162f, 0.95504f, 0.963363f, 0.970294f, 0.975916f, 0.980461f, 0.983947f, 0.986924f, 0.989259f, 0.991279f, 0.992857f}, + {0.959154f, 0.926795f, 0.925535f, 0.935964f, 0.94903f, 0.960231f, 0.969742f, 0.976657f, 0.981907f, 0.985621f, 0.988734f, 0.990863f, 0.992689f, 0.994138f, 0.995236f, 0.996008f}, + {0.955995f, 0.924468f, 0.932689f, 0.94973f, 0.964333f, 0.974929f, 0.982326f, 0.98703f, 0.990202f, 0.992629f, 0.994181f, 0.995418f, 0.996343f, 0.996968f, 0.997568f, 0.997996f}, + {0.946252f, 0.923783f, 0.946605f, 0.967366f, 0.97998f, 0.987421f, 0.991385f, 0.994093f, 0.995561f, 0.996672f, 0.997433f, 0.998012f, 0.998422f, 0.998715f, 0.998984f, 0.999102f}, + {0.932012f, 0.937248f, 0.969594f, 0.984982f, 0.991926f, 0.995169f, 0.996916f, 0.997861f, 0.998446f, 0.998839f, 0.999085f, 0.999278f, 0.999434f, 0.999522f, 0.999622f, 0.999682f}, + {0.92778f, 0.969808f, 0.990195f, 0.995894f, 0.997922f, 0.998769f, 0.999198f, 0.999453f, 0.999629f, 0.999694f, 0.999755f, 0.999796f, 0.999837f, 0.999883f, 0.999902f, 0.999933f}, + {0.954945f, 0.994752f, 0.99863f, 0.999412f, 0.999724f, 0.999824f, 0.999909f, 0.999931f, 0.999941f, 0.999956f, 0.999967f, 0.999976f, 0.999978f, 0.999976f, 0.999985f, 0.999991f}, + {0.991706f, 0.999817f, 0.999923f, 0.999948f, 0.999952f, 0.999963f, 0.99997f, 0.999956f, 0.999973f, 0.999978f, 0.999969f, 0.999965f, 0.999976f, 0.999972f, 0.999972f, 0.999974f} + }, + { + {0.87117f, 0.773478f, 0.737746f, 0.723257f, 0.72006f, 0.723647f, 0.73159f, 0.742279f, 0.755881f, 0.77029f, 0.786075f, 0.802347f, 0.819384f, 0.836806f, 0.853569f, 0.869326f}, + {0.884158f, 0.795796f, 0.764103f, 0.752993f, 0.751808f, 0.757047f, 0.766419f, 0.778018f, 0.791387f, 0.806107f, 0.820874f, 0.836148f, 0.851992f, 0.867051f, 0.881087f, 0.894105f}, + {0.897193f, 0.818653f, 0.791824f, 0.783455f, 0.784951f, 0.791205f, 0.801575f, 0.813517f, 0.826859f, 0.840245f, 0.854066f, 0.867971f, 0.881108f, 0.894085f, 0.905971f, 0.916447f}, + {0.910219f, 0.841752f, 0.819608f, 0.814407f, 0.817329f, 0.824996f, 0.835448f, 0.846951f, 0.85955f, 0.872219f, 0.884421f, 0.896327f, 0.907341f, 0.918095f, 0.927445f, 0.935841f}, + {0.922657f, 0.864426f, 0.846726f, 0.843736f, 0.848332f, 0.8565f, 0.866924f, 0.878112f, 0.888836f, 0.900162f, 0.910612f, 0.920476f, 0.929843f, 0.93849f, 0.945881f, 0.952372f}, + {0.934391f, 0.885423f, 0.871598f, 0.870985f, 0.875979f, 0.884842f, 0.894438f, 0.904629f, 0.914874f, 0.924299f, 0.933131f, 0.94145f, 0.948769f, 0.955549f, 0.961276f, 0.965885f}, + {0.944813f, 0.903683f, 0.892907f, 0.893655f, 0.899506f, 0.908364f, 0.917845f, 0.927402f, 0.936392f, 0.944634f, 0.952183f, 0.958657f, 0.964227f, 0.969092f, 0.973609f, 0.976964f}, + {0.953322f, 0.917611f, 0.908865f, 0.911234f, 0.918508f, 0.927746f, 0.937292f, 0.946151f, 0.954015f, 0.961192f, 0.967056f, 0.972082f, 0.97663f, 0.979991f, 0.982995f, 0.985403f}, + {0.958765f, 0.92578f, 0.919436f, 0.924414f, 0.933929f, 0.944303f, 0.953903f, 0.962076f, 0.968977f, 0.97452f, 0.979117f, 0.982571f, 0.985534f, 0.987818f, 0.989918f, 0.991516f}, + {0.960459f, 0.927539f, 0.925494f, 0.93535f, 0.948172f, 0.95928f, 0.968789f, 0.975776f, 0.980982f, 0.984789f, 0.987955f, 0.990108f, 0.991955f, 0.993384f, 0.994493f, 0.995297f}, + {0.956553f, 0.924392f, 0.932135f, 0.948955f, 0.963575f, 0.974228f, 0.981718f, 0.986488f, 0.989738f, 0.992198f, 0.993817f, 0.995048f, 0.996016f, 0.996585f, 0.997211f, 0.997639f}, + {0.946362f, 0.923322f, 0.945985f, 0.966732f, 0.979478f, 0.987009f, 0.991067f, 0.993829f, 0.995364f, 0.996483f, 0.997253f, 0.997861f, 0.998278f, 0.998575f, 0.998839f, 0.998956f}, + {0.931879f, 0.936811f, 0.969181f, 0.984665f, 0.991706f, 0.995039f, 0.996801f, 0.997769f, 0.998383f, 0.998789f, 0.99904f, 0.999225f, 0.99938f, 0.999481f, 0.999566f, 0.999629f}, + {0.927626f, 0.969587f, 0.990047f, 0.995803f, 0.997869f, 0.998725f, 0.99917f, 0.999432f, 0.999612f, 0.999677f, 0.999743f, 0.999784f, 0.99983f, 0.999869f, 0.999892f, 0.999909f}, + {0.954886f, 0.994722f, 0.998604f, 0.999405f, 0.999718f, 0.999819f, 0.999901f, 0.999927f, 0.99994f, 0.999955f, 0.999963f, 0.999973f, 0.999975f, 0.999975f, 0.999984f, 0.999989f}, + {0.991701f, 0.999816f, 0.999923f, 0.999948f, 0.999952f, 0.999962f, 0.99997f, 0.999956f, 0.999973f, 0.999978f, 0.999969f, 0.999966f, 0.999976f, 0.999972f, 0.999971f, 0.999974f} + }, + { + {0.877747f, 0.780883f, 0.742996f, 0.725979f, 0.720276f, 0.721584f, 0.727147f, 0.73577f, 0.74746f, 0.759975f, 0.773773f, 0.78838f, 0.803892f, 0.819738f, 0.835206f, 0.849861f}, + {0.890437f, 0.803154f, 0.769619f, 0.756273f, 0.752772f, 0.75586f, 0.763174f, 0.772737f, 0.784325f, 0.797186f, 0.810509f, 0.82418f, 0.838674f, 0.852726f, 0.865502f, 0.877691f}, + {0.903016f, 0.825754f, 0.797396f, 0.786968f, 0.7864f, 0.790698f, 0.799182f, 0.809329f, 0.820902f, 0.832886f, 0.845313f, 0.858026f, 0.869922f, 0.881835f, 0.893135f, 0.902931f}, + {0.915517f, 0.848335f, 0.824852f, 0.817858f, 0.818912f, 0.824792f, 0.833618f, 0.843552f, 0.854758f, 0.86613f, 0.877177f, 0.888174f, 0.89831f, 0.908404f, 0.917352f, 0.925143f}, + {0.927334f, 0.870321f, 0.851424f, 0.846779f, 0.849725f, 0.856368f, 0.865377f, 0.875324f, 0.88497f, 0.895235f, 0.905f, 0.914069f, 0.922817f, 0.931072f, 0.938056f, 0.944178f}, + {0.938346f, 0.890327f, 0.875427f, 0.873281f, 0.876998f, 0.884557f, 0.893063f, 0.9022f, 0.911707f, 0.920452f, 0.928671f, 0.936515f, 0.943604f, 0.949998f, 0.955491f, 0.959952f}, + {0.947986f, 0.907455f, 0.895621f, 0.895174f, 0.899899f, 0.907895f, 0.916439f, 0.925357f, 0.933864f, 0.941756f, 0.948879f, 0.955232f, 0.960495f, 0.965329f, 0.96974f, 0.972912f}, + {0.955697f, 0.920194f, 0.910511f, 0.911946f, 0.918341f, 0.926907f, 0.936032f, 0.94445f, 0.952065f, 0.95907f, 0.964801f, 0.969697f, 0.974137f, 0.977583f, 0.980525f, 0.982781f}, + {0.960396f, 0.927293f, 0.92013f, 0.924394f, 0.933401f, 0.943429f, 0.952746f, 0.960788f, 0.967585f, 0.973104f, 0.977618f, 0.981119f, 0.984027f, 0.986349f, 0.988453f, 0.989993f}, + {0.961426f, 0.928168f, 0.925529f, 0.934943f, 0.947474f, 0.958464f, 0.967918f, 0.974878f, 0.980124f, 0.983917f, 0.987153f, 0.989318f, 0.991151f, 0.992612f, 0.99371f, 0.994486f}, + {0.957033f, 0.924479f, 0.931826f, 0.948434f, 0.962967f, 0.973631f, 0.981151f, 0.985945f, 0.989286f, 0.991776f, 0.993382f, 0.994624f, 0.995601f, 0.996179f, 0.996832f, 0.997288f}, + {0.946532f, 0.923184f, 0.945647f, 0.966362f, 0.979097f, 0.986728f, 0.990816f, 0.993564f, 0.995129f, 0.996286f, 0.997077f, 0.997686f, 0.998115f, 0.998438f, 0.998684f, 0.998786f}, + {0.931906f, 0.936671f, 0.968964f, 0.984479f, 0.991552f, 0.994907f, 0.996694f, 0.997677f, 0.998291f, 0.998723f, 0.998984f, 0.999165f, 0.99933f, 0.999433f, 0.999522f, 0.99958f}, + {0.927624f, 0.969526f, 0.989973f, 0.995746f, 0.997823f, 0.998688f, 0.999141f, 0.999415f, 0.999588f, 0.999669f, 0.999731f, 0.999762f, 0.999818f, 0.999851f, 0.999879f, 0.999897f}, + {0.954887f, 0.994707f, 0.998592f, 0.999394f, 0.999713f, 0.999817f, 0.999897f, 0.999924f, 0.999939f, 0.999954f, 0.999962f, 0.999971f, 0.999976f, 0.999973f, 0.999982f, 0.999988f}, + {0.991702f, 0.999815f, 0.999923f, 0.999947f, 0.999952f, 0.999962f, 0.99997f, 0.999956f, 0.999973f, 0.999978f, 0.999969f, 0.999966f, 0.999976f, 0.999972f, 0.999971f, 0.999974f} + }, + { + {0.882977f, 0.78669f, 0.746894f, 0.727572f, 0.719627f, 0.718709f, 0.722092f, 0.728754f, 0.738316f, 0.749029f, 0.761128f, 0.774097f, 0.787947f, 0.802312f, 0.816624f, 0.830502f}, + {0.895358f, 0.808916f, 0.773799f, 0.7584f, 0.752786f, 0.753903f, 0.759079f, 0.766832f, 0.776629f, 0.787813f, 0.799613f, 0.811772f, 0.824958f, 0.83777f, 0.849522f, 0.860857f}, + {0.907601f, 0.83135f, 0.801585f, 0.789286f, 0.786795f, 0.789243f, 0.795902f, 0.804415f, 0.814463f, 0.825046f, 0.836104f, 0.847556f, 0.858515f, 0.869251f, 0.879759f, 0.88891f}, + {0.919673f, 0.853465f, 0.828784f, 0.820179f, 0.819573f, 0.823793f, 0.831027f, 0.83955f, 0.849394f, 0.859493f, 0.869622f, 0.879553f, 0.888914f, 0.898326f, 0.906568f, 0.914022f}, + {0.930956f, 0.874844f, 0.854905f, 0.848788f, 0.85031f, 0.855533f, 0.863259f, 0.871986f, 0.880561f, 0.889948f, 0.898834f, 0.907374f, 0.915474f, 0.923353f, 0.929711f, 0.935547f}, + {0.941411f, 0.89408f, 0.87826f, 0.874849f, 0.877281f, 0.883697f, 0.891194f, 0.89953f, 0.90819f, 0.916301f, 0.923914f, 0.931342f, 0.938026f, 0.944281f, 0.949469f, 0.953744f}, + {0.950435f, 0.910324f, 0.897619f, 0.896182f, 0.899914f, 0.906985f, 0.914796f, 0.923094f, 0.931078f, 0.938664f, 0.94546f, 0.951465f, 0.956487f, 0.961276f, 0.965436f, 0.968771f}, + {0.957518f, 0.922155f, 0.911715f, 0.912334f, 0.918047f, 0.92595f, 0.934652f, 0.942688f, 0.949951f, 0.95679f, 0.962383f, 0.967156f, 0.971493f, 0.974836f, 0.977894f, 0.980128f}, + {0.961658f, 0.928481f, 0.920719f, 0.924333f, 0.932857f, 0.942504f, 0.951604f, 0.959438f, 0.966116f, 0.971594f, 0.976043f, 0.979541f, 0.98248f, 0.984776f, 0.986909f, 0.988461f}, + {0.962219f, 0.928767f, 0.925655f, 0.934658f, 0.946905f, 0.957694f, 0.967021f, 0.973998f, 0.979208f, 0.983029f, 0.986244f, 0.988426f, 0.990309f, 0.991799f, 0.992883f, 0.993719f}, + {0.957482f, 0.924727f, 0.931764f, 0.948101f, 0.962494f, 0.973132f, 0.980627f, 0.985422f, 0.988838f, 0.991293f, 0.992952f, 0.994155f, 0.995162f, 0.995793f, 0.996428f, 0.996872f}, + {0.946771f, 0.923294f, 0.945555f, 0.96612f, 0.978828f, 0.986438f, 0.990567f, 0.993354f, 0.994904f, 0.99609f, 0.99689f, 0.997514f, 0.997931f, 0.998266f, 0.998509f, 0.998636f}, + {0.932051f, 0.936765f, 0.968918f, 0.984371f, 0.991426f, 0.994804f, 0.996598f, 0.997592f, 0.998227f, 0.998646f, 0.998923f, 0.999101f, 0.999271f, 0.999381f, 0.999454f, 0.999517f}, + {0.927743f, 0.969565f, 0.98996f, 0.995715f, 0.997791f, 0.998656f, 0.999114f, 0.999399f, 0.999573f, 0.999649f, 0.999718f, 0.999748f, 0.999803f, 0.999836f, 0.999861f, 0.999883f}, + {0.954938f, 0.99471f, 0.99859f, 0.99939f, 0.999708f, 0.999814f, 0.999894f, 0.999923f, 0.999937f, 0.999951f, 0.999959f, 0.999968f, 0.999973f, 0.999971f, 0.999978f, 0.999984f}, + {0.991707f, 0.999816f, 0.999923f, 0.999947f, 0.999951f, 0.999962f, 0.99997f, 0.999956f, 0.999973f, 0.999978f, 0.999969f, 0.999966f, 0.999976f, 0.999972f, 0.999971f, 0.999974f} + }, + { + {0.88718f, 0.791265f, 0.749686f, 0.728275f, 0.718228f, 0.715162f, 0.716462f, 0.721278f, 0.728961f, 0.737937f, 0.748332f, 0.759736f, 0.771954f, 0.784898f, 0.797953f, 0.810917f}, + {0.899343f, 0.813459f, 0.776874f, 0.759595f, 0.751982f, 0.751167f, 0.754454f, 0.760382f, 0.768506f, 0.778075f, 0.788391f, 0.799165f, 0.810982f, 0.82258f, 0.833486f, 0.843918f}, + {0.911236f, 0.835741f, 0.804707f, 0.790707f, 0.786512f, 0.787057f, 0.792158f, 0.798957f, 0.807525f, 0.81683f, 0.82656f, 0.836814f, 0.846637f, 0.856566f, 0.866175f, 0.874829f}, + {0.922975f, 0.857485f, 0.831744f, 0.821637f, 0.819443f, 0.822148f, 0.82795f, 0.83509f, 0.843705f, 0.852616f, 0.861632f, 0.87066f, 0.879052f, 0.887896f, 0.895586f, 0.902597f}, + {0.933824f, 0.878354f, 0.857478f, 0.850105f, 0.850241f, 0.854179f, 0.860704f, 0.868262f, 0.875808f, 0.884313f, 0.892511f, 0.900266f, 0.907834f, 0.915249f, 0.921143f, 0.926654f}, + {0.943829f, 0.897002f, 0.880335f, 0.87583f, 0.877105f, 0.882524f, 0.889055f, 0.896473f, 0.904396f, 0.911913f, 0.918998f, 0.925969f, 0.932316f, 0.938166f, 0.943144f, 0.947488f}, + {0.95235f, 0.912517f, 0.899088f, 0.896743f, 0.899543f, 0.90584f, 0.91296f, 0.920684f, 0.928102f, 0.935284f, 0.941791f, 0.947552f, 0.952356f, 0.956925f, 0.961032f, 0.964383f}, + {0.958953f, 0.923707f, 0.912614f, 0.912528f, 0.917563f, 0.924883f, 0.933114f, 0.940735f, 0.947724f, 0.95444f, 0.959839f, 0.964442f, 0.968741f, 0.972099f, 0.97511f, 0.977389f}, + {0.962657f, 0.929478f, 0.92119f, 0.924276f, 0.932297f, 0.941605f, 0.95047f, 0.958f, 0.964579f, 0.969996f, 0.974393f, 0.977923f, 0.980772f, 0.983108f, 0.985188f, 0.986875f}, + {0.96288f, 0.929335f, 0.925846f, 0.93448f, 0.946391f, 0.956989f, 0.966176f, 0.973082f, 0.978247f, 0.982056f, 0.98529f, 0.987511f, 0.989395f, 0.990923f, 0.992051f, 0.992859f}, + {0.957907f, 0.925126f, 0.931868f, 0.947943f, 0.962145f, 0.972694f, 0.980115f, 0.984894f, 0.988325f, 0.990804f, 0.992483f, 0.993697f, 0.994771f, 0.995353f, 0.996007f, 0.996485f}, + {0.947059f, 0.923637f, 0.945659f, 0.966036f, 0.978634f, 0.986174f, 0.990319f, 0.993109f, 0.99469f, 0.995891f, 0.996685f, 0.997324f, 0.997742f, 0.998093f, 0.998319f, 0.99846f}, + {0.932316f, 0.937019f, 0.968993f, 0.98433f, 0.991339f, 0.994711f, 0.996512f, 0.997512f, 0.998152f, 0.998564f, 0.998851f, 0.999032f, 0.999202f, 0.999314f, 0.999398f, 0.999459f}, + {0.927979f, 0.969703f, 0.989979f, 0.995709f, 0.997768f, 0.998636f, 0.999094f, 0.999377f, 0.999553f, 0.999636f, 0.999704f, 0.999729f, 0.999786f, 0.999821f, 0.999844f, 0.999872f}, + {0.955042f, 0.994732f, 0.998592f, 0.999391f, 0.999705f, 0.999812f, 0.999893f, 0.999918f, 0.999934f, 0.99995f, 0.999956f, 0.999966f, 0.999973f, 0.999969f, 0.999977f, 0.999983f}, + {0.991714f, 0.999817f, 0.999923f, 0.999947f, 0.999951f, 0.999962f, 0.999969f, 0.999956f, 0.999973f, 0.999978f, 0.999969f, 0.999966f, 0.999976f, 0.999972f, 0.999971f, 0.999974f} + }, + { + {0.890624f, 0.794913f, 0.751595f, 0.728315f, 0.716165f, 0.711259f, 0.710489f, 0.713487f, 0.719264f, 0.72661f, 0.735377f, 0.745399f, 0.755902f, 0.767561f, 0.779444f, 0.791432f}, + {0.902561f, 0.817053f, 0.779069f, 0.759979f, 0.750559f, 0.747973f, 0.749392f, 0.753796f, 0.760216f, 0.768113f, 0.776937f, 0.786565f, 0.797039f, 0.80733f, 0.817108f, 0.826796f}, + {0.914196f, 0.839209f, 0.806955f, 0.791422f, 0.785544f, 0.784497f, 0.787997f, 0.793195f, 0.800421f, 0.808331f, 0.816868f, 0.826063f, 0.83466f, 0.843702f, 0.852359f, 0.860494f}, + {0.925655f, 0.860665f, 0.83391f, 0.822388f, 0.818834f, 0.820022f, 0.824499f, 0.830276f, 0.837635f, 0.845529f, 0.853455f, 0.861507f, 0.869202f, 0.877202f, 0.884398f, 0.891023f}, + {0.936108f, 0.881133f, 0.85936f, 0.850771f, 0.849623f, 0.852478f, 0.857742f, 0.864299f, 0.870899f, 0.878544f, 0.8859f, 0.893041f, 0.900033f, 0.906907f, 0.91244f, 0.917751f}, + {0.945738f, 0.899317f, 0.881803f, 0.876366f, 0.876596f, 0.880928f, 0.886643f, 0.893232f, 0.90038f, 0.907277f, 0.913822f, 0.920371f, 0.926364f, 0.931915f, 0.936756f, 0.94087f}, + {0.953892f, 0.914299f, 0.900195f, 0.897005f, 0.89897f, 0.904506f, 0.910921f, 0.918114f, 0.92501f, 0.931694f, 0.937925f, 0.943503f, 0.94808f, 0.952466f, 0.956531f, 0.959867f}, + {0.960106f, 0.924951f, 0.913294f, 0.912564f, 0.917012f, 0.923719f, 0.931536f, 0.93876f, 0.94542f, 0.951927f, 0.957144f, 0.961631f, 0.965882f, 0.969256f, 0.972213f, 0.974584f}, + {0.963489f, 0.930305f, 0.92158f, 0.924196f, 0.931797f, 0.940695f, 0.949222f, 0.956532f, 0.963004f, 0.968356f, 0.972664f, 0.976165f, 0.979009f, 0.981425f, 0.983548f, 0.985218f}, + {0.963473f, 0.92992f, 0.926131f, 0.93442f, 0.946014f, 0.956334f, 0.965333f, 0.972178f, 0.977249f, 0.981065f, 0.984335f, 0.986485f, 0.9884f, 0.98998f, 0.991134f, 0.991982f}, + {0.958326f, 0.925614f, 0.93211f, 0.947913f, 0.961902f, 0.972276f, 0.979642f, 0.984396f, 0.987816f, 0.990302f, 0.992003f, 0.993238f, 0.99431f, 0.994931f, 0.995598f, 0.996026f}, + {0.947422f, 0.924138f, 0.945912f, 0.966055f, 0.978472f, 0.985964f, 0.990089f, 0.992852f, 0.99445f, 0.995661f, 0.9965f, 0.997122f, 0.99754f, 0.997916f, 0.998136f, 0.998282f}, + {0.932675f, 0.937446f, 0.969148f, 0.984324f, 0.9913f, 0.994631f, 0.996427f, 0.997433f, 0.998081f, 0.998488f, 0.998776f, 0.998951f, 0.99912f, 0.999257f, 0.999339f, 0.9994f}, + {0.928284f, 0.969893f, 0.990039f, 0.995709f, 0.997756f, 0.998618f, 0.999072f, 0.999362f, 0.999535f, 0.999619f, 0.999689f, 0.999712f, 0.999778f, 0.999807f, 0.99983f, 0.999854f}, + {0.955178f, 0.994767f, 0.998607f, 0.999394f, 0.9997f, 0.999809f, 0.999889f, 0.999916f, 0.999933f, 0.999949f, 0.999952f, 0.999963f, 0.999969f, 0.999967f, 0.999977f, 0.999982f}, + {0.991724f, 0.999818f, 0.999923f, 0.999947f, 0.999951f, 0.999962f, 0.999969f, 0.999955f, 0.999973f, 0.999978f, 0.999969f, 0.999966f, 0.999976f, 0.999971f, 0.999971f, 0.999974f} + }, + { + {0.893434f, 0.797814f, 0.752922f, 0.727812f, 0.713735f, 0.706931f, 0.704372f, 0.705642f, 0.709603f, 0.715397f, 0.722403f, 0.731039f, 0.739981f, 0.750329f, 0.761289f, 0.772331f}, + {0.905203f, 0.819884f, 0.780557f, 0.759869f, 0.748764f, 0.74445f, 0.744254f, 0.74695f, 0.751782f, 0.758117f, 0.765638f, 0.773848f, 0.783125f, 0.79231f, 0.801129f, 0.810013f}, + {0.916605f, 0.841987f, 0.808558f, 0.791604f, 0.78415f, 0.781576f, 0.783488f, 0.787291f, 0.793066f, 0.79974f, 0.807069f, 0.815146f, 0.822749f, 0.830759f, 0.838712f, 0.846306f}, + {0.927836f, 0.863206f, 0.835518f, 0.822659f, 0.817761f, 0.81748f, 0.820596f, 0.825366f, 0.831471f, 0.838282f, 0.845202f, 0.852335f, 0.859172f, 0.866653f, 0.873016f, 0.879285f}, + {0.938008f, 0.883324f, 0.860708f, 0.850965f, 0.848699f, 0.850403f, 0.854568f, 0.86014f, 0.865852f, 0.872584f, 0.879233f, 0.885634f, 0.892101f, 0.898517f, 0.90361f, 0.908631f}, + {0.947304f, 0.901111f, 0.882892f, 0.876543f, 0.875772f, 0.879161f, 0.883957f, 0.889877f, 0.896303f, 0.902553f, 0.908637f, 0.91475f, 0.920323f, 0.925431f, 0.930243f, 0.934371f}, + {0.955132f, 0.915713f, 0.900974f, 0.896986f, 0.898208f, 0.903074f, 0.908749f, 0.915397f, 0.921827f, 0.928078f, 0.934038f, 0.939215f, 0.94377f, 0.947926f, 0.951965f, 0.955321f}, + {0.961061f, 0.925986f, 0.913823f, 0.912456f, 0.916355f, 0.9225f, 0.929826f, 0.936681f, 0.943031f, 0.94939f, 0.954417f, 0.958823f, 0.962909f, 0.96627f, 0.969289f, 0.971649f}, + {0.964207f, 0.931075f, 0.921945f, 0.924141f, 0.931276f, 0.939751f, 0.947996f, 0.955015f, 0.961373f, 0.96664f, 0.970834f, 0.974377f, 0.977259f, 0.979673f, 0.981779f, 0.983545f}, + {0.963978f, 0.930519f, 0.926508f, 0.934408f, 0.945704f, 0.955672f, 0.964484f, 0.971222f, 0.976174f, 0.980013f, 0.983308f, 0.985497f, 0.987412f, 0.989029f, 0.99017f, 0.991111f}, + {0.958762f, 0.926217f, 0.932511f, 0.94797f, 0.961684f, 0.971881f, 0.979163f, 0.983856f, 0.987279f, 0.989795f, 0.991492f, 0.992756f, 0.993819f, 0.994449f, 0.99516f, 0.995594f}, + {0.947832f, 0.924771f, 0.946249f, 0.966141f, 0.978386f, 0.985761f, 0.989856f, 0.992601f, 0.994222f, 0.995427f, 0.996276f, 0.996921f, 0.997338f, 0.997714f, 0.997952f, 0.998097f}, + {0.933114f, 0.93796f, 0.969371f, 0.984371f, 0.991257f, 0.994548f, 0.996345f, 0.997353f, 0.997996f, 0.998405f, 0.998696f, 0.998877f, 0.999051f, 0.999192f, 0.999279f, 0.999336f}, + {0.928676f, 0.970165f, 0.990118f, 0.995726f, 0.997746f, 0.998599f, 0.99905f, 0.999336f, 0.999517f, 0.999599f, 0.999669f, 0.999686f, 0.999762f, 0.999791f, 0.999811f, 0.999834f}, + {0.955348f, 0.994803f, 0.998615f, 0.999396f, 0.999697f, 0.999803f, 0.999889f, 0.999915f, 0.999931f, 0.999947f, 0.999949f, 0.999962f, 0.999966f, 0.999967f, 0.99997f, 0.999978f}, + {0.991734f, 0.999819f, 0.999923f, 0.999947f, 0.999951f, 0.999962f, 0.999969f, 0.999955f, 0.999973f, 0.999978f, 0.999969f, 0.999966f, 0.999976f, 0.999971f, 0.999971f, 0.999974f} + }, + { + {0.895766f, 0.800041f, 0.753664f, 0.726898f, 0.711004f, 0.702437f, 0.698171f, 0.697751f, 0.70003f, 0.704347f, 0.7097f, 0.716982f, 0.724742f, 0.733595f, 0.743427f, 0.753685f}, + {0.907349f, 0.822096f, 0.781567f, 0.75938f, 0.746575f, 0.74062f, 0.738894f, 0.73996f, 0.743312f, 0.748194f, 0.754427f, 0.761379f, 0.769242f, 0.777495f, 0.785436f, 0.793383f}, + {0.918598f, 0.844123f, 0.809641f, 0.791319f, 0.7824f, 0.77837f, 0.778798f, 0.781282f, 0.785739f, 0.791183f, 0.797331f, 0.804284f, 0.810899f, 0.817841f, 0.825218f, 0.832207f}, + {0.929631f, 0.865211f, 0.836575f, 0.822486f, 0.816343f, 0.814767f, 0.816643f, 0.820147f, 0.825207f, 0.831048f, 0.837014f, 0.843117f, 0.849265f, 0.855874f, 0.861713f, 0.86756f}, + {0.939552f, 0.885097f, 0.861661f, 0.850918f, 0.847426f, 0.848121f, 0.851277f, 0.855917f, 0.860636f, 0.86656f, 0.872519f, 0.878149f, 0.884097f, 0.890198f, 0.894954f, 0.899522f}, + {0.948613f, 0.902507f, 0.883647f, 0.876371f, 0.874718f, 0.877191f, 0.881224f, 0.886323f, 0.892109f, 0.897762f, 0.90331f, 0.90898f, 0.914114f, 0.919126f, 0.923574f, 0.927664f}, + {0.956161f, 0.916811f, 0.901554f, 0.89681f, 0.897271f, 0.901427f, 0.906562f, 0.91262f, 0.918545f, 0.924355f, 0.929955f, 0.935019f, 0.939407f, 0.943388f, 0.947411f, 0.950763f}, + {0.961875f, 0.926812f, 0.914214f, 0.912295f, 0.915596f, 0.921195f, 0.928058f, 0.93455f, 0.940557f, 0.946781f, 0.951559f, 0.955916f, 0.959969f, 0.963305f, 0.966318f, 0.96869f}, + {0.964815f, 0.931745f, 0.922315f, 0.924067f, 0.930668f, 0.938737f, 0.946705f, 0.953519f, 0.959637f, 0.964868f, 0.969074f, 0.972498f, 0.975442f, 0.977914f, 0.980016f, 0.981782f}, + {0.964467f, 0.931144f, 0.926877f, 0.934474f, 0.945292f, 0.955041f, 0.963646f, 0.970267f, 0.975109f, 0.978975f, 0.982244f, 0.984445f, 0.9864f, 0.988078f, 0.989237f, 0.990188f}, + {0.959202f, 0.926855f, 0.932978f, 0.948112f, 0.961503f, 0.97153f, 0.978656f, 0.983336f, 0.986739f, 0.989265f, 0.990959f, 0.992223f, 0.993323f, 0.993972f, 0.994708f, 0.995183f}, + {0.948301f, 0.925526f, 0.946736f, 0.966259f, 0.978299f, 0.985574f, 0.989635f, 0.992358f, 0.993987f, 0.995201f, 0.996059f, 0.996718f, 0.997147f, 0.997501f, 0.997776f, 0.997928f}, + {0.933641f, 0.938601f, 0.969659f, 0.984442f, 0.991226f, 0.994473f, 0.996258f, 0.997281f, 0.997916f, 0.998332f, 0.998633f, 0.998808f, 0.998971f, 0.999132f, 0.999212f, 0.999281f}, + {0.929114f, 0.970469f, 0.990208f, 0.995737f, 0.997744f, 0.99858f, 0.999031f, 0.999318f, 0.999502f, 0.99958f, 0.999644f, 0.999669f, 0.999741f, 0.999768f, 0.999797f, 0.999821f}, + {0.955539f, 0.994859f, 0.998629f, 0.999398f, 0.999695f, 0.999801f, 0.999885f, 0.999914f, 0.999925f, 0.999945f, 0.999946f, 0.999959f, 0.999961f, 0.999964f, 0.999968f, 0.999974f}, + {0.991748f, 0.99982f, 0.999924f, 0.999947f, 0.999951f, 0.999962f, 0.999969f, 0.999955f, 0.999973f, 0.999978f, 0.999969f, 0.999965f, 0.999976f, 0.999971f, 0.999971f, 0.999972f} + } +}; + +static const float table_ggx_glass_inv_E[16][16][16] = { + { + {0.467207f, 0.538927f, 0.574659f, 0.608772f, 0.642304f, 0.675257f, 0.707957f, 0.740158f, 0.771917f, 0.803155f, 0.83407f, 0.864431f, 0.894363f, 0.923674f, 0.952321f, 0.980283f}, + {0.464609f, 0.544532f, 0.584937f, 0.623371f, 0.660449f, 0.696496f, 0.731308f, 0.764927f, 0.797233f, 0.82808f, 0.85774f, 0.885719f, 0.912446f, 0.937796f, 0.96165f, 0.984053f}, + {0.461956f, 0.551493f, 0.597421f, 0.640579f, 0.681798f, 0.720813f, 0.757636f, 0.792069f, 0.824053f, 0.85368f, 0.881081f, 0.906327f, 0.929485f, 0.950494f, 0.969874f, 0.987302f}, + {0.45894f, 0.559813f, 0.612552f, 0.661377f, 0.706645f, 0.748464f, 0.786586f, 0.820906f, 0.851626f, 0.879155f, 0.903579f, 0.925338f, 0.944554f, 0.961512f, 0.976562f, 0.989744f}, + {0.456133f, 0.570329f, 0.631129f, 0.685976f, 0.73567f, 0.779491f, 0.817903f, 0.850987f, 0.879359f, 0.903643f, 0.924492f, 0.942345f, 0.957678f, 0.970785f, 0.982122f, 0.991754f}, + {0.453071f, 0.583454f, 0.65385f, 0.715586f, 0.768731f, 0.813542f, 0.850635f, 0.881055f, 0.905815f, 0.926283f, 0.943045f, 0.957066f, 0.968633f, 0.9783f, 0.986587f, 0.993419f}, + {0.451459f, 0.600348f, 0.681926f, 0.750265f, 0.805757f, 0.84933f, 0.883432f, 0.909636f, 0.929928f, 0.946092f, 0.958852f, 0.969084f, 0.977468f, 0.984297f, 0.990051f, 0.994624f}, + {0.451195f, 0.62222f, 0.716361f, 0.789977f, 0.845362f, 0.885478f, 0.914407f, 0.935464f, 0.950656f, 0.962478f, 0.971595f, 0.978785f, 0.984267f, 0.988836f, 0.992629f, 0.995593f}, + {0.454655f, 0.650514f, 0.757753f, 0.833856f, 0.8855f, 0.91928f, 0.941692f, 0.956897f, 0.967189f, 0.975121f, 0.981058f, 0.985686f, 0.9893f, 0.992086f, 0.99434f, 0.996262f}, + {0.466375f, 0.687794f, 0.805606f, 0.879126f, 0.922795f, 0.948203f, 0.963606f, 0.97338f, 0.979543f, 0.984405f, 0.98786f, 0.990528f, 0.992651f, 0.994388f, 0.995646f, 0.996643f}, + {0.494072f, 0.736034f, 0.857614f, 0.922007f, 0.954045f, 0.970447f, 0.979529f, 0.985027f, 0.987903f, 0.990558f, 0.992345f, 0.993723f, 0.994905f, 0.995714f, 0.996365f, 0.996948f}, + {0.54918f, 0.796767f, 0.91f, 0.957384f, 0.976739f, 0.985349f, 0.989745f, 0.992093f, 0.99292f, 0.994137f, 0.995029f, 0.995624f, 0.996217f, 0.996624f, 0.996871f, 0.997133f}, + {0.643871f, 0.870216f, 0.955899f, 0.981825f, 0.990287f, 0.993789f, 0.995402f, 0.996054f, 0.995607f, 0.99605f, 0.996438f, 0.996734f, 0.996834f, 0.997026f, 0.997038f, 0.997198f}, + {0.77505f, 0.944715f, 0.986041f, 0.994556f, 0.996691f, 0.99757f, 0.997928f, 0.997881f, 0.996692f, 0.996987f, 0.997098f, 0.997113f, 0.997145f, 0.997175f, 0.997226f, 0.997242f}, + {0.910815f, 0.989663f, 0.997687f, 0.998948f, 0.99884f, 0.998825f, 0.998798f, 0.998538f, 0.997143f, 0.997186f, 0.997289f, 0.997175f, 0.997165f, 0.997177f, 0.997328f, 0.99722f}, + {0.988773f, 0.999559f, 0.999684f, 0.999632f, 0.999128f, 0.998962f, 0.998883f, 0.998629f, 0.997223f, 0.997127f, 0.997255f, 0.997299f, 0.997234f, 0.997171f, 0.997179f, 0.997287f} + }, + + { + {0.331776f, 0.492473f, 0.54275f, 0.58052f, 0.615581f, 0.650102f, 0.683863f, 0.717645f, 0.750486f, 0.782911f, 0.814667f, 0.845786f, 0.876317f, 0.905953f, 0.934498f, 0.958563f}, + {0.322602f, 0.492259f, 0.548848f, 0.591202f, 0.629944f, 0.667743f, 0.704394f, 0.740062f, 0.774339f, 0.807034f, 0.838191f, 0.867899f, 0.895982f, 0.922349f, 0.947096f, 0.967158f}, + {0.313884f, 0.492341f, 0.556257f, 0.603478f, 0.646619f, 0.687837f, 0.727374f, 0.764869f, 0.799831f, 0.832292f, 0.862188f, 0.889588f, 0.914668f, 0.937611f, 0.958241f, 0.974788f}, + {0.306584f, 0.492486f, 0.564964f, 0.618144f, 0.665772f, 0.710574f, 0.752767f, 0.791556f, 0.826674f, 0.858133f, 0.886068f, 0.910543f, 0.93235f, 0.951393f, 0.967994f, 0.980979f}, + {0.302228f, 0.493724f, 0.575805f, 0.635368f, 0.687856f, 0.736327f, 0.780757f, 0.820176f, 0.854453f, 0.883836f, 0.908819f, 0.930057f, 0.948134f, 0.963338f, 0.97616f, 0.986112f}, + {0.302604f, 0.497132f, 0.589276f, 0.65601f, 0.713326f, 0.764997f, 0.810677f, 0.849865f, 0.882233f, 0.908671f, 0.930141f, 0.947615f, 0.961814f, 0.973482f, 0.983032f, 0.990239f}, + {0.311866f, 0.503628f, 0.606047f, 0.680282f, 0.742333f, 0.796606f, 0.842505f, 0.880074f, 0.909306f, 0.931619f, 0.949066f, 0.962478f, 0.973166f, 0.981543f, 0.988346f, 0.993396f}, + {0.334117f, 0.51637f, 0.627737f, 0.708995f, 0.775339f, 0.83081f, 0.87527f, 0.909366f, 0.933935f, 0.951815f, 0.964865f, 0.974633f, 0.982087f, 0.98786f, 0.992355f, 0.995724f}, + {0.37616f, 0.540195f, 0.656277f, 0.743628f, 0.812714f, 0.86728f, 0.907718f, 0.936156f, 0.955518f, 0.968451f, 0.977528f, 0.98398f, 0.988883f, 0.992473f, 0.995349f, 0.997396f}, + {0.444909f, 0.580253f, 0.694618f, 0.785468f, 0.854731f, 0.904603f, 0.937922f, 0.959346f, 0.972722f, 0.981115f, 0.986813f, 0.990738f, 0.993523f, 0.99568f, 0.997376f, 0.99854f}, + {0.540913f, 0.642909f, 0.747808f, 0.836981f, 0.90045f, 0.940121f, 0.963532f, 0.977101f, 0.985125f, 0.98995f, 0.993016f, 0.995111f, 0.996642f, 0.997782f, 0.99864f, 0.999226f}, + {0.655892f, 0.730559f, 0.819629f, 0.895723f, 0.944071f, 0.969216f, 0.98198f, 0.989137f, 0.993044f, 0.995314f, 0.996787f, 0.997799f, 0.998483f, 0.998986f, 0.999396f, 0.999651f}, + {0.767441f, 0.835319f, 0.902341f, 0.949704f, 0.976619f, 0.987855f, 0.993068f, 0.995822f, 0.997367f, 0.998242f, 0.998795f, 0.999172f, 0.999436f, 0.999621f, 0.999777f, 0.999871f}, + {0.860268f, 0.935274f, 0.966945f, 0.984092f, 0.993497f, 0.996752f, 0.998115f, 0.998871f, 0.999308f, 0.999513f, 0.999674f, 0.999771f, 0.999844f, 0.999896f, 0.999942f, 0.999961f}, + {0.939241f, 0.989576f, 0.994816f, 0.997406f, 0.999071f, 0.999539f, 0.999731f, 0.999832f, 0.999896f, 0.999931f, 0.999949f, 0.999969f, 0.999977f, 0.999986f, 0.99999f, 0.999995f}, + {0.990906f, 0.999677f, 0.999807f, 0.999874f, 0.99993f, 0.999952f, 0.999963f, 0.999954f, 0.99997f, 0.999978f, 0.999968f, 0.999965f, 0.999976f, 0.999972f, 0.999972f, 0.999975f} + }, + { + {0.256904f, 0.424754f, 0.496329f, 0.541f, 0.577161f, 0.610539f, 0.643f, 0.675636f, 0.708369f, 0.741092f, 0.773355f, 0.80506f, 0.835457f, 0.864645f, 0.89056f, 0.90455f}, + {0.256637f, 0.421044f, 0.498777f, 0.548196f, 0.58799f, 0.624202f, 0.659399f, 0.694031f, 0.728631f, 0.762539f, 0.795678f, 0.827183f, 0.857095f, 0.884656f, 0.909124f, 0.923263f}, + {0.260348f, 0.418234f, 0.501961f, 0.556894f, 0.600553f, 0.639889f, 0.6775f, 0.71432f, 0.750706f, 0.785707f, 0.81925f, 0.850363f, 0.878689f, 0.904429f, 0.926475f, 0.940143f}, + {0.270219f, 0.418368f, 0.50699f, 0.567241f, 0.615318f, 0.657666f, 0.697777f, 0.736644f, 0.774409f, 0.810466f, 0.84373f, 0.873585f, 0.899967f, 0.923266f, 0.942284f, 0.954443f}, + {0.288652f, 0.424105f, 0.515123f, 0.58019f, 0.632592f, 0.678303f, 0.720819f, 0.76136f, 0.800106f, 0.836255f, 0.868657f, 0.896684f, 0.920475f, 0.940283f, 0.956331f, 0.966379f}, + {0.318977f, 0.436583f, 0.527232f, 0.596754f, 0.653232f, 0.701882f, 0.746601f, 0.78854f, 0.827661f, 0.863311f, 0.893631f, 0.918971f, 0.939366f, 0.955602f, 0.968137f, 0.976146f}, + {0.363206f, 0.460856f, 0.546377f, 0.618231f, 0.677949f, 0.729701f, 0.776126f, 0.818725f, 0.857302f, 0.890705f, 0.918218f, 0.939441f, 0.955885f, 0.96848f, 0.977766f, 0.983681f}, + {0.424515f, 0.501089f, 0.575559f, 0.646174f, 0.708432f, 0.762509f, 0.810299f, 0.852203f, 0.888208f, 0.917752f, 0.940618f, 0.957515f, 0.969877f, 0.978848f, 0.98533f, 0.989367f}, + {0.502553f, 0.557605f, 0.618782f, 0.683938f, 0.746765f, 0.802128f, 0.849225f, 0.888143f, 0.919084f, 0.942748f, 0.960251f, 0.972378f, 0.980698f, 0.986699f, 0.990911f, 0.993465f}, + {0.592986f, 0.631644f, 0.678726f, 0.734988f, 0.7948f, 0.848594f, 0.891821f, 0.924174f, 0.94746f, 0.964093f, 0.975778f, 0.983457f, 0.988777f, 0.992312f, 0.994813f, 0.996281f}, + {0.687377f, 0.714248f, 0.753773f, 0.800942f, 0.852108f, 0.898733f, 0.933333f, 0.955821f, 0.97041f, 0.980304f, 0.986956f, 0.99124f, 0.994077f, 0.996003f, 0.997313f, 0.998074f}, + {0.770882f, 0.79523f, 0.83876f, 0.87676f, 0.911536f, 0.944101f, 0.966593f, 0.978906f, 0.986079f, 0.990761f, 0.993961f, 0.995955f, 0.997319f, 0.998217f, 0.998788f, 0.999133f}, + {0.835431f, 0.873433f, 0.92092f, 0.944318f, 0.960154f, 0.976041f, 0.987186f, 0.992157f, 0.994831f, 0.996532f, 0.997669f, 0.998502f, 0.998984f, 0.999324f, 0.999555f, 0.999681f}, + {0.886285f, 0.948097f, 0.976424f, 0.98447f, 0.987702f, 0.992719f, 0.99661f, 0.997933f, 0.998634f, 0.999061f, 0.999395f, 0.999581f, 0.999729f, 0.999819f, 0.999886f, 0.99992f}, + {0.944359f, 0.99137f, 0.996669f, 0.99791f, 0.998076f, 0.998807f, 0.999526f, 0.999714f, 0.999805f, 0.999864f, 0.999907f, 0.99994f, 0.999961f, 0.999967f, 0.999978f, 0.999993f}, + {0.991143f, 0.999719f, 0.999863f, 0.999898f, 0.999893f, 0.999925f, 0.999958f, 0.999949f, 0.999969f, 0.999976f, 0.999967f, 0.999965f, 0.999976f, 0.999972f, 0.999972f, 0.999975f} + }, + { + {0.264585f, 0.380989f, 0.454393f, 0.503716f, 0.54096f, 0.573291f, 0.602941f, 0.631997f, 0.660964f, 0.690201f, 0.719512f, 0.748977f, 0.777784f, 0.803781f, 0.821673f, 0.826875f}, + {0.277732f, 0.383596f, 0.457525f, 0.509819f, 0.550482f, 0.585225f, 0.617104f, 0.647916f, 0.678334f, 0.708938f, 0.739772f, 0.770601f, 0.800401f, 0.827885f, 0.848226f, 0.858468f}, + {0.297496f, 0.390598f, 0.463136f, 0.517902f, 0.56183f, 0.5992f, 0.633399f, 0.665758f, 0.697656f, 0.729799f, 0.761682f, 0.793706f, 0.824544f, 0.852764f, 0.874231f, 0.887592f}, + {0.326267f, 0.404597f, 0.473285f, 0.529043f, 0.57572f, 0.615744f, 0.651933f, 0.685996f, 0.719357f, 0.752568f, 0.78587f, 0.818445f, 0.849566f, 0.877518f, 0.89911f, 0.912971f}, + {0.364065f, 0.427977f, 0.489784f, 0.544678f, 0.593086f, 0.635453f, 0.673594f, 0.709267f, 0.744133f, 0.77849f, 0.812188f, 0.844951f, 0.875402f, 0.901525f, 0.921826f, 0.934905f}, + {0.413338f, 0.462718f, 0.51532f, 0.566394f, 0.614844f, 0.658715f, 0.699065f, 0.736491f, 0.772566f, 0.807468f, 0.841022f, 0.872546f, 0.901018f, 0.9245f, 0.9418f, 0.953305f}, + {0.47433f, 0.510329f, 0.552084f, 0.596886f, 0.643299f, 0.687754f, 0.729747f, 0.768691f, 0.80548f, 0.8399f, 0.871764f, 0.900638f, 0.925231f, 0.944736f, 0.958796f, 0.967747f}, + {0.544959f, 0.570248f, 0.601173f, 0.637774f, 0.679581f, 0.723945f, 0.766767f, 0.806354f, 0.842948f, 0.875258f, 0.903389f, 0.927466f, 0.947312f, 0.962232f, 0.972586f, 0.978895f}, + {0.6222f, 0.638229f, 0.661379f, 0.690631f, 0.72677f, 0.768451f, 0.810514f, 0.849477f, 0.883368f, 0.911109f, 0.93332f, 0.951218f, 0.965418f, 0.975785f, 0.982781f, 0.987031f}, + {0.699547f, 0.708814f, 0.728904f, 0.755107f, 0.786019f, 0.821987f, 0.859796f, 0.894699f, 0.922949f, 0.943679f, 0.958869f, 0.970413f, 0.979505f, 0.98593f, 0.990077f, 0.992511f}, + {0.770313f, 0.772954f, 0.797454f, 0.826894f, 0.854083f, 0.880596f, 0.909153f, 0.936118f, 0.956346f, 0.96926f, 0.977842f, 0.984166f, 0.989052f, 0.992586f, 0.994846f, 0.996153f}, + {0.825324f, 0.829644f, 0.86696f, 0.898979f, 0.920101f, 0.934728f, 0.950628f, 0.967633f, 0.979593f, 0.986058f, 0.989888f, 0.992809f, 0.995032f, 0.996639f, 0.997636f, 0.998231f}, + {0.863698f, 0.888044f, 0.93283f, 0.956652f, 0.968193f, 0.973147f, 0.978605f, 0.986924f, 0.992497f, 0.994971f, 0.996334f, 0.997324f, 0.99812f, 0.99872f, 0.999111f, 0.999357f}, + {0.896649f, 0.951907f, 0.979323f, 0.988331f, 0.991859f, 0.992727f, 0.993374f, 0.996207f, 0.998059f, 0.998683f, 0.999045f, 0.999279f, 0.999495f, 0.999651f, 0.999771f, 0.999839f}, + {0.946504f, 0.991866f, 0.997096f, 0.998411f, 0.998961f, 0.999007f, 0.998924f, 0.999404f, 0.999715f, 0.999807f, 0.999858f, 0.999894f, 0.999925f, 0.999948f, 0.99997f, 0.999976f}, + {0.991229f, 0.999729f, 0.999872f, 0.99992f, 0.999927f, 0.999937f, 0.999938f, 0.999939f, 0.999966f, 0.999974f, 0.999966f, 0.999961f, 0.999976f, 0.999972f, 0.999972f, 0.999973f} + }, + { + {0.317672f, 0.379772f, 0.434995f, 0.478433f, 0.513252f, 0.543012f, 0.569608f, 0.594619f, 0.618758f, 0.642435f, 0.665975f, 0.688625f, 0.710007f, 0.726249f, 0.732969f, 0.737468f}, + {0.34194f, 0.393822f, 0.444657f, 0.487584f, 0.52402f, 0.555426f, 0.583729f, 0.610112f, 0.635474f, 0.660523f, 0.68545f, 0.710145f, 0.734133f, 0.754925f, 0.768756f, 0.781315f}, + {0.372936f, 0.41426f, 0.459314f, 0.500417f, 0.53751f, 0.570438f, 0.600301f, 0.628293f, 0.654918f, 0.681319f, 0.70749f, 0.734155f, 0.760681f, 0.785337f, 0.804356f, 0.822369f}, + {0.412386f, 0.443328f, 0.480816f, 0.518452f, 0.554844f, 0.588701f, 0.619944f, 0.649243f, 0.677332f, 0.704851f, 0.732926f, 0.761178f, 0.789821f, 0.816979f, 0.839927f, 0.860467f}, + {0.459182f, 0.480803f, 0.510698f, 0.543466f, 0.577691f, 0.611229f, 0.643044f, 0.674001f, 0.703592f, 0.732581f, 0.761858f, 0.791634f, 0.82104f, 0.849167f, 0.873217f, 0.893996f}, + {0.514798f, 0.528562f, 0.550377f, 0.576799f, 0.606945f, 0.638741f, 0.671324f, 0.703154f, 0.734342f, 0.764995f, 0.795377f, 0.825267f, 0.854095f, 0.880996f, 0.903836f, 0.922661f}, + {0.576429f, 0.583964f, 0.599092f, 0.619577f, 0.644143f, 0.673295f, 0.705428f, 0.73839f, 0.77082f, 0.802373f, 0.832844f, 0.861325f, 0.887556f, 0.911092f, 0.930845f, 0.94606f}, + {0.642323f, 0.645034f, 0.655166f, 0.670406f, 0.690854f, 0.716584f, 0.747033f, 0.780057f, 0.812784f, 0.843988f, 0.872615f, 0.897819f, 0.91928f, 0.937816f, 0.953006f, 0.964439f}, + {0.707651f, 0.705863f, 0.713653f, 0.727617f, 0.746742f, 0.769487f, 0.796892f, 0.82727f, 0.85825f, 0.886988f, 0.911665f, 0.931306f, 0.946921f, 0.959863f, 0.970274f, 0.977884f}, + {0.768305f, 0.761011f, 0.770667f, 0.788632f, 0.809512f, 0.830379f, 0.852541f, 0.877292f, 0.90318f, 0.926979f, 0.945545f, 0.958815f, 0.968652f, 0.976559f, 0.982819f, 0.987355f}, + {0.819533f, 0.807633f, 0.825012f, 0.851067f, 0.874615f, 0.893058f, 0.907921f, 0.923517f, 0.941923f, 0.959031f, 0.970957f, 0.978474f, 0.983602f, 0.98763f, 0.99097f, 0.99347f}, + {0.856481f, 0.848157f, 0.88085f, 0.911788f, 0.932947f, 0.946153f, 0.953749f, 0.959831f, 0.970164f, 0.980711f, 0.986951f, 0.99046f, 0.992739f, 0.994419f, 0.995858f, 0.996993f}, + {0.879455f, 0.895342f, 0.938113f, 0.961698f, 0.973822f, 0.979847f, 0.982648f, 0.983368f, 0.987279f, 0.992764f, 0.995312f, 0.996578f, 0.997372f, 0.997933f, 0.998501f, 0.998916f}, + {0.902488f, 0.953905f, 0.980707f, 0.989527f, 0.99321f, 0.994913f, 0.995672f, 0.995206f, 0.996094f, 0.998062f, 0.998778f, 0.999099f, 0.999288f, 0.999444f, 0.999577f, 0.999716f}, + {0.947838f, 0.99217f, 0.997259f, 0.998559f, 0.999105f, 0.999327f, 0.999431f, 0.99931f, 0.999346f, 0.999717f, 0.99982f, 0.999867f, 0.999898f, 0.999922f, 0.999947f, 0.999962f}, + {0.991276f, 0.999736f, 0.999882f, 0.999921f, 0.999937f, 0.999945f, 0.999952f, 0.999937f, 0.999953f, 0.999971f, 0.999965f, 0.99996f, 0.999975f, 0.99997f, 0.99997f, 0.999973f} + }, + { + {0.389232f, 0.4106f, 0.441287f, 0.471024f, 0.498133f, 0.522389f, 0.544754f, 0.564854f, 0.583887f, 0.601715f, 0.61798f, 0.632338f, 0.641487f, 0.642305f, 0.642109f, 0.645058f}, + {0.419866f, 0.433959f, 0.459285f, 0.486614f, 0.512656f, 0.537534f, 0.56031f, 0.581903f, 0.602083f, 0.621111f, 0.639131f, 0.655627f, 0.669362f, 0.677087f, 0.685536f, 0.69844f}, + {0.457074f, 0.464442f, 0.483894f, 0.506939f, 0.531485f, 0.556034f, 0.579539f, 0.601915f, 0.623243f, 0.643633f, 0.663162f, 0.682512f, 0.700151f, 0.714379f, 0.729927f, 0.750548f}, + {0.500718f, 0.502026f, 0.515138f, 0.534071f, 0.555887f, 0.578839f, 0.602149f, 0.625411f, 0.647713f, 0.6697f, 0.6915f, 0.713411f, 0.734647f, 0.753837f, 0.775004f, 0.799966f}, + {0.549321f, 0.546636f, 0.554598f, 0.56844f, 0.58618f, 0.606839f, 0.62957f, 0.653197f, 0.6769f, 0.700492f, 0.724456f, 0.748843f, 0.772559f, 0.795413f, 0.819034f, 0.845355f}, + {0.603212f, 0.59682f, 0.600127f, 0.610079f, 0.623859f, 0.641501f, 0.66259f, 0.686419f, 0.711285f, 0.736487f, 0.762277f, 0.788308f, 0.813579f, 0.837172f, 0.860793f, 0.885258f}, + {0.659187f, 0.650636f, 0.651303f, 0.657924f, 0.668481f, 0.683561f, 0.70242f, 0.725576f, 0.751116f, 0.777973f, 0.804939f, 0.831435f, 0.855943f, 0.877751f, 0.898556f, 0.919262f}, + {0.71551f, 0.704609f, 0.703716f, 0.708983f, 0.718526f, 0.732501f, 0.75024f, 0.771848f, 0.796942f, 0.823383f, 0.850091f, 0.875083f, 0.896821f, 0.914699f, 0.930683f, 0.946116f}, + {0.768218f, 0.754625f, 0.753729f, 0.761135f, 0.773317f, 0.788683f, 0.80554f, 0.8244f, 0.846324f, 0.870275f, 0.894278f, 0.915623f, 0.932582f, 0.945417f, 0.956229f, 0.966498f}, + {0.815168f, 0.796799f, 0.799071f, 0.812766f, 0.830588f, 0.848294f, 0.864463f, 0.879108f, 0.895118f, 0.913632f, 0.932964f, 0.949149f, 0.960601f, 0.968452f, 0.974828f, 0.980732f}, + {0.852166f, 0.829841f, 0.841897f, 0.865298f, 0.888307f, 0.9063f, 0.919384f, 0.92889f, 0.937434f, 0.948938f, 0.962664f, 0.973255f, 0.979758f, 0.983791f, 0.986941f, 0.990001f}, + {0.876614f, 0.859595f, 0.888882f, 0.918553f, 0.939569f, 0.953198f, 0.961563f, 0.966168f, 0.968709f, 0.97368f, 0.982199f, 0.988093f, 0.991157f, 0.992837f, 0.994129f, 0.995457f}, + {0.889616f, 0.899825f, 0.941002f, 0.964038f, 0.976181f, 0.982571f, 0.986116f, 0.987916f, 0.987746f, 0.988747f, 0.993139f, 0.995725f, 0.996832f, 0.997418f, 0.997862f, 0.998328f}, + {0.906243f, 0.95518f, 0.981506f, 0.990171f, 0.993785f, 0.995553f, 0.996545f, 0.996982f, 0.996721f, 0.996453f, 0.998093f, 0.998888f, 0.999156f, 0.999327f, 0.999409f, 0.999539f}, + {0.948599f, 0.992358f, 0.99739f, 0.998668f, 0.999176f, 0.999406f, 0.999541f, 0.999591f, 0.999568f, 0.999408f, 0.999713f, 0.999839f, 0.999881f, 0.999901f, 0.999926f, 0.999939f}, + {0.991309f, 0.999739f, 0.999888f, 0.999919f, 0.999936f, 0.999947f, 0.999957f, 0.999945f, 0.999963f, 0.999961f, 0.999962f, 0.99996f, 0.999975f, 0.999969f, 0.999969f, 0.999972f} + }, + { + {0.464607f, 0.455732f, 0.464628f, 0.479669f, 0.495949f, 0.512354f, 0.528314f, 0.542978f, 0.556498f, 0.567824f, 0.576463f, 0.580128f, 0.575605f, 0.568531f, 0.562623f, 0.559205f}, + {0.498542f, 0.485636f, 0.490143f, 0.501702f, 0.516224f, 0.531793f, 0.54759f, 0.562699f, 0.577045f, 0.589905f, 0.600538f, 0.607645f, 0.609028f, 0.609586f, 0.612334f, 0.618659f}, + {0.537333f, 0.521767f, 0.521981f, 0.529418f, 0.541199f, 0.55568f, 0.570931f, 0.586192f, 0.601126f, 0.615273f, 0.628334f, 0.639068f, 0.646205f, 0.653576f, 0.664226f, 0.679003f}, + {0.58039f, 0.563085f, 0.559246f, 0.563593f, 0.572154f, 0.583834f, 0.597981f, 0.613261f, 0.629026f, 0.644943f, 0.660698f, 0.675112f, 0.687528f, 0.701108f, 0.717599f, 0.738633f}, + {0.626902f, 0.608143f, 0.602518f, 0.603236f, 0.608819f, 0.618142f, 0.63031f, 0.645141f, 0.662034f, 0.679491f, 0.697664f, 0.715681f, 0.732767f, 0.751152f, 0.771428f, 0.795163f}, + {0.674906f, 0.656073f, 0.64876f, 0.647692f, 0.650566f, 0.657853f, 0.668736f, 0.682954f, 0.700176f, 0.719539f, 0.739842f, 0.760707f, 0.781203f, 0.802008f, 0.82361f, 0.846272f}, + {0.723717f, 0.704351f, 0.696222f, 0.694352f, 0.696957f, 0.703334f, 0.713785f, 0.727349f, 0.744532f, 0.764707f, 0.786484f, 0.809047f, 0.830832f, 0.851582f, 0.871387f, 0.890878f}, + {0.770417f, 0.74989f, 0.741971f, 0.741f, 0.745419f, 0.753661f, 0.764643f, 0.778067f, 0.79442f, 0.813643f, 0.835382f, 0.857523f, 0.878316f, 0.896853f, 0.912706f, 0.927042f}, + {0.812279f, 0.789808f, 0.7826f, 0.785788f, 0.79504f, 0.807f, 0.820062f, 0.833465f, 0.847781f, 0.863701f, 0.882574f, 0.902333f, 0.920185f, 0.934458f, 0.945346f, 0.954754f}, + {0.848046f, 0.821273f, 0.818615f, 0.829032f, 0.845226f, 0.861958f, 0.876709f, 0.88927f, 0.899701f, 0.910298f, 0.92378f, 0.939469f, 0.952959f, 0.962471f, 0.968968f, 0.974084f}, + {0.874714f, 0.844976f, 0.852751f, 0.874465f, 0.896205f, 0.914235f, 0.927761f, 0.937383f, 0.943498f, 0.948295f, 0.955712f, 0.966655f, 0.975661f, 0.980913f, 0.984102f, 0.986657f}, + {0.890484f, 0.867243f, 0.894007f, 0.922732f, 0.943369f, 0.956978f, 0.965632f, 0.971131f, 0.974095f, 0.975102f, 0.977362f, 0.984168f, 0.989293f, 0.99165f, 0.993033f, 0.994062f}, + {0.896619f, 0.902953f, 0.942851f, 0.965488f, 0.977382f, 0.98389f, 0.987623f, 0.989862f, 0.9908f, 0.9906f, 0.990299f, 0.993846f, 0.996119f, 0.997008f, 0.997498f, 0.997813f}, + {0.908873f, 0.955985f, 0.982049f, 0.990586f, 0.994125f, 0.995898f, 0.996901f, 0.997459f, 0.997764f, 0.997618f, 0.996962f, 0.998277f, 0.998985f, 0.999217f, 0.999302f, 0.999407f}, + {0.949116f, 0.992473f, 0.997458f, 0.99872f, 0.999217f, 0.999448f, 0.999588f, 0.999656f, 0.999694f, 0.999686f, 0.999497f, 0.999741f, 0.999857f, 0.999887f, 0.999913f, 0.999924f}, + {0.991334f, 0.999745f, 0.999889f, 0.999921f, 0.999937f, 0.999949f, 0.999954f, 0.999949f, 0.999967f, 0.999973f, 0.999954f, 0.999956f, 0.999974f, 0.999969f, 0.999969f, 0.99997f} + }, + { + {0.535644f, 0.50519f, 0.496654f, 0.497589f, 0.503236f, 0.510989f, 0.519873f, 0.527879f, 0.535008f, 0.539309f, 0.539252f, 0.531167f, 0.519742f, 0.509007f, 0.49861f, 0.487933f}, + {0.570331f, 0.538577f, 0.527508f, 0.525756f, 0.528668f, 0.535016f, 0.543254f, 0.551359f, 0.558994f, 0.565094f, 0.567923f, 0.56429f, 0.559234f, 0.55558f, 0.553574f, 0.551784f}, + {0.608133f, 0.576666f, 0.563094f, 0.558455f, 0.559389f, 0.563998f, 0.570572f, 0.578631f, 0.586698f, 0.594588f, 0.59993f, 0.601645f, 0.602898f, 0.606063f, 0.611528f, 0.61833f}, + {0.648542f, 0.617661f, 0.602755f, 0.596267f, 0.595127f, 0.597269f, 0.602791f, 0.610193f, 0.618942f, 0.628369f, 0.636854f, 0.643649f, 0.65072f, 0.660298f, 0.672199f, 0.686181f}, + {0.690624f, 0.660779f, 0.645878f, 0.638184f, 0.634787f, 0.635821f, 0.640049f, 0.646755f, 0.656027f, 0.66701f, 0.678948f, 0.690056f, 0.70241f, 0.717372f, 0.734148f, 0.751897f}, + {0.732596f, 0.704246f, 0.689645f, 0.68144f, 0.677921f, 0.678025f, 0.682047f, 0.689125f, 0.698744f, 0.711014f, 0.725492f, 0.74041f, 0.756919f, 0.775316f, 0.794663f, 0.813491f}, + {0.773768f, 0.746302f, 0.731699f, 0.72453f, 0.722755f, 0.724264f, 0.729055f, 0.736672f, 0.747245f, 0.760346f, 0.776148f, 0.793309f, 0.811932f, 0.831565f, 0.850666f, 0.86747f}, + {0.811941f, 0.784254f, 0.770546f, 0.765597f, 0.766766f, 0.772039f, 0.77987f, 0.789017f, 0.800264f, 0.813001f, 0.828234f, 0.845605f, 0.864049f, 0.882742f, 0.898867f, 0.911758f}, + {0.845093f, 0.815462f, 0.803637f, 0.803392f, 0.810509f, 0.820776f, 0.832867f, 0.844459f, 0.855457f, 0.866203f, 0.878509f, 0.893151f, 0.909659f, 0.925137f, 0.937169f, 0.945601f}, + {0.872363f, 0.839073f, 0.832138f, 0.8403f, 0.854991f, 0.871149f, 0.885615f, 0.897785f, 0.907383f, 0.914778f, 0.922322f, 0.932492f, 0.945472f, 0.956909f, 0.964608f, 0.969221f}, + {0.891443f, 0.85558f, 0.860369f, 0.880426f, 0.901355f, 0.919079f, 0.932875f, 0.942666f, 0.949403f, 0.953541f, 0.956108f, 0.961355f, 0.970612f, 0.978002f, 0.982078f, 0.984329f}, + {0.900528f, 0.872783f, 0.8976f, 0.925454f, 0.94568f, 0.959191f, 0.967968f, 0.973783f, 0.977401f, 0.979213f, 0.979158f, 0.980373f, 0.986408f, 0.990353f, 0.992219f, 0.993144f}, + {0.901743f, 0.905093f, 0.944182f, 0.966457f, 0.978205f, 0.98465f, 0.9884f, 0.990632f, 0.992106f, 0.992708f, 0.992145f, 0.991677f, 0.994772f, 0.996532f, 0.997214f, 0.997501f}, + {0.910784f, 0.956624f, 0.982355f, 0.990847f, 0.994321f, 0.996039f, 0.997124f, 0.997692f, 0.998021f, 0.99817f, 0.998013f, 0.997404f, 0.998577f, 0.999088f, 0.999224f, 0.999337f}, + {0.949535f, 0.992566f, 0.99751f, 0.998743f, 0.999234f, 0.999473f, 0.999598f, 0.999686f, 0.999714f, 0.999748f, 0.99974f, 0.999573f, 0.999796f, 0.99987f, 0.999902f, 0.99991f}, + {0.99135f, 0.999749f, 0.999893f, 0.999923f, 0.999936f, 0.999949f, 0.99996f, 0.999951f, 0.999967f, 0.999974f, 0.999963f, 0.999951f, 0.999973f, 0.999968f, 0.999969f, 0.999968f} + }, + { + {0.59973f, 0.552818f, 0.530643f, 0.520157f, 0.516116f, 0.51552f, 0.516777f, 0.51803f, 0.518346f, 0.514724f, 0.504512f, 0.49003f, 0.476615f, 0.463236f, 0.449735f, 0.435024f}, + {0.632997f, 0.587111f, 0.564079f, 0.55199f, 0.545828f, 0.543759f, 0.544237f, 0.545366f, 0.546202f, 0.544842f, 0.53818f, 0.529142f, 0.521583f, 0.51462f, 0.508502f, 0.501598f}, + {0.668169f, 0.624811f, 0.601631f, 0.587864f, 0.580326f, 0.576726f, 0.576042f, 0.577016f, 0.578406f, 0.578992f, 0.57605f, 0.572798f, 0.570656f, 0.570384f, 0.571488f, 0.572872f}, + {0.705117f, 0.664106f, 0.641318f, 0.62698f, 0.618315f, 0.613663f, 0.612384f, 0.61263f, 0.614626f, 0.617233f, 0.618782f, 0.620316f, 0.624132f, 0.630072f, 0.637842f, 0.646764f}, + {0.742334f, 0.703971f, 0.68226f, 0.668393f, 0.658955f, 0.654337f, 0.652719f, 0.653158f, 0.656184f, 0.66065f, 0.665755f, 0.671911f, 0.680942f, 0.692708f, 0.706068f, 0.719966f}, + {0.778325f, 0.742889f, 0.722235f, 0.70907f, 0.70122f, 0.69721f, 0.6965f, 0.698327f, 0.702251f, 0.708926f, 0.716871f, 0.727084f, 0.740321f, 0.75591f, 0.772929f, 0.789173f}, + {0.81242f, 0.778793f, 0.759492f, 0.748279f, 0.742735f, 0.741557f, 0.743404f, 0.747793f, 0.753545f, 0.761827f, 0.771555f, 0.783946f, 0.799266f, 0.816835f, 0.83493f, 0.850679f}, + {0.843431f, 0.810221f, 0.792039f, 0.783845f, 0.782521f, 0.78594f, 0.791957f, 0.799556f, 0.808191f, 0.817271f, 0.827202f, 0.839323f, 0.854523f, 0.87179f, 0.888237f, 0.901303f}, + {0.869961f, 0.834643f, 0.819008f, 0.816238f, 0.821508f, 0.83095f, 0.84206f, 0.853057f, 0.863007f, 0.871636f, 0.880071f, 0.889763f, 0.902333f, 0.917331f, 0.930631f, 0.93963f}, + {0.890577f, 0.85214f, 0.841829f, 0.848149f, 0.861853f, 0.877146f, 0.891448f, 0.903829f, 0.913532f, 0.920373f, 0.925714f, 0.931231f, 0.939873f, 0.951653f, 0.960918f, 0.966293f}, + {0.903713f, 0.8635f, 0.866053f, 0.884673f, 0.905078f, 0.922462f, 0.936053f, 0.945959f, 0.953258f, 0.957631f, 0.960226f, 0.961587f, 0.96635f, 0.974725f, 0.980311f, 0.983058f}, + {0.908067f, 0.876709f, 0.900129f, 0.927439f, 0.947228f, 0.960614f, 0.969409f, 0.975195f, 0.978983f, 0.981397f, 0.982261f, 0.98159f, 0.983296f, 0.988598f, 0.991442f, 0.992607f}, + {0.905559f, 0.906706f, 0.945145f, 0.967146f, 0.978792f, 0.985152f, 0.988866f, 0.991238f, 0.992573f, 0.993521f, 0.993828f, 0.993031f, 0.992871f, 0.995809f, 0.996953f, 0.997356f}, + {0.912211f, 0.957039f, 0.982562f, 0.990982f, 0.994478f, 0.996159f, 0.997183f, 0.997758f, 0.99816f, 0.998377f, 0.998465f, 0.998245f, 0.997787f, 0.998881f, 0.999157f, 0.999302f}, + {0.949831f, 0.99262f, 0.997544f, 0.998773f, 0.999238f, 0.999496f, 0.999626f, 0.999703f, 0.999743f, 0.999767f, 0.999784f, 0.999767f, 0.999643f, 0.999844f, 0.999891f, 0.999905f}, + {0.991361f, 0.999754f, 0.999893f, 0.999924f, 0.999936f, 0.999951f, 0.999959f, 0.999951f, 0.999969f, 0.999973f, 0.999964f, 0.999959f, 0.999968f, 0.999967f, 0.999968f, 0.999968f} + }, + { + {0.654676f, 0.59532f, 0.562607f, 0.54273f, 0.530577f, 0.52264f, 0.517073f, 0.511514f, 0.504402f, 0.491501f, 0.475258f, 0.459301f, 0.444324f, 0.429177f, 0.414139f, 0.398977f}, + {0.686151f, 0.629447f, 0.597385f, 0.577208f, 0.563557f, 0.5543f, 0.548279f, 0.542757f, 0.536421f, 0.526823f, 0.514555f, 0.503255f, 0.493831f, 0.484346f, 0.475693f, 0.46729f}, + {0.717895f, 0.665604f, 0.635024f, 0.614131f, 0.600309f, 0.590793f, 0.583714f, 0.578272f, 0.573119f, 0.56593f, 0.558015f, 0.551866f, 0.547493f, 0.544452f, 0.542585f, 0.541624f}, + {0.751169f, 0.702484f, 0.673297f, 0.653206f, 0.639342f, 0.62976f, 0.622743f, 0.617912f, 0.613845f, 0.609127f, 0.605943f, 0.604379f, 0.605509f, 0.608557f, 0.613293f, 0.619877f}, + {0.783237f, 0.738911f, 0.711777f, 0.692944f, 0.679718f, 0.670958f, 0.664668f, 0.661096f, 0.658669f, 0.657331f, 0.657487f, 0.660671f, 0.666855f, 0.675339f, 0.686082f, 0.698414f}, + {0.81389f, 0.773134f, 0.748038f, 0.730966f, 0.719877f, 0.712763f, 0.709313f, 0.707496f, 0.707847f, 0.709368f, 0.713043f, 0.719855f, 0.729735f, 0.742554f, 0.757318f, 0.773124f}, + {0.842615f, 0.804118f, 0.780557f, 0.766424f, 0.758346f, 0.754852f, 0.75494f, 0.757283f, 0.760534f, 0.765159f, 0.771012f, 0.779851f, 0.791974f, 0.806569f, 0.823433f, 0.839688f}, + {0.86778f, 0.829723f, 0.80825f, 0.797446f, 0.794359f, 0.796189f, 0.80129f, 0.807893f, 0.815203f, 0.822077f, 0.829476f, 0.83815f, 0.849642f, 0.864134f, 0.880192f, 0.894549f}, + {0.888723f, 0.849193f, 0.830428f, 0.825644f, 0.829293f, 0.838161f, 0.848673f, 0.859429f, 0.868781f, 0.877112f, 0.883703f, 0.890558f, 0.899185f, 0.911532f, 0.925323f, 0.935976f}, + {0.904265f, 0.861773f, 0.849084f, 0.853769f, 0.866609f, 0.881528f, 0.895544f, 0.907821f, 0.917513f, 0.924602f, 0.929705f, 0.933389f, 0.938068f, 0.947244f, 0.957673f, 0.964536f}, + {0.912919f, 0.869358f, 0.870041f, 0.88768f, 0.907484f, 0.924736f, 0.938087f, 0.947975f, 0.955366f, 0.960351f, 0.963268f, 0.964553f, 0.965688f, 0.971382f, 0.97857f, 0.982323f}, + {0.913656f, 0.879634f, 0.901988f, 0.928741f, 0.948291f, 0.961506f, 0.970343f, 0.976191f, 0.980038f, 0.982511f, 0.983914f, 0.984118f, 0.9833f, 0.986313f, 0.990643f, 0.99235f}, + {0.908461f, 0.907873f, 0.945866f, 0.967611f, 0.979155f, 0.985489f, 0.989231f, 0.991488f, 0.992973f, 0.993936f, 0.99444f, 0.994481f, 0.993323f, 0.994502f, 0.996668f, 0.997279f}, + {0.913294f, 0.957376f, 0.982744f, 0.991115f, 0.994583f, 0.99626f, 0.997271f, 0.997831f, 0.99826f, 0.998478f, 0.998631f, 0.998611f, 0.998137f, 0.998381f, 0.99909f, 0.999289f}, + {0.950029f, 0.992669f, 0.997573f, 0.998792f, 0.999256f, 0.999498f, 0.99963f, 0.999708f, 0.999759f, 0.999793f, 0.999807f, 0.999807f, 0.99973f, 0.999747f, 0.999879f, 0.999903f}, + {0.991379f, 0.999757f, 0.999895f, 0.999925f, 0.999936f, 0.999953f, 0.999958f, 0.99995f, 0.999968f, 0.999973f, 0.999967f, 0.999959f, 0.999972f, 0.999963f, 0.999968f, 0.999968f} + }, + { + {0.701283f, 0.631609f, 0.590791f, 0.563657f, 0.544568f, 0.530369f, 0.518693f, 0.506491f, 0.491062f, 0.471977f, 0.453936f, 0.436798f, 0.420917f, 0.405036f, 0.389759f, 0.375973f}, + {0.730196f, 0.664903f, 0.625716f, 0.598936f, 0.579934f, 0.564673f, 0.552868f, 0.541584f, 0.527948f, 0.512314f, 0.497918f, 0.485108f, 0.473825f, 0.463099f, 0.453284f, 0.445269f}, + {0.75871f, 0.699282f, 0.662597f, 0.636558f, 0.617696f, 0.60309f, 0.591416f, 0.580311f, 0.56901f, 0.556289f, 0.54594f, 0.53783f, 0.531363f, 0.526312f, 0.522932f, 0.521629f}, + {0.787871f, 0.733163f, 0.699089f, 0.674943f, 0.656999f, 0.643239f, 0.632021f, 0.622998f, 0.613578f, 0.604161f, 0.598042f, 0.594089f, 0.592947f, 0.59385f, 0.596666f, 0.602704f}, + {0.815874f, 0.765978f, 0.735051f, 0.71273f, 0.69632f, 0.684541f, 0.675091f, 0.667648f, 0.661466f, 0.656148f, 0.653631f, 0.654271f, 0.657856f, 0.66402f, 0.672603f, 0.684604f}, + {0.841934f, 0.796586f, 0.767979f, 0.748061f, 0.734541f, 0.72515f, 0.71936f, 0.715301f, 0.712778f, 0.711296f, 0.71245f, 0.716704f, 0.723992f, 0.734124f, 0.746976f, 0.762878f}, + {0.865935f, 0.823198f, 0.796706f, 0.780209f, 0.770091f, 0.765027f, 0.763333f, 0.764378f, 0.766053f, 0.768751f, 0.773071f, 0.779501f, 0.788486f, 0.800539f, 0.815685f, 0.832755f}, + {0.886749f, 0.844826f, 0.820477f, 0.807657f, 0.80303f, 0.803694f, 0.808046f, 0.813893f, 0.8204f, 0.826566f, 0.832809f, 0.83965f, 0.848298f, 0.85991f, 0.874561f, 0.890263f}, + {0.903223f, 0.860252f, 0.838974f, 0.832478f, 0.835173f, 0.843307f, 0.853267f, 0.863631f, 0.872986f, 0.880853f, 0.887624f, 0.893368f, 0.899353f, 0.908364f, 0.92135f, 0.933599f}, + {0.914895f, 0.869102f, 0.854416f, 0.857914f, 0.869986f, 0.884328f, 0.898298f, 0.910349f, 0.919873f, 0.927424f, 0.932819f, 0.936563f, 0.939487f, 0.94486f, 0.954848f, 0.963392f}, + {0.92025f, 0.873787f, 0.873043f, 0.889895f, 0.909314f, 0.926297f, 0.939483f, 0.949355f, 0.956715f, 0.961806f, 0.965408f, 0.96719f, 0.967507f, 0.969543f, 0.976742f, 0.981854f}, + {0.917948f, 0.881872f, 0.903407f, 0.929708f, 0.949123f, 0.962271f, 0.970883f, 0.976753f, 0.980604f, 0.983267f, 0.984823f, 0.985719f, 0.985322f, 0.984983f, 0.989636f, 0.992183f}, + {0.910636f, 0.908797f, 0.946414f, 0.967988f, 0.979453f, 0.985659f, 0.989433f, 0.991682f, 0.99316f, 0.994164f, 0.994788f, 0.99502f, 0.994648f, 0.993706f, 0.996244f, 0.997233f}, + {0.914078f, 0.95762f, 0.982874f, 0.991184f, 0.994643f, 0.996325f, 0.997353f, 0.997903f, 0.99829f, 0.99851f, 0.998671f, 0.99875f, 0.998692f, 0.998057f, 0.998976f, 0.999278f}, + {0.950208f, 0.992704f, 0.997595f, 0.9988f, 0.999282f, 0.999503f, 0.999644f, 0.999721f, 0.999751f, 0.999793f, 0.999808f, 0.999814f, 0.999826f, 0.999707f, 0.999862f, 0.999902f}, + {0.991386f, 0.999757f, 0.999895f, 0.999926f, 0.999937f, 0.999953f, 0.99996f, 0.999951f, 0.999968f, 0.999975f, 0.999967f, 0.999959f, 0.999976f, 0.999961f, 0.999967f, 0.999968f} + }, + { + {0.739778f, 0.661981f, 0.614519f, 0.581398f, 0.557306f, 0.537236f, 0.519877f, 0.501546f, 0.47938f, 0.458089f, 0.438817f, 0.421047f, 0.404398f, 0.388427f, 0.374196f, 0.361575f}, + {0.766009f, 0.6941f, 0.649217f, 0.617718f, 0.593578f, 0.573984f, 0.557176f, 0.539899f, 0.52048f, 0.502346f, 0.486733f, 0.472533f, 0.460112f, 0.448827f, 0.439189f, 0.431442f}, + {0.791642f, 0.726574f, 0.684914f, 0.654938f, 0.63208f, 0.613643f, 0.597698f, 0.581789f, 0.565231f, 0.550402f, 0.538079f, 0.528682f, 0.520661f, 0.514542f, 0.5106f, 0.509097f}, + {0.817359f, 0.757799f, 0.719905f, 0.692383f, 0.671033f, 0.654384f, 0.639872f, 0.626648f, 0.61344f, 0.601787f, 0.593969f, 0.588313f, 0.585293f, 0.584608f, 0.586594f, 0.591851f}, + {0.841507f, 0.787679f, 0.75347f, 0.728337f, 0.70957f, 0.694878f, 0.683113f, 0.673125f, 0.663414f, 0.656921f, 0.652573f, 0.651336f, 0.652872f, 0.657233f, 0.664633f, 0.675853f}, + {0.864067f, 0.814815f, 0.783425f, 0.761238f, 0.745584f, 0.734387f, 0.726839f, 0.720942f, 0.716462f, 0.713896f, 0.713758f, 0.716234f, 0.721376f, 0.729465f, 0.74094f, 0.756301f}, + {0.884084f, 0.838008f, 0.808943f, 0.790538f, 0.778836f, 0.772328f, 0.769884f, 0.769473f, 0.770142f, 0.77224f, 0.776124f, 0.780973f, 0.787884f, 0.797596f, 0.811259f, 0.828174f}, + {0.901344f, 0.856394f, 0.829732f, 0.815137f, 0.809389f, 0.809136f, 0.812727f, 0.817882f, 0.823857f, 0.830124f, 0.836163f, 0.842295f, 0.84916f, 0.858317f, 0.871217f, 0.887319f}, + {0.914526f, 0.868599f, 0.84526f, 0.837525f, 0.839408f, 0.846857f, 0.856456f, 0.866433f, 0.875764f, 0.883618f, 0.890695f, 0.896488f, 0.901232f, 0.907641f, 0.918784f, 0.931855f}, + {0.922982f, 0.874709f, 0.858501f, 0.861113f, 0.872533f, 0.886545f, 0.900127f, 0.911956f, 0.921509f, 0.929207f, 0.935147f, 0.939275f, 0.941776f, 0.944701f, 0.952789f, 0.962454f}, + {0.925782f, 0.877133f, 0.875308f, 0.891519f, 0.910631f, 0.927329f, 0.940375f, 0.950293f, 0.957518f, 0.96278f, 0.966636f, 0.968953f, 0.969842f, 0.969839f, 0.975088f, 0.981411f}, + {0.921248f, 0.883587f, 0.90448f, 0.93043f, 0.949709f, 0.962698f, 0.971276f, 0.977072f, 0.981011f, 0.983684f, 0.985523f, 0.986612f, 0.986854f, 0.985561f, 0.988429f, 0.992005f}, + {0.912277f, 0.909461f, 0.946828f, 0.968264f, 0.979653f, 0.985861f, 0.989548f, 0.991826f, 0.993265f, 0.994305f, 0.994896f, 0.995299f, 0.995359f, 0.994336f, 0.995546f, 0.997175f}, + {0.914709f, 0.957806f, 0.98299f, 0.99125f, 0.994695f, 0.996377f, 0.997389f, 0.997929f, 0.998325f, 0.998541f, 0.998718f, 0.998825f, 0.99885f, 0.998436f, 0.998697f, 0.999265f}, + {0.950336f, 0.992723f, 0.99761f, 0.998802f, 0.999296f, 0.999519f, 0.999649f, 0.999722f, 0.999762f, 0.9998f, 0.999822f, 0.999833f, 0.999837f, 0.999763f, 0.999808f, 0.9999f}, + {0.99139f, 0.999757f, 0.999897f, 0.999926f, 0.999938f, 0.999952f, 0.999961f, 0.999951f, 0.999968f, 0.999974f, 0.999967f, 0.99996f, 0.999976f, 0.999964f, 0.999965f, 0.999968f} + }, + { + {0.770998f, 0.686931f, 0.634265f, 0.596254f, 0.567331f, 0.543185f, 0.520343f, 0.495714f, 0.470991f, 0.448555f, 0.428511f, 0.410107f, 0.393342f, 0.378156f, 0.36469f, 0.352596f}, + {0.795015f, 0.717653f, 0.668339f, 0.632841f, 0.604974f, 0.581209f, 0.560113f, 0.537314f, 0.515121f, 0.496039f, 0.479315f, 0.464286f, 0.451354f, 0.440024f, 0.430609f, 0.422883f}, + {0.817973f, 0.7482f, 0.702787f, 0.669535f, 0.643446f, 0.621934f, 0.602381f, 0.582128f, 0.563082f, 0.547239f, 0.533819f, 0.523213f, 0.514104f, 0.507522f, 0.503359f, 0.501306f}, + {0.840778f, 0.777305f, 0.736223f, 0.705801f, 0.682064f, 0.662551f, 0.645414f, 0.628567f, 0.613626f, 0.601269f, 0.592265f, 0.585321f, 0.580982f, 0.57963f, 0.580866f, 0.585123f}, + {0.8619f, 0.804678f, 0.767553f, 0.740228f, 0.719376f, 0.702886f, 0.68916f, 0.676527f, 0.665539f, 0.658178f, 0.652959f, 0.650719f, 0.650971f, 0.654012f, 0.660239f, 0.670351f}, + {0.881182f, 0.828897f, 0.795305f, 0.771161f, 0.753987f, 0.741464f, 0.73213f, 0.724484f, 0.71928f, 0.71662f, 0.715945f, 0.71725f, 0.721061f, 0.727652f, 0.737836f, 0.752075f}, + {0.898328f, 0.849545f, 0.818445f, 0.798279f, 0.78526f, 0.777848f, 0.774228f, 0.772896f, 0.773319f, 0.775384f, 0.778796f, 0.783347f, 0.789071f, 0.797256f, 0.809091f, 0.8251f}, + {0.912492f, 0.865099f, 0.836682f, 0.820873f, 0.813947f, 0.813045f, 0.816107f, 0.820657f, 0.82658f, 0.832902f, 0.839364f, 0.845288f, 0.851083f, 0.858572f, 0.869737f, 0.885193f}, + {0.923206f, 0.875112f, 0.850108f, 0.841381f, 0.842447f, 0.849294f, 0.858589f, 0.868246f, 0.877387f, 0.885927f, 0.893229f, 0.899232f, 0.903716f, 0.908704f, 0.917536f, 0.930437f}, + {0.929416f, 0.879031f, 0.861479f, 0.863345f, 0.874394f, 0.888073f, 0.901441f, 0.913068f, 0.922679f, 0.930421f, 0.936747f, 0.94131f, 0.944077f, 0.946029f, 0.951657f, 0.961578f}, + {0.929961f, 0.879713f, 0.877021f, 0.892717f, 0.91156f, 0.928023f, 0.940969f, 0.950753f, 0.958077f, 0.963495f, 0.967515f, 0.970119f, 0.97154f, 0.971433f, 0.973997f, 0.980923f}, + {0.923813f, 0.88494f, 0.905293f, 0.930999f, 0.950162f, 0.963021f, 0.971522f, 0.977304f, 0.981213f, 0.984018f, 0.985846f, 0.987192f, 0.987814f, 0.986963f, 0.987549f, 0.991779f}, + {0.913577f, 0.909968f, 0.947136f, 0.968498f, 0.979824f, 0.98596f, 0.989639f, 0.991884f, 0.993358f, 0.994389f, 0.995062f, 0.995502f, 0.995694f, 0.995242f, 0.994964f, 0.997095f}, + {0.915225f, 0.957948f, 0.983091f, 0.991314f, 0.994726f, 0.996395f, 0.9974f, 0.997954f, 0.998351f, 0.998569f, 0.99875f, 0.998843f, 0.99892f, 0.998785f, 0.998458f, 0.999245f}, + {0.950438f, 0.99275f, 0.997626f, 0.998808f, 0.9993f, 0.999522f, 0.999649f, 0.999722f, 0.999765f, 0.9998f, 0.999817f, 0.999832f, 0.999842f, 0.999849f, 0.999771f, 0.999898f}, + {0.991403f, 0.999757f, 0.999897f, 0.999927f, 0.999939f, 0.999952f, 0.999961f, 0.999951f, 0.999969f, 0.999972f, 0.999966f, 0.99996f, 0.999974f, 0.999965f, 0.999964f, 0.999968f} + }, + { + {0.79705f, 0.707087f, 0.650125f, 0.608325f, 0.575656f, 0.547339f, 0.519517f, 0.490858f, 0.465293f, 0.442303f, 0.421886f, 0.403233f, 0.38683f, 0.372037f, 0.359003f, 0.347211f}, + {0.818406f, 0.736522f, 0.683598f, 0.644745f, 0.613662f, 0.5868f, 0.561474f, 0.535419f, 0.51204f, 0.492423f, 0.474782f, 0.459397f, 0.446089f, 0.434972f, 0.42572f, 0.417781f}, + {0.838915f, 0.76538f, 0.71697f, 0.680901f, 0.652404f, 0.627981f, 0.604879f, 0.582095f, 0.562335f, 0.545635f, 0.53178f, 0.520098f, 0.510837f, 0.503805f, 0.499364f, 0.496573f}, + {0.859427f, 0.792616f, 0.748843f, 0.71611f, 0.690565f, 0.66897f, 0.649153f, 0.630161f, 0.614583f, 0.601802f, 0.592015f, 0.584405f, 0.579516f, 0.577337f, 0.577881f, 0.581019f}, + {0.877941f, 0.817762f, 0.778341f, 0.74933f, 0.726722f, 0.70854f, 0.693008f, 0.678967f, 0.667968f, 0.660119f, 0.654418f, 0.651497f, 0.650648f, 0.653018f, 0.658252f, 0.666947f}, + {0.894946f, 0.839848f, 0.804323f, 0.778658f, 0.760117f, 0.746318f, 0.735719f, 0.727265f, 0.721936f, 0.718995f, 0.718274f, 0.719192f, 0.722341f, 0.727937f, 0.736645f, 0.749427f}, + {0.90937f, 0.858314f, 0.825635f, 0.804151f, 0.790096f, 0.781706f, 0.777206f, 0.775328f, 0.775831f, 0.7781f, 0.781525f, 0.785871f, 0.791006f, 0.798083f, 0.808513f, 0.823113f}, + {0.921259f, 0.871938f, 0.842067f, 0.825098f, 0.817405f, 0.815975f, 0.818193f, 0.822737f, 0.828566f, 0.83501f, 0.841897f, 0.847892f, 0.853643f, 0.860164f, 0.869398f, 0.883714f}, + {0.930002f, 0.880092f, 0.853777f, 0.84416f, 0.844764f, 0.851092f, 0.859958f, 0.869441f, 0.878832f, 0.887484f, 0.89514f, 0.901397f, 0.906208f, 0.9106f, 0.917304f, 0.929364f}, + {0.93434f, 0.882394f, 0.863801f, 0.865045f, 0.875658f, 0.889041f, 0.902161f, 0.913795f, 0.9235f, 0.931512f, 0.937785f, 0.942816f, 0.946137f, 0.948175f, 0.951499f, 0.960778f}, + {0.933288f, 0.881678f, 0.878297f, 0.893636f, 0.912242f, 0.928599f, 0.9414f, 0.951132f, 0.958467f, 0.963995f, 0.968187f, 0.971034f, 0.972905f, 0.973151f, 0.973816f, 0.980384f}, + {0.925808f, 0.885998f, 0.905907f, 0.931442f, 0.950453f, 0.963263f, 0.971733f, 0.977432f, 0.981437f, 0.984181f, 0.986101f, 0.987512f, 0.988453f, 0.988142f, 0.987422f, 0.991483f}, + {0.914584f, 0.910362f, 0.947376f, 0.968621f, 0.979921f, 0.986048f, 0.989702f, 0.991953f, 0.993416f, 0.994454f, 0.995204f, 0.995643f, 0.995904f, 0.995802f, 0.994945f, 0.996973f}, + {0.915627f, 0.958056f, 0.98316f, 0.991351f, 0.994752f, 0.996424f, 0.997426f, 0.997968f, 0.998351f, 0.998579f, 0.99877f, 0.998878f, 0.998955f, 0.998924f, 0.998463f, 0.999213f}, + {0.950525f, 0.99277f, 0.997636f, 0.998811f, 0.999304f, 0.999523f, 0.999655f, 0.999724f, 0.999768f, 0.999796f, 0.999833f, 0.999839f, 0.999859f, 0.999856f, 0.999769f, 0.999893f}, + {0.991407f, 0.999758f, 0.999897f, 0.999927f, 0.999939f, 0.999952f, 0.999961f, 0.999951f, 0.999969f, 0.999973f, 0.999967f, 0.99996f, 0.999976f, 0.999968f, 0.999965f, 0.999968f} + }, + { + {0.817657f, 0.723241f, 0.662787f, 0.617806f, 0.581707f, 0.549774f, 0.517554f, 0.487769f, 0.461541f, 0.43842f, 0.417691f, 0.399079f, 0.383059f, 0.368634f, 0.355749f, 0.34413f}, + {0.837002f, 0.751305f, 0.695682f, 0.653945f, 0.620295f, 0.590505f, 0.56115f, 0.534408f, 0.510693f, 0.490235f, 0.472319f, 0.45677f, 0.443685f, 0.432378f, 0.422948f, 0.414752f}, + {0.855837f, 0.77891f, 0.727936f, 0.689818f, 0.658997f, 0.632206f, 0.606236f, 0.582562f, 0.562559f, 0.545354f, 0.530933f, 0.518986f, 0.509504f, 0.502321f, 0.497312f, 0.493854f}, + {0.87425f, 0.804615f, 0.758634f, 0.724153f, 0.696774f, 0.673192f, 0.65101f, 0.631897f, 0.615946f, 0.602754f, 0.592606f, 0.584959f, 0.57949f, 0.57674f, 0.576506f, 0.578649f}, + {0.890419f, 0.827886f, 0.786812f, 0.756174f, 0.732164f, 0.712579f, 0.695441f, 0.681054f, 0.669964f, 0.66197f, 0.65612f, 0.652777f, 0.651928f, 0.653243f, 0.657598f, 0.664986f}, + {0.90543f, 0.848397f, 0.811216f, 0.784383f, 0.764677f, 0.749748f, 0.738095f, 0.729745f, 0.724129f, 0.721272f, 0.720688f, 0.721413f, 0.724267f, 0.729195f, 0.736498f, 0.747847f}, + {0.918058f, 0.865296f, 0.831113f, 0.808539f, 0.793531f, 0.784463f, 0.779086f, 0.777031f, 0.777935f, 0.780148f, 0.783813f, 0.788206f, 0.793626f, 0.799897f, 0.808777f, 0.821865f}, + {0.92817f, 0.877163f, 0.846146f, 0.828246f, 0.819912f, 0.81795f, 0.819629f, 0.824224f, 0.830215f, 0.836919f, 0.843879f, 0.850116f, 0.856108f, 0.862218f, 0.869877f, 0.882704f}, + {0.935269f, 0.883777f, 0.856602f, 0.846148f, 0.846328f, 0.852397f, 0.860816f, 0.8704f, 0.880012f, 0.888671f, 0.896505f, 0.903096f, 0.908467f, 0.912619f, 0.91797f, 0.928547f}, + {0.938124f, 0.884951f, 0.865568f, 0.866333f, 0.876638f, 0.889789f, 0.902716f, 0.914317f, 0.924097f, 0.932265f, 0.938791f, 0.943975f, 0.947756f, 0.949879f, 0.952018f, 0.960114f}, + {0.93579f, 0.883236f, 0.879279f, 0.894274f, 0.912769f, 0.928973f, 0.941669f, 0.951429f, 0.958813f, 0.964351f, 0.968547f, 0.971721f, 0.973799f, 0.974578f, 0.974338f, 0.979852f}, + {0.927364f, 0.886746f, 0.906354f, 0.931745f, 0.95066f, 0.963418f, 0.971877f, 0.977557f, 0.981557f, 0.984338f, 0.986312f, 0.987779f, 0.988855f, 0.989031f, 0.987891f, 0.991104f}, + {0.915345f, 0.910666f, 0.947524f, 0.968757f, 0.980016f, 0.986115f, 0.989741f, 0.991972f, 0.993453f, 0.994511f, 0.995276f, 0.995723f, 0.996041f, 0.996168f, 0.995255f, 0.996776f}, + {0.915938f, 0.958148f, 0.983201f, 0.991381f, 0.99478f, 0.996435f, 0.99744f, 0.997984f, 0.998355f, 0.998594f, 0.998779f, 0.998912f, 0.998993f, 0.999027f, 0.998616f, 0.99915f}, + {0.950581f, 0.992777f, 0.997638f, 0.998817f, 0.999309f, 0.999523f, 0.999654f, 0.999726f, 0.999771f, 0.999794f, 0.999827f, 0.999842f, 0.999862f, 0.999874f, 0.999802f, 0.999884f}, + {0.991412f, 0.999758f, 0.999897f, 0.999927f, 0.999939f, 0.999952f, 0.999961f, 0.999951f, 0.999969f, 0.999973f, 0.999967f, 0.99996f, 0.999975f, 0.999968f, 0.999966f, 0.999968f} + }, + { + {0.834262f, 0.736081f, 0.672702f, 0.625014f, 0.586161f, 0.550531f, 0.516081f, 0.486013f, 0.459502f, 0.435917f, 0.415263f, 0.39704f, 0.38115f, 0.366798f, 0.353983f, 0.342407f}, + {0.851862f, 0.763193f, 0.705094f, 0.661069f, 0.625188f, 0.592424f, 0.560815f, 0.533871f, 0.510054f, 0.489451f, 0.471438f, 0.455787f, 0.442738f, 0.431341f, 0.421574f, 0.413145f}, + {0.869257f, 0.789477f, 0.736528f, 0.696478f, 0.663679f, 0.634635f, 0.606979f, 0.583289f, 0.563214f, 0.545723f, 0.531246f, 0.519275f, 0.50954f, 0.501924f, 0.496418f, 0.49241f}, + {0.885878f, 0.814001f, 0.766181f, 0.730203f, 0.701311f, 0.675861f, 0.652699f, 0.63334f, 0.617329f, 0.604181f, 0.594001f, 0.585954f, 0.580486f, 0.577284f, 0.576186f, 0.577435f}, + {0.900284f, 0.835873f, 0.793276f, 0.761237f, 0.736218f, 0.715139f, 0.697124f, 0.682916f, 0.671961f, 0.663839f, 0.657969f, 0.654832f, 0.65357f, 0.654377f, 0.65769f, 0.664005f}, + {0.913773f, 0.855093f, 0.816642f, 0.78864f, 0.76792f, 0.751972f, 0.739652f, 0.731461f, 0.726004f, 0.723444f, 0.722722f, 0.723692f, 0.72628f, 0.730495f, 0.737157f, 0.747096f}, + {0.924899f, 0.870493f, 0.835283f, 0.811765f, 0.795979f, 0.786153f, 0.780495f, 0.778662f, 0.77946f, 0.782012f, 0.785891f, 0.790644f, 0.795793f, 0.801773f, 0.809674f, 0.821251f}, + {0.933694f, 0.881228f, 0.849145f, 0.830641f, 0.821706f, 0.819135f, 0.820668f, 0.825357f, 0.831337f, 0.838222f, 0.845529f, 0.852179f, 0.858367f, 0.864221f, 0.870816f, 0.882142f}, + {0.939375f, 0.88676f, 0.858762f, 0.847718f, 0.847456f, 0.853243f, 0.861524f, 0.87118f, 0.880766f, 0.889638f, 0.897678f, 0.90467f, 0.910191f, 0.914583f, 0.918902f, 0.928033f}, + {0.941125f, 0.886904f, 0.866931f, 0.867285f, 0.877266f, 0.890242f, 0.903113f, 0.914783f, 0.924603f, 0.932848f, 0.939544f, 0.944953f, 0.948932f, 0.951516f, 0.952998f, 0.959612f}, + {0.937776f, 0.884404f, 0.880006f, 0.89478f, 0.91314f, 0.929183f, 0.94187f, 0.951681f, 0.959063f, 0.964666f, 0.968907f, 0.972145f, 0.97442f, 0.975584f, 0.975366f, 0.979376f}, + {0.92858f, 0.887323f, 0.906695f, 0.931937f, 0.950831f, 0.963534f, 0.971975f, 0.977659f, 0.981644f, 0.984444f, 0.986487f, 0.988046f, 0.989126f, 0.989509f, 0.988619f, 0.990707f}, + {0.915996f, 0.910913f, 0.947682f, 0.968833f, 0.98007f, 0.986144f, 0.98975f, 0.992f, 0.993487f, 0.994564f, 0.995305f, 0.995811f, 0.99615f, 0.996282f, 0.995737f, 0.996513f}, + {0.916171f, 0.958214f, 0.983234f, 0.99141f, 0.994796f, 0.996442f, 0.997449f, 0.997982f, 0.998363f, 0.99861f, 0.998803f, 0.998928f, 0.999017f, 0.99905f, 0.998836f, 0.999022f}, + {0.950623f, 0.992779f, 0.997641f, 0.998824f, 0.999312f, 0.999527f, 0.999656f, 0.999725f, 0.999771f, 0.999797f, 0.999835f, 0.999839f, 0.999864f, 0.999876f, 0.999835f, 0.999855f}, + {0.991415f, 0.999758f, 0.999897f, 0.999927f, 0.999939f, 0.999952f, 0.999961f, 0.999951f, 0.999969f, 0.999973f, 0.999967f, 0.999959f, 0.999976f, 0.999967f, 0.999968f, 0.999967f} + } +}; + +static const float table_sheen_E[32][32] = { + {0.943446f, 0.829183f, 0.758593f, 0.701678f, 0.65437f, 0.613853f, 0.578324f, 0.546567f, 0.517736f, 0.491244f, 0.466677f, 0.443702f, 0.422089f, 0.401649f, 0.382255f, 0.363786f, 0.346264f, 0.329937f, 0.3147f, 0.300355f, 0.286744f, 0.273754f, 0.2613f, 0.249303f, 0.237713f, 0.22648f, 0.215584f, 0.204988f, 0.194684f, 0.184666f, 0.174931f, 0.165459f}, + {0.943527f, 0.825942f, 0.755178f, 0.698084f, 0.650598f, 0.609906f, 0.574227f, 0.542291f, 0.513309f, 0.486677f, 0.461965f, 0.438862f, 0.417121f, 0.396567f, 0.377068f, 0.358499f, 0.340878f, 0.324466f, 0.309131f, 0.294691f, 0.280993f, 0.267918f, 0.255377f, 0.243296f, 0.231623f, 0.220311f, 0.209329f, 0.198659f, 0.188276f, 0.178176f, 0.168359f, 0.158801f}, + {0.94159f, 0.822574f, 0.751611f, 0.694328f, 0.646623f, 0.60574f, 0.569858f, 0.537753f, 0.508596f, 0.481807f, 0.456942f, 0.433696f, 0.411825f, 0.391151f, 0.371534f, 0.352855f, 0.335132f, 0.318621f, 0.3032f, 0.288665f, 0.274878f, 0.261717f, 0.249088f, 0.236925f, 0.22517f, 0.213775f, 0.20272f, 0.191969f, 0.181514f, 0.171338f, 0.16144f, 0.151807f}, + {0.947645f, 0.819075f, 0.747871f, 0.690367f, 0.642425f, 0.601337f, 0.565226f, 0.532917f, 0.503575f, 0.476605f, 0.451569f, 0.428174f, 0.406162f, 0.38536f, 0.365618f, 0.346832f, 0.329003f, 0.312389f, 0.296871f, 0.282243f, 0.268367f, 0.255119f, 0.242405f, 0.230161f, 0.218327f, 0.206862f, 0.195731f, 0.18491f, 0.174385f, 0.16414f, 0.154173f, 0.144472f}, + {0.931949f, 0.815488f, 0.744024f, 0.6862f, 0.637992f, 0.596647f, 0.560271f, 0.527753f, 0.498193f, 0.471027f, 0.445819f, 0.42226f, 0.400092f, 0.379144f, 0.359283f, 0.340377f, 0.322447f, 0.305737f, 0.290118f, 0.275394f, 0.261429f, 0.248096f, 0.2353f, 0.222984f, 0.211078f, 0.199541f, 0.188343f, 0.177461f, 0.166877f, 0.156573f, 0.146546f, 0.136784f}, + {0.927251f, 0.811799f, 0.739918f, 0.681784f, 0.633273f, 0.591611f, 0.554994f, 0.522205f, 0.492415f, 0.46504f, 0.439642f, 0.415899f, 0.393569f, 0.37248f, 0.35248f, 0.333463f, 0.31542f, 0.298607f, 0.282892f, 0.268086f, 0.254031f, 0.240616f, 0.227752f, 0.21536f, 0.203389f, 0.191793f, 0.180542f, 0.169607f, 0.158972f, 0.148623f, 0.138553f, 0.128751f}, + {0.944949f, 0.807898f, 0.735619f, 0.677107f, 0.62824f, 0.586245f, 0.549329f, 0.516248f, 0.486213f, 0.458594f, 0.432987f, 0.40905f, 0.386553f, 0.365305f, 0.345168f, 0.326027f, 0.307882f, 0.290974f, 0.27516f, 0.260268f, 0.246135f, 0.232649f, 0.219716f, 0.207267f, 0.195241f, 0.183598f, 0.172308f, 0.161336f, 0.15067f, 0.140293f, 0.130202f, 0.120373f}, + {0.926739f, 0.803886f, 0.73108f, 0.672099f, 0.622817f, 0.580449f, 0.543192f, 0.509824f, 0.479494f, 0.451625f, 0.425779f, 0.401649f, 0.378978f, 0.357567f, 0.337293f, 0.318033f, 0.299781f, 0.28278f, 0.266884f, 0.251909f, 0.237707f, 0.224155f, 0.211166f, 0.198674f, 0.186609f, 0.174943f, 0.163621f, 0.152637f, 0.141963f, 0.131588f, 0.121493f, 0.111675f}, + {0.919685f, 0.799638f, 0.72623f, 0.666732f, 0.616988f, 0.574212f, 0.536564f, 0.502848f, 0.472221f, 0.444071f, 0.417988f, 0.393637f, 0.370768f, 0.349201f, 0.328791f, 0.30941f, 0.291068f, 0.273971f, 0.258004f, 0.242962f, 0.228693f, 0.215099f, 0.202076f, 0.189557f, 0.17748f, 0.165797f, 0.154488f, 0.143513f, 0.132859f, 0.12251f, 0.112452f, 0.102663f}, + {0.921379f, 0.795163f, 0.720993f, 0.660933f, 0.610687f, 0.567427f, 0.529359f, 0.49527f, 0.464308f, 0.435861f, 0.409513f, 0.38494f, 0.361875f, 0.340136f, 0.319589f, 0.300094f, 0.281665f, 0.2645f, 0.248462f, 0.233371f, 0.219069f, 0.205448f, 0.192409f, 0.179886f, 0.167823f, 0.156167f, 0.144891f, 0.133964f, 0.123368f, 0.113088f, 0.103106f, 0.0934057f}, + {0.912241f, 0.790311f, 0.715419f, 0.654675f, 0.603798f, 0.560013f, 0.521488f, 0.486989f, 0.455643f, 0.426892f, 0.400276f, 0.375458f, 0.352193f, 0.330302f, 0.309625f, 0.290033f, 0.271525f, 0.2543f, 0.238222f, 0.223103f, 0.208785f, 0.195163f, 0.182143f, 0.169651f, 0.15763f, 0.146039f, 0.134842f, 0.124007f, 0.113516f, 0.103354f, 0.0935006f, 0.0839435f}, + {0.91345f, 0.785198f, 0.70931f, 0.64782f, 0.596253f, 0.551881f, 0.512834f, 0.477892f, 0.446165f, 0.417072f, 0.390154f, 0.365109f, 0.341651f, 0.319601f, 0.2988f, 0.279133f, 0.260575f, 0.243316f, 0.227216f, 0.212098f, 0.197803f, 0.184217f, 0.171254f, 0.158835f, 0.146906f, 0.135426f, 0.124352f, 0.113664f, 0.103339f, 0.0933538f, 0.0836994f, 0.0743491f}, + {0.917381f, 0.779585f, 0.70264f, 0.640234f, 0.587942f, 0.542923f, 0.503322f, 0.467867f, 0.435732f, 0.406285f, 0.379066f, 0.353768f, 0.330129f, 0.307935f, 0.287036f, 0.267313f, 0.248731f, 0.231476f, 0.215402f, 0.200323f, 0.186083f, 0.172584f, 0.159726f, 0.147435f, 0.135657f, 0.124347f, 0.113469f, 0.102992f, 0.092898f, 0.0831719f, 0.0737889f, 0.0647255f}, + {0.9016f, 0.773416f, 0.695288f, 0.631867f, 0.578743f, 0.532989f, 0.492754f, 0.456782f, 0.424198f, 0.394388f, 0.366874f, 0.341344f, 0.317524f, 0.295205f, 0.274237f, 0.254489f, 0.235933f, 0.218722f, 0.202718f, 0.187724f, 0.173608f, 0.160244f, 0.147555f, 0.135463f, 0.123904f, 0.112837f, 0.102231f, 0.0920529f, 0.0822744f, 0.072887f, 0.0638682f, 0.0551924f}, + {0.89597f, 0.766728f, 0.687074f, 0.622508f, 0.568442f, 0.521924f, 0.481014f, 0.444465f, 0.411431f, 0.381233f, 0.353424f, 0.327669f, 0.303705f, 0.2813f, 0.260303f, 0.240585f, 0.222097f, 0.204991f, 0.189117f, 0.174291f, 0.160361f, 0.147219f, 0.134768f, 0.122952f, 0.1117f, 0.100963f, 0.0907206f, 0.0809338f, 0.0715818f, 0.0626399f, 0.0540926f, 0.0459167f}, + {0.889611f, 0.759066f, 0.677879f, 0.612037f, 0.556915f, 0.5095f, 0.467866f, 0.43074f, 0.397213f, 0.366648f, 0.338564f, 0.312623f, 0.288544f, 0.266104f, 0.245138f, 0.225512f, 0.207174f, 0.190249f, 0.174593f, 0.160007f, 0.146351f, 0.133517f, 0.12141f, 0.10996f, 0.0991205f, 0.0888212f, 0.079053f, 0.0697677f, 0.0609446f, 0.0525649f, 0.0446104f, 0.0370559f}, + {0.88571f, 0.750491f, 0.667413f, 0.600153f, 0.543867f, 0.495509f, 0.453121f, 0.415381f, 0.381383f, 0.350454f, 0.322136f, 0.296045f, 0.271906f, 0.249507f, 0.228655f, 0.209217f, 0.19112f, 0.17448f, 0.159124f, 0.144888f, 0.13162f, 0.119201f, 0.107552f, 0.096592f, 0.0862693f, 0.0765452f, 0.0673689f, 0.0587079f, 0.0505464f, 0.0428553f, 0.03562f, 0.0288094f}, + {0.881187f, 0.740717f, 0.655493f, 0.586624f, 0.529056f, 0.479691f, 0.436498f, 0.398131f, 0.36368f, 0.332435f, 0.30394f, 0.277786f, 0.25368f, 0.231415f, 0.21078f, 0.191636f, 0.173914f, 0.157676f, 0.142762f, 0.129006f, 0.116246f, 0.104388f, 0.093325f, 0.0829933f, 0.0733365f, 0.064305f, 0.0558577f, 0.0479562f, 0.0405888f, 0.0337189f, 0.0273257f, 0.0213849f}, + {0.871552f, 0.729423f, 0.641759f, 0.571064f, 0.51215f, 0.461717f, 0.417699f, 0.378747f, 0.343881f, 0.312389f, 0.28379f, 0.257688f, 0.23375f, 0.211747f, 0.191478f, 0.172789f, 0.15559f, 0.139922f, 0.125599f, 0.112475f, 0.10039f, 0.089234f, 0.078919f, 0.0693676f, 0.0605158f, 0.0523276f, 0.0447506f, 0.037752f, 0.0313042f, 0.0253749f, 0.019938f, 0.0149783f}, + {0.862202f, 0.71629f, 0.625816f, 0.553169f, 0.492726f, 0.441201f, 0.396405f, 0.356893f, 0.321718f, 0.290114f, 0.261572f, 0.235654f, 0.212044f, 0.190491f, 0.170786f, 0.15274f, 0.136254f, 0.12133f, 0.107812f, 0.0955063f, 0.0842785f, 0.0740051f, 0.0645986f, 0.0559841f, 0.0481095f, 0.0409034f, 0.0343314f, 0.0283543f, 0.0229354f, 0.0180445f, 0.0136542f, 0.00973637f}, + {0.854242f, 0.700808f, 0.607223f, 0.53239f, 0.470404f, 0.417759f, 0.372242f, 0.332304f, 0.296972f, 0.265426f, 0.237128f, 0.211624f, 0.188581f, 0.167724f, 0.148806f, 0.131644f, 0.116108f, 0.102177f, 0.0896697f, 0.0783904f, 0.0682186f, 0.0590272f, 0.0507134f, 0.0432071f, 0.036439f, 0.0303554f, 0.0249063f, 0.0200439f, 0.0157306f, 0.0119318f, 0.00861227f, 0.00574364f}, + {0.849415f, 0.682471f, 0.585377f, 0.508187f, 0.444628f, 0.390946f, 0.344851f, 0.304708f, 0.269428f, 0.238205f, 0.210447f, 0.185652f, 0.163483f, 0.143608f, 0.125798f, 0.109808f, 0.0955169f, 0.0828409f, 0.0715812f, 0.0615731f, 0.052665f, 0.0447368f, 0.03769f, 0.0314372f, 0.0259102f, 0.0210422f, 0.0167823f, 0.0130802f, 0.00988758f, 0.00716571f, 0.00487594f, 0.00298292f}, + {0.826131f, 0.66057f, 0.559653f, 0.479971f, 0.41487f, 0.360302f, 0.313872f, 0.273805f, 0.238939f, 0.208449f, 0.181598f, 0.157936f, 0.137028f, 0.11853f, 0.102173f, 0.0877084f, 0.0749816f, 0.063839f, 0.0541136f, 0.0455908f, 0.0381677f, 0.0316713f, 0.0260305f, 0.0211355f, 0.016916f, 0.0133054f, 0.0102383f, 0.0076575f, 0.00552056f, 0.00377583f, 0.00238132f, 0.00129849f}, + {0.812095f, 0.634496f, 0.529093f, 0.44694f, 0.380486f, 0.325406f, 0.279036f, 0.239517f, 0.205614f, 0.176316f, 0.150927f, 0.128895f, 0.109726f, 0.0930842f, 0.0786069f, 0.0660483f, 0.0552158f, 0.0459069f, 0.0379652f, 0.0311522f, 0.0253495f, 0.0204161f, 0.0162403f, 0.0127359f, 0.00981095f, 0.00739878f, 0.00543373f, 0.003856f, 0.00261187f, 0.00165708f, 0.000946434f, 0.000443164f}, + {0.794071f, 0.603171f, 0.493023f, 0.408376f, 0.340973f, 0.285893f, 0.240198f, 0.201957f, 0.169687f, 0.142314f, 0.119063f, 0.0992952f, 0.0824592f, 0.0681709f, 0.0560355f, 0.0457793f, 0.0371415f, 0.0299437f, 0.0239457f, 0.0189681f, 0.0148637f, 0.0115041f, 0.00876013f, 0.00655424f, 0.00479841f, 0.0034206f, 0.00235615f, 0.00155722f, 0.000970439f, 0.000556371f, 0.000278639f, 0.000105997f}, + {0.763979f, 0.565522f, 0.450168f, 0.363447f, 0.295723f, 0.241536f, 0.197573f, 0.161537f, 0.131902f, 0.107384f, 0.087099f, 0.0703382f, 0.0564711f, 0.0450734f, 0.0357098f, 0.0280724f, 0.0218626f, 0.0168724f, 0.0128856f, 0.00972834f, 0.00723374f, 0.00529015f, 0.00379385f, 0.00265875f, 0.00181094f, 0.00119149f, 0.000752846f, 0.000450051f, 0.000249434f, 0.000123833f, 5.16742e-05f, 1.48307e-05f}, + {0.736436f, 0.520102f, 0.399499f, 0.311411f, 0.244558f, 0.192643f, 0.151786f, 0.11939f, 0.0936107f, 0.0730717f, 0.0567342f, 0.0437701f, 0.0335016f, 0.0254089f, 0.0190926f, 0.0141879f, 0.0104086f, 0.0075515f, 0.00539284f, 0.00378805f, 0.00261317f, 0.00175799f, 0.00115495f, 0.000735692f, 0.000449918f, 0.00026424f, 0.000146425f, 7.54017e-05f, 3.52908e-05f, 1.42643e-05f, 4.57858e-06f, 8.81577e-07f}, + {0.700224f, 0.465658f, 0.339632f, 0.251689f, 0.187643f, 0.140115f, 0.104474f, 0.0775548f, 0.0572586f, 0.0419565f, 0.0304561f, 0.0219111f, 0.0155727f, 0.0109402f, 0.00756375f, 0.00515542f, 0.00344945f, 0.00226989f, 0.00145839f, 0.000917069f, 0.000562676f, 0.000333521f, 0.000190339f, 0.000104056f, 5.46174e-05f, 2.66385e-05f, 1.20736e-05f, 4.9736e-06f, 1.76633e-06f, 5.29699e-07f, 1.10831e-07f, 1.21185e-08f}, + {0.663667f, 0.399957f, 0.269205f, 0.184027f, 0.126383f, 0.086515f, 0.0589411f, 0.0397684f, 0.0265884f, 0.0175079f, 0.011371f, 0.00726631f, 0.00457177f, 0.00281099f, 0.00169641f, 0.000999952f, 0.00057396f, 0.000321279f, 0.000173225f, 9.0491e-05f, 4.5631e-05f, 2.18649e-05f, 9.83801e-06f, 4.21215e-06f, 1.68447e-06f, 6.02285e-07f, 1.97599e-07f, 5.49234e-08f, 1.23614e-08f, 2.1325e-09f, 2.28753e-10f, 9.38201e-12f}, + {0.627924f, 0.318773f, 0.185733f, 0.109707f, 0.0645309f, 0.037627f, 0.0216008f, 0.0121971f, 0.00673593f, 0.00363777f, 0.00192611f, 0.000980903f, 0.000492178f, 0.000238301f, 0.000111442f, 5.00866e-05f, 2.15714e-05f, 8.99007e-06f, 3.42523e-06f, 1.26682e-06f, 4.34498e-07f, 1.37677e-07f, 3.95201e-08f, 1.02132e-08f, 2.45011e-09f, 4.75872e-10f, 7.71094e-11f, 9.70048e-12f, 8.28134e-13f, 4.82864e-14f, 1.24283e-15f, 6.80699e-18f}, + {0.602571f, 0.208486f, 0.086843f, 0.0363861f, 0.0150805f, 0.00613398f, 0.00243117f, 0.000935378f, 0.000340054f, 0.000120725f, 3.98771e-05f, 1.26402e-05f, 3.65801e-06f, 1.02043e-06f, 2.51742e-07f, 5.80963e-08f, 1.22453e-08f, 2.34199e-09f, 3.72857e-10f, 5.74371e-11f, 7.22338e-12f, 6.44319e-13f, 6.22934e-14f, 3.85108e-15f, 1.89348e-16f, 8.59175e-18f, 1.95153e-19f, 2.63448e-21f, 1.71356e-23f, 5.21569e-26f, 2.13312e-29f, 4.3595e-34f}, + {0.591225f, 0.045818f, 0.00732363f, 0.00112657f, 0.000170285f, 2.07311e-05f, 2.37514e-06f, 1.86339e-07f, 1.1563e-08f, 7.84983e-10f, 2.46995e-11f, 1.01276e-12f, 2.0924e-14f, 2.83508e-16f, 7.15504e-18f, 2.95273e-20f, 8.42547e-23f, 2.83875e-25f, 9.54702e-28f, 5.32362e-31f, 4.20998e-34f, 1.43471e-37f, 3.92305e-40f, 1.4013e-45f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f} +}; + +static const float table_ggx_dielectric_E[16][16][16] = { + { + {0.000833139f, 0.000739042f, 0.000661531f, 0.00058659f, 0.000504253f, 0.000429894f, 0.00034459f, 0.000248786f, 0.000130008f, 4.30204e-05f, 1.54746e-05f, 7.03338e-06f, 3.85273e-06f, 2.39524e-06f, 1.67518e-06f, 1.27851e-06f}, + {0.000971227f, 0.000870615f, 0.000791253f, 0.000703758f, 0.000616392f, 0.000533401f, 0.000428542f, 0.000310971f, 0.000162786f, 5.49843e-05f, 1.97338e-05f, 8.86372e-06f, 4.74838e-06f, 2.90918e-06f, 2.0109e-06f, 1.53578e-06f}, + {0.00117122f, 0.00106393f, 0.000977222f, 0.00087564f, 0.000762933f, 0.000667494f, 0.000542036f, 0.000394954f, 0.000209898f, 7.17009e-05f, 2.53486e-05f, 1.11729e-05f, 5.8894e-06f, 3.51212e-06f, 2.38932e-06f, 1.82166e-06f}, + {0.00145307f, 0.00132647f, 0.00123762f, 0.00111287f, 0.00098268f, 0.000850916f, 0.000704074f, 0.000520591f, 0.000278186f, 9.42205e-05f, 3.27689e-05f, 1.42655e-05f, 7.27467e-06f, 4.21994e-06f, 2.79021e-06f, 2.1252e-06f}, + {0.00187665f, 0.00174242f, 0.0015913f, 0.00147f, 0.0012994f, 0.00112776f, 0.000939697f, 0.000694948f, 0.000375119f, 0.000126431f, 4.36664e-05f, 1.83223e-05f, 8.92567e-06f, 5.04081e-06f, 3.22432e-06f, 2.41999e-06f}, + {0.00250117f, 0.00231726f, 0.00215006f, 0.00194379f, 0.00174525f, 0.00153672f, 0.00127908f, 0.000963896f, 0.000518268f, 0.000174377f, 5.81443e-05f, 2.35887e-05f, 1.10161e-05f, 5.88478e-06f, 3.6355e-06f, 2.68866e-06f}, + {0.00344393f, 0.00321262f, 0.00297996f, 0.00275639f, 0.00248222f, 0.00219712f, 0.00181121f, 0.00136085f, 0.000733074f, 0.000241602f, 7.79961e-05f, 3.03e-05f, 1.34434e-05f, 6.78013e-06f, 4.01359e-06f, 2.90952e-06f}, + {0.00502222f, 0.00468816f, 0.00437739f, 0.00400831f, 0.00363854f, 0.00321053f, 0.00268791f, 0.00200402f, 0.00107331f, 0.000344745f, 0.000105866f, 3.84394e-05f, 1.60633e-05f, 7.58774e-06f, 4.30163e-06f, 3.08396e-06f}, + {0.00760919f, 0.00717899f, 0.00670281f, 0.0061924f, 0.00560971f, 0.00490708f, 0.00410922f, 0.00307884f, 0.00162484f, 0.000500342f, 0.000142486f, 4.77747e-05f, 1.83874e-05f, 8.12365e-06f, 4.43344e-06f, 3.16708e-06f}, + {0.0123334f, 0.0115619f, 0.0108044f, 0.00999222f, 0.00902f, 0.00794271f, 0.00664624f, 0.00491208f, 0.0025462f, 0.00073129f, 0.000187547f, 5.68591e-05f, 2.01069e-05f, 8.37956e-06f, 4.43916e-06f, 3.20476e-06f}, + {0.0210496f, 0.0198311f, 0.0185466f, 0.0170842f, 0.0154773f, 0.0135819f, 0.0112714f, 0.0082633f, 0.00412282f, 0.001059f, 0.000235039f, 6.366e-05f, 2.06888e-05f, 8.23859e-06f, 4.33161e-06f, 3.1942e-06f}, + {0.0385231f, 0.036234f, 0.0338544f, 0.031228f, 0.0282111f, 0.0246418f, 0.0203127f, 0.0146674f, 0.00682645f, 0.00148063f, 0.00027352f, 6.59662e-05f, 2.02234e-05f, 7.8928e-06f, 4.18144e-06f, 3.16758e-06f}, + {0.0750848f, 0.0708705f, 0.0661296f, 0.0607573f, 0.0547065f, 0.0476295f, 0.0388318f, 0.0269979f, 0.0111858f, 0.00187513f, 0.000285965f, 6.43457e-05f, 1.91992e-05f, 7.45021e-06f, 4.03854e-06f, 3.15126e-06f}, + {0.156612f, 0.147597f, 0.13748f, 0.12619f, 0.113024f, 0.0970109f, 0.0768087f, 0.0495397f, 0.0165158f, 0.00206221f, 0.000279698f, 6.11915e-05f, 1.82972e-05f, 7.16881e-06f, 3.94998e-06f, 3.12396e-06f}, + {0.339907f, 0.318571f, 0.297574f, 0.271907f, 0.238398f, 0.195571f, 0.142549f, 0.0791503f, 0.0199063f, 0.00204778f, 0.000270804f, 5.93819e-05f, 1.77928e-05f, 7.02194e-06f, 3.91683e-06f, 3.12036e-06f}, + {0.716349f, 0.663103f, 0.590735f, 0.503601f, 0.407083f, 0.305267f, 0.200609f, 0.097081f, 0.0203857f, 0.00201006f, 0.000266758f, 5.87193e-05f, 1.76699e-05f, 6.99297e-06f, 3.90627e-06f, 3.11936e-06f} + }, + { + {0.0054489f, 0.00482758f, 0.00430475f, 0.00381337f, 0.00332831f, 0.00284381f, 0.00234429f, 0.00180105f, 0.00123002f, 0.000687392f, 0.000346588f, 0.000182707f, 0.000107221f, 6.96051e-05f, 4.98454e-05f, 3.86404e-05f}, + {0.00632047f, 0.00566836f, 0.00509984f, 0.00456772f, 0.0040243f, 0.00345987f, 0.00287984f, 0.00223329f, 0.00152974f, 0.000867574f, 0.000435897f, 0.00022754f, 0.000131303f, 8.41223e-05f, 5.97612e-05f, 4.64033e-05f}, + {0.00751868f, 0.00683849f, 0.00621179f, 0.00557888f, 0.00494806f, 0.00430001f, 0.0035993f, 0.00281247f, 0.00194378f, 0.00110538f, 0.000552399f, 0.000284381f, 0.00016138f, 0.000101163f, 7.08287e-05f, 5.49811e-05f}, + {0.00917018f, 0.00839765f, 0.00770217f, 0.00698923f, 0.00622979f, 0.00543909f, 0.00457211f, 0.00360984f, 0.00251132f, 0.00142492f, 0.000707093f, 0.00035873f, 0.000198194f, 0.000120952f, 8.2766e-05f, 6.40531e-05f}, + {0.0115296f, 0.0106853f, 0.00981214f, 0.00896792f, 0.00803715f, 0.00704736f, 0.00596575f, 0.00472702f, 0.00330195f, 0.00187294f, 0.000920679f, 0.000455649f, 0.000242469f, 0.000143645f, 9.54207e-05f, 7.30283e-05f}, + {0.0149886f, 0.0139356f, 0.0128885f, 0.0117971f, 0.0106259f, 0.00938115f, 0.00797168f, 0.00632205f, 0.00442635f, 0.00250747f, 0.00120767f, 0.000579839f, 0.00029674f, 0.000167605f, 0.000107637f, 8.1211e-05f}, + {0.020083f, 0.0187734f, 0.0174339f, 0.0160347f, 0.0144876f, 0.0128035f, 0.0108938f, 0.00868579f, 0.00605735f, 0.00339308f, 0.00159783f, 0.000738063f, 0.000359774f, 0.000192457f, 0.000118643f, 8.79938e-05f}, + {0.0279459f, 0.026192f, 0.0244034f, 0.0224763f, 0.0203525f, 0.0180162f, 0.0153666f, 0.0122229f, 0.00848837f, 0.00467733f, 0.00212656f, 0.000930591f, 0.000427272f, 0.000215171f, 0.000127045f, 9.31421e-05f}, + {0.0402593f, 0.0378179f, 0.0353093f, 0.0325471f, 0.0295181f, 0.0261582f, 0.0222662f, 0.0176824f, 0.0121424f, 0.00652877f, 0.00281585f, 0.00114965f, 0.000489492f, 0.000230955f, 0.000131329f, 9.59171e-05f}, + {0.0600786f, 0.0565731f, 0.0528449f, 0.0487969f, 0.0442528f, 0.0391631f, 0.0332573f, 0.0261877f, 0.0177251f, 0.00912576f, 0.00365579f, 0.00136535f, 0.000536541f, 0.00023833f, 0.00013182f, 9.71272e-05f}, + {0.0926893f, 0.0874447f, 0.0816981f, 0.0754352f, 0.0684505f, 0.0603947f, 0.0510103f, 0.0397201f, 0.0261436f, 0.0125808f, 0.00453719f, 0.00153327f, 0.000555563f, 0.000235702f, 0.000129202f, 9.69834e-05f}, + {0.147257f, 0.139052f, 0.129869f, 0.119935f, 0.108499f, 0.0953123f, 0.079793f, 0.060981f, 0.0381665f, 0.0166025f, 0.00526269f, 0.00160539f, 0.000548524f, 0.000227108f, 0.000125193f, 9.63345e-05f}, + {0.238632f, 0.225199f, 0.210292f, 0.193614f, 0.174596f, 0.152403f, 0.125454f, 0.0919936f, 0.0528787f, 0.0200386f, 0.00558471f, 0.00158949f, 0.000526298f, 0.000216321f, 0.00012142f, 9.57553e-05f}, + {0.387215f, 0.363624f, 0.339193f, 0.312425f, 0.279986f, 0.238885f, 0.187623f, 0.126957f, 0.064932f, 0.0216823f, 0.00558656f, 0.00153846f, 0.000505618f, 0.000208917f, 0.000118933f, 9.51526e-05f}, + {0.601368f, 0.565664f, 0.532116f, 0.480309f, 0.410484f, 0.327764f, 0.238057f, 0.148055f, 0.0696973f, 0.0218727f, 0.00549581f, 0.00150288f, 0.000493932f, 0.000205215f, 0.000117959f, 9.50296e-05f}, + {0.850891f, 0.788596f, 0.690268f, 0.580937f, 0.469289f, 0.358751f, 0.251714f, 0.152438f, 0.0702474f, 0.0217677f, 0.00544833f, 0.00149152f, 0.000491073f, 0.000204302f, 0.000117631f, 9.49407e-05f} + }, + { + {0.0134773f, 0.0119334f, 0.0106402f, 0.00943146f, 0.00827477f, 0.00712604f, 0.00598572f, 0.00480555f, 0.00362505f, 0.00248347f, 0.00156394f, 0.000964066f, 0.000620601f, 0.000427409f, 0.000317538f, 0.000252033f}, + {0.0154715f, 0.0138684f, 0.0124784f, 0.0111661f, 0.00987902f, 0.00856818f, 0.00725332f, 0.00586758f, 0.00444672f, 0.00306948f, 0.00193197f, 0.00118275f, 0.000752525f, 0.000513362f, 0.000379663f, 0.000302407f}, + {0.018133f, 0.0164694f, 0.014946f, 0.0134629f, 0.011988f, 0.01048f, 0.00892565f, 0.00727173f, 0.00553599f, 0.0038303f, 0.00240588f, 0.00145722f, 0.000914262f, 0.000613295f, 0.000448658f, 0.000357988f}, + {0.0217691f, 0.0199308f, 0.0182436f, 0.0165531f, 0.0148152f, 0.0130371f, 0.0111501f, 0.00914209f, 0.00699686f, 0.00483563f, 0.00302397f, 0.00180912f, 0.00111084f, 0.000728306f, 0.0005233f, 0.000416705f}, + {0.0268022f, 0.0247771f, 0.0227878f, 0.0208044f, 0.0187235f, 0.0165533f, 0.0142274f, 0.0116998f, 0.00897598f, 0.00620667f, 0.00384934f, 0.00226023f, 0.00134572f, 0.000858441f, 0.00060167f, 0.0004751f}, + {0.0339414f, 0.0315519f, 0.0291755f, 0.0267461f, 0.0241738f, 0.0214679f, 0.0185015f, 0.0152512f, 0.0117175f, 0.00808103f, 0.00494193f, 0.00283123f, 0.0016288f, 0.000997006f, 0.00067781f, 0.000528645f}, + {0.0441083f, 0.0412223f, 0.0382958f, 0.0352252f, 0.0319457f, 0.0284347f, 0.0245693f, 0.0202935f, 0.0155534f, 0.0106412f, 0.00639801f, 0.00354955f, 0.00195491f, 0.00113935f, 0.000746232f, 0.000573412f}, + {0.0590103f, 0.055343f, 0.0515593f, 0.0475658f, 0.0432285f, 0.0385148f, 0.0333405f, 0.0274946f, 0.0209867f, 0.0141888f, 0.00831519f, 0.00441743f, 0.00230368f, 0.00127026f, 0.00079906f, 0.000607241f}, + {0.081026f, 0.0761906f, 0.071196f, 0.065735f, 0.0598391f, 0.0533955f, 0.0461258f, 0.0379552f, 0.0287092f, 0.0190676f, 0.0107546f, 0.00539737f, 0.00263185f, 0.00136538f, 0.000828535f, 0.000626811f}, + {0.113957f, 0.107471f, 0.100498f, 0.0929509f, 0.0846462f, 0.0754061f, 0.0650015f, 0.0531292f, 0.0396794f, 0.0255514f, 0.0136604f, 0.00636976f, 0.00288726f, 0.00141338f, 0.000835217f, 0.000635768f}, + {0.163512f, 0.154467f, 0.144593f, 0.133784f, 0.121783f, 0.10823f, 0.092816f, 0.0750354f, 0.0547318f, 0.0335873f, 0.0166494f, 0.00714922f, 0.00301045f, 0.00140856f, 0.000823361f, 0.000636303f}, + {0.237967f, 0.224954f, 0.21048f, 0.194654f, 0.176822f, 0.156529f, 0.133013f, 0.105369f, 0.0736485f, 0.0421191f, 0.0190916f, 0.0075472f, 0.0030057f, 0.00136947f, 0.000802573f, 0.000633212f}, + {0.347622f, 0.327749f, 0.306321f, 0.28301f, 0.256642f, 0.225294f, 0.187228f, 0.142072f, 0.0929064f, 0.0487841f, 0.0203309f, 0.00757853f, 0.0029212f, 0.00131786f, 0.000782341f, 0.00062987f}, + {0.500004f, 0.468164f, 0.439508f, 0.40699f, 0.364072f, 0.309008f, 0.243923f, 0.173495f, 0.105729f, 0.0519279f, 0.0205797f, 0.00744622f, 0.00283547f, 0.00128046f, 0.000768588f, 0.000626691f}, + {0.682999f, 0.650709f, 0.610607f, 0.543879f, 0.46044f, 0.36923f, 0.276602f, 0.187945f, 0.110242f, 0.0525648f, 0.0204669f, 0.00733238f, 0.00278506f, 0.00126175f, 0.000763024f, 0.000625869f}, + {0.879889f, 0.81163f, 0.707536f, 0.598578f, 0.490206f, 0.38462f, 0.283682f, 0.190684f, 0.110882f, 0.052544f, 0.0203766f, 0.00729589f, 0.0027724f, 0.001257f, 0.000761166f, 0.000625359f} + }, + { + {0.0238197f, 0.0211108f, 0.0188422f, 0.0167573f, 0.0147763f, 0.0128504f, 0.010956f, 0.00906967f, 0.00721569f, 0.00543793f, 0.00388576f, 0.00270171f, 0.00190172f, 0.00139396f, 0.00107937f, 0.00088027f}, + {0.027024f, 0.0242377f, 0.0218403f, 0.0195824f, 0.0174037f, 0.0152367f, 0.0130791f, 0.0108893f, 0.00870305f, 0.00658977f, 0.00471157f, 0.00326184f, 0.00227979f, 0.00166215f, 0.00128599f, 0.00105485f}, + {0.0312307f, 0.028357f, 0.0257586f, 0.0232631f, 0.0208073f, 0.0183345f, 0.0158315f, 0.0132536f, 0.0106309f, 0.00806245f, 0.005755f, 0.00395292f, 0.00273407f, 0.00197022f, 0.00151425f, 0.0012473f}, + {0.0368842f, 0.0337766f, 0.0309339f, 0.028114f, 0.0252827f, 0.0224056f, 0.0194298f, 0.0163467f, 0.0131567f, 0.00996559f, 0.00708664f, 0.00481926f, 0.00327804f, 0.00232049f, 0.00176065f, 0.00145048f}, + {0.0445504f, 0.0411596f, 0.0379045f, 0.0346566f, 0.0313193f, 0.0278805f, 0.0242788f, 0.020473f, 0.016498f, 0.0124936f, 0.00881884f, 0.00590692f, 0.00391931f, 0.00271135f, 0.00201762f, 0.00165313f}, + {0.0551315f, 0.0512576f, 0.0474356f, 0.0435717f, 0.0395285f, 0.0353354f, 0.0308395f, 0.0260586f, 0.021011f, 0.0158556f, 0.0110624f, 0.00726079f, 0.00467893f, 0.00312695f, 0.00226797f, 0.00184002f}, + {0.0697923f, 0.0652443f, 0.0606751f, 0.0559088f, 0.0508999f, 0.045599f, 0.0398809f, 0.033734f, 0.0271379f, 0.0203319f, 0.0139857f, 0.00893493f, 0.00554413f, 0.0035507f, 0.0024935f, 0.00199771f}, + {0.090504f, 0.0849509f, 0.0792256f, 0.0732382f, 0.0668228f, 0.0599185f, 0.0524799f, 0.0443196f, 0.0355052f, 0.0263326f, 0.0177353f, 0.0109306f, 0.006466f, 0.00394227f, 0.00267066f, 0.00211782f}, + {0.119864f, 0.112845f, 0.105589f, 0.0977262f, 0.089284f, 0.080165f, 0.0700984f, 0.0590518f, 0.0469187f, 0.0342734f, 0.0223816f, 0.0131589f, 0.00734204f, 0.00423762f, 0.00277741f, 0.00219115f}, + {0.161698f, 0.152675f, 0.142986f, 0.132555f, 0.121174f, 0.108654f, 0.0948148f, 0.0793925f, 0.0623309f, 0.0443728f, 0.0277639f, 0.0153645f, 0.00804042f, 0.0044007f, 0.00281335f, 0.00222742f}, + {0.221163f, 0.209139f, 0.19608f, 0.181832f, 0.166153f, 0.148703f, 0.129126f, 0.106964f, 0.0821502f, 0.056202f, 0.0331533f, 0.0171563f, 0.008421f, 0.0044189f, 0.00279129f, 0.00223515f}, + {0.304872f, 0.28827f, 0.270099f, 0.250395f, 0.228592f, 0.203852f, 0.175231f, 0.142043f, 0.104966f, 0.0679245f, 0.0374763f, 0.0181623f, 0.00848426f, 0.00433705f, 0.00273886f, 0.00222901f}, + {0.419258f, 0.394724f, 0.369774f, 0.343265f, 0.312835f, 0.275756f, 0.230938f, 0.179571f, 0.125717f, 0.0765274f, 0.0397846f, 0.0183976f, 0.0083389f, 0.00421535f, 0.00268452f, 0.00222f}, + {0.564586f, 0.528693f, 0.500018f, 0.463913f, 0.413847f, 0.351108f, 0.280343f, 0.20718f, 0.138166f, 0.0805441f, 0.0404455f, 0.0182559f, 0.00816844f, 0.0041224f, 0.0026463f, 0.00221114f}, + {0.724662f, 0.697084f, 0.650536f, 0.575759f, 0.487769f, 0.39564f, 0.304575f, 0.218596f, 0.142428f, 0.0815253f, 0.0404322f, 0.0180835f, 0.00806238f, 0.00407511f, 0.00263051f, 0.00220859f}, + {0.894611f, 0.82241f, 0.718073f, 0.61173f, 0.507051f, 0.405794f, 0.309477f, 0.220748f, 0.143096f, 0.0815987f, 0.0403418f, 0.0180254f, 0.00803507f, 0.00406293f, 0.00262515f, 0.00220711f} + }, + { + {0.0358343f, 0.0318379f, 0.0285018f, 0.025466f, 0.0225984f, 0.0198491f, 0.0171665f, 0.0145469f, 0.0120017f, 0.00957318f, 0.00738436f, 0.00557967f, 0.00422319f, 0.00327311f, 0.0026358f, 0.00220758f}, + {0.0401601f, 0.0360909f, 0.0326095f, 0.0293522f, 0.0262432f, 0.0231857f, 0.020174f, 0.0171764f, 0.0142277f, 0.0113899f, 0.00879617f, 0.00663365f, 0.00500545f, 0.00387396f, 0.00312824f, 0.00264104f}, + {0.0457675f, 0.0416052f, 0.0378846f, 0.0343402f, 0.0308827f, 0.0274416f, 0.0240029f, 0.0205291f, 0.0170547f, 0.0136661f, 0.010542f, 0.00790713f, 0.00592566f, 0.00455506f, 0.00366917f, 0.00311836f}, + {0.0531949f, 0.0487785f, 0.0447594f, 0.0408071f, 0.036889f, 0.0329475f, 0.0289295f, 0.0248344f, 0.0206752f, 0.0165481f, 0.01272f, 0.00946548f, 0.00700681f, 0.00531864f, 0.0042506f, 0.00362199f}, + {0.0631052f, 0.0583486f, 0.0538427f, 0.0493753f, 0.0448329f, 0.0401991f, 0.0354157f, 0.0304558f, 0.0253692f, 0.0202774f, 0.0154824f, 0.0113772f, 0.00825911f, 0.0061583f, 0.00485322f, 0.00412526f}, + {0.0765093f, 0.0712044f, 0.0660153f, 0.0608039f, 0.0554114f, 0.0498659f, 0.0440226f, 0.0379064f, 0.0315586f, 0.0251239f, 0.0189796f, 0.0137102f, 0.00971429f, 0.00704499f, 0.00544079f, 0.00459175f}, + {0.0946911f, 0.0886122f, 0.0825482f, 0.0762678f, 0.0697294f, 0.0628755f, 0.055586f, 0.0478732f, 0.039754f, 0.0314252f, 0.0234375f, 0.0165402f, 0.0113484f, 0.00794176f, 0.00597195f, 0.00498885f}, + {0.119714f, 0.112505f, 0.105099f, 0.0974135f, 0.0892439f, 0.0805268f, 0.0712618f, 0.0612599f, 0.0506454f, 0.0396504f, 0.0290232f, 0.0198596f, 0.0130767f, 0.00877228f, 0.0063965f, 0.00529482f}, + {0.15416f, 0.145329f, 0.13621f, 0.126403f, 0.115936f, 0.104726f, 0.0925239f, 0.0793263f, 0.0650568f, 0.0502183f, 0.0357813f, 0.0235156f, 0.0147231f, 0.00941683f, 0.00666896f, 0.00548995f}, + {0.201638f, 0.190615f, 0.178818f, 0.166189f, 0.152515f, 0.137613f, 0.121326f, 0.103408f, 0.0838158f, 0.0632103f, 0.0434132f, 0.0271049f, 0.0160558f, 0.00980044f, 0.0067856f, 0.00559379f}, + {0.266619f, 0.25235f, 0.236947f, 0.220278f, 0.202099f, 0.182063f, 0.15973f, 0.134658f, 0.106853f, 0.0777947f, 0.0508658f, 0.0300301f, 0.0168412f, 0.0099017f, 0.00677348f, 0.00562793f}, + {0.354322f, 0.335062f, 0.314385f, 0.292341f, 0.268175f, 0.240684f, 0.20878f, 0.172098f, 0.131797f, 0.0915616f, 0.0567327f, 0.0317579f, 0.0170689f, 0.00979803f, 0.0066878f, 0.00562442f}, + {0.468551f, 0.440725f, 0.414082f, 0.38617f, 0.353238f, 0.312441f, 0.263599f, 0.20898f, 0.152905f, 0.101252f, 0.0599336f, 0.0323058f, 0.0169154f, 0.00960406f, 0.00658901f, 0.00560931f}, + {0.605581f, 0.568177f, 0.540397f, 0.501468f, 0.446818f, 0.380197f, 0.307363f, 0.233795f, 0.164861f, 0.105749f, 0.0609902f, 0.0322404f, 0.0166837f, 0.00944633f, 0.00651632f, 0.0055923f}, + {0.750163f, 0.725931f, 0.674553f, 0.595927f, 0.506948f, 0.415919f, 0.327045f, 0.243548f, 0.168929f, 0.106952f, 0.0611084f, 0.0320564f, 0.0165289f, 0.00936413f, 0.00648574f, 0.00558712f}, + {0.90352f, 0.829307f, 0.726325f, 0.622715f, 0.521319f, 0.423627f, 0.330922f, 0.245397f, 0.169596f, 0.107093f, 0.0610393f, 0.031989f, 0.0164881f, 0.00934261f, 0.00647503f, 0.00558409f} + }, + { + {0.049263f, 0.0439495f, 0.039526f, 0.0355251f, 0.0317568f, 0.028172f, 0.0246975f, 0.0213342f, 0.0180912f, 0.0150024f, 0.0121741f, 0.00974301f, 0.00778936f, 0.00631804f, 0.00526283f, 0.00451406f}, + {0.0545288f, 0.0491761f, 0.0446147f, 0.0403699f, 0.0363441f, 0.0324123f, 0.0285694f, 0.0247851f, 0.0210973f, 0.0175548f, 0.0142732f, 0.0114247f, 0.00913658f, 0.00742588f, 0.00622164f, 0.00538976f}, + {0.0612851f, 0.0558621f, 0.0510569f, 0.0465052f, 0.0420904f, 0.0377294f, 0.0334143f, 0.0290996f, 0.0248306f, 0.0206789f, 0.0168068f, 0.0134114f, 0.0106881f, 0.008665f, 0.00726887f, 0.00635282f}, + {0.0701276f, 0.0644691f, 0.0593445f, 0.0543413f, 0.0494218f, 0.0445061f, 0.0395415f, 0.034537f, 0.0295095f, 0.0245491f, 0.0198938f, 0.0157815f, 0.0124732f, 0.0100339f, 0.00838855f, 0.00736803f}, + {0.0817766f, 0.0757684f, 0.070125f, 0.064561f, 0.0589476f, 0.0532648f, 0.047451f, 0.0414943f, 0.0354518f, 0.0294362f, 0.0237113f, 0.0186193f, 0.0145004f, 0.0115168f, 0.00954218f, 0.00838362f}, + {0.0972988f, 0.0907249f, 0.084342f, 0.0779665f, 0.0714237f, 0.0647249f, 0.057753f, 0.0505347f, 0.0431154f, 0.0356457f, 0.0284353f, 0.0220085f, 0.016808f, 0.0130674f, 0.0106663f, 0.00932891f}, + {0.118018f, 0.110635f, 0.103318f, 0.095781f, 0.0879837f, 0.0798674f, 0.0713186f, 0.0623647f, 0.0530538f, 0.0435497f, 0.0343289f, 0.0260379f, 0.0193581f, 0.0146214f, 0.0116855f, 0.0101398f}, + {0.146f, 0.137441f, 0.128689f, 0.119648f, 0.1101f, 0.0999781f, 0.0893148f, 0.0779289f, 0.0659733f, 0.0536418f, 0.0415628f, 0.0306845f, 0.0220275f, 0.0160602f, 0.0125125f, 0.0107719f}, + {0.183728f, 0.173487f, 0.162931f, 0.151648f, 0.139672f, 0.126919f, 0.11318f, 0.0984522f, 0.0826797f, 0.0663106f, 0.0501368f, 0.0357302f, 0.0245653f, 0.0172002f, 0.0130701f, 0.0111893f}, + {0.234548f, 0.222029f, 0.20868f, 0.194472f, 0.179179f, 0.162651f, 0.144712f, 0.125123f, 0.103844f, 0.0814873f, 0.0596167f, 0.0406355f, 0.026637f, 0.0179185f, 0.0133483f, 0.011425f}, + {0.302344f, 0.286446f, 0.269391f, 0.251107f, 0.231339f, 0.20967f, 0.185595f, 0.158676f, 0.128987f, 0.0979997f, 0.068685f, 0.0446287f, 0.0279229f, 0.0181857f, 0.0133941f, 0.0115223f}, + {0.391323f, 0.370159f, 0.347859f, 0.324505f, 0.299011f, 0.269867f, 0.235947f, 0.197185f, 0.155072f, 0.113067f, 0.0757243f, 0.0470591f, 0.0283976f, 0.018111f, 0.0132954f, 0.0115375f}, + {0.503589f, 0.473541f, 0.446217f, 0.417774f, 0.383304f, 0.340254f, 0.289226f, 0.233094f, 0.176135f, 0.123386f, 0.0796023f, 0.0479481f, 0.0283004f, 0.0178708f, 0.0131569f, 0.0115212f}, + {0.633226f, 0.595523f, 0.568606f, 0.527724f, 0.470465f, 0.402181f, 0.328971f, 0.255944f, 0.187661f, 0.128162f, 0.0809784f, 0.0480034f, 0.028048f, 0.0176587f, 0.0130483f, 0.011496f}, + {0.767073f, 0.74497f, 0.690584f, 0.610465f, 0.521984f, 0.432625f, 0.345964f, 0.26467f, 0.191575f, 0.129502f, 0.0812154f, 0.0478403f, 0.0278634f, 0.0175445f, 0.0130018f, 0.011488f}, + {0.90934f, 0.834459f, 0.733265f, 0.632227f, 0.533697f, 0.438997f, 0.349256f, 0.266338f, 0.192235f, 0.129685f, 0.0811716f, 0.0477733f, 0.0278134f, 0.0175141f, 0.0129847f, 0.011483f} + }, + { + {0.0640814f, 0.0574846f, 0.0519985f, 0.0470462f, 0.042391f, 0.0379756f, 0.03371f, 0.0295985f, 0.0256463f, 0.0218829f, 0.0184027f, 0.0153367f, 0.0127657f, 0.0107273f, 0.00918596f, 0.00803987f}, + {0.0700642f, 0.0634915f, 0.0579038f, 0.0527207f, 0.0478182f, 0.0430505f, 0.0384107f, 0.0338681f, 0.0294587f, 0.0252286f, 0.0212803f, 0.0177715f, 0.0148381f, 0.0125294f, 0.010818f, 0.00957796f}, + {0.0776754f, 0.0710878f, 0.0652858f, 0.0598068f, 0.0545127f, 0.0493069f, 0.0441839f, 0.0390928f, 0.034085f, 0.0292264f, 0.0246667f, 0.0205831f, 0.0171768f, 0.0145194f, 0.0125906f, 0.0112666f}, + {0.087544f, 0.0807737f, 0.0746673f, 0.0687346f, 0.0629286f, 0.0571556f, 0.0513547f, 0.0455507f, 0.0397578f, 0.0340643f, 0.028693f, 0.0238524f, 0.0198115f, 0.0166866f, 0.0144752f, 0.0130444f}, + {0.100415f, 0.0933282f, 0.0867113f, 0.0802169f, 0.0736964f, 0.0671269f, 0.0604465f, 0.0536521f, 0.0468096f, 0.0400272f, 0.0335458f, 0.0276704f, 0.0227425f, 0.0190003f, 0.0164058f, 0.0148235f}, + {0.117374f, 0.10975f, 0.10239f, 0.0950646f, 0.0875875f, 0.0799596f, 0.0720803f, 0.0639825f, 0.0557144f, 0.0474366f, 0.0394149f, 0.0321278f, 0.0260095f, 0.0213924f, 0.0182838f, 0.0164845f}, + {0.139747f, 0.131328f, 0.123023f, 0.11451f, 0.105738f, 0.0966491f, 0.0871373f, 0.0772478f, 0.067047f, 0.0566811f, 0.0465843f, 0.0373203f, 0.0295588f, 0.0237671f, 0.0199902f, 0.0179184f}, + {0.169556f, 0.159968f, 0.150209f, 0.140156f, 0.129591f, 0.118443f, 0.106766f, 0.0944001f, 0.081508f, 0.0682636f, 0.0552209f, 0.0432074f, 0.0332304f, 0.025961f, 0.0213918f, 0.0190475f}, + {0.209163f, 0.197897f, 0.186309f, 0.173979f, 0.160947f, 0.147134f, 0.132358f, 0.116619f, 0.0998744f, 0.0825344f, 0.06528f, 0.0495133f, 0.0367055f, 0.0277252f, 0.022373f, 0.0198138f}, + {0.261686f, 0.248121f, 0.233706f, 0.218435f, 0.202089f, 0.18453f, 0.165568f, 0.144965f, 0.122681f, 0.0993001f, 0.0762148f, 0.0555861f, 0.0395549f, 0.0288856f, 0.0229146f, 0.0202667f}, + {0.330562f, 0.313556f, 0.295419f, 0.276134f, 0.25544f, 0.232849f, 0.207796f, 0.179854f, 0.149148f, 0.117136f, 0.0865125f, 0.0605197f, 0.0413898f, 0.0294082f, 0.0230902f, 0.0204814f}, + {0.419323f, 0.396875f, 0.373606f, 0.349596f, 0.323465f, 0.293472f, 0.258505f, 0.218722f, 0.175813f, 0.133044f, 0.0944332f, 0.0635843f, 0.0421678f, 0.0294277f, 0.0230191f, 0.0205425f}, + {0.529025f, 0.497538f, 0.470052f, 0.441529f, 0.4063f, 0.362149f, 0.310225f, 0.253701f, 0.196712f, 0.143748f, 0.0988194f, 0.0648012f, 0.0421795f, 0.0291832f, 0.0228607f, 0.0205362f}, + {0.652546f, 0.614936f, 0.588741f, 0.546853f, 0.488476f, 0.419868f, 0.347178f, 0.275177f, 0.207898f, 0.148689f, 0.100442f, 0.0649891f, 0.0419435f, 0.0289391f, 0.0227237f, 0.0205056f}, + {0.778651f, 0.757907f, 0.702076f, 0.621855f, 0.534538f, 0.447013f, 0.362479f, 0.283235f, 0.211692f, 0.150109f, 0.100774f, 0.0648621f, 0.0417482f, 0.0288019f, 0.0226636f, 0.0204958f}, + {0.913306f, 0.838644f, 0.73936f, 0.640683f, 0.544696f, 0.452603f, 0.365415f, 0.284779f, 0.212338f, 0.15032f, 0.100752f, 0.0648007f, 0.0416937f, 0.0287644f, 0.0226404f, 0.0204887f} + }, + { + {0.0803585f, 0.0725536f, 0.0660569f, 0.0601876f, 0.0546685f, 0.0494325f, 0.0443772f, 0.039507f, 0.0348263f, 0.0303632f, 0.0262068f, 0.0224862f, 0.0192785f, 0.0166424f, 0.0145671f, 0.0129636f}, + {0.0868272f, 0.0791381f, 0.0726053f, 0.066551f, 0.060827f, 0.0552656f, 0.0498625f, 0.0445833f, 0.0394648f, 0.0345559f, 0.02995f, 0.0257962f, 0.0222347f, 0.0193303f, 0.0170918f, 0.015405f}, + {0.0949956f, 0.0873776f, 0.0806932f, 0.0743873f, 0.0683033f, 0.0623328f, 0.0564699f, 0.0506613f, 0.0449668f, 0.0394454f, 0.034247f, 0.0295345f, 0.0255088f, 0.0222636f, 0.0198192f, 0.0180796f}, + {0.10551f, 0.0977934f, 0.0908542f, 0.0841298f, 0.077564f, 0.0710516f, 0.0645252f, 0.0580227f, 0.0515577f, 0.0452203f, 0.0392291f, 0.033774f, 0.0291231f, 0.0254156f, 0.0227025f, 0.0208908f}, + {0.119117f, 0.111153f, 0.103748f, 0.0965002f, 0.0892401f, 0.0819454f, 0.074555f, 0.0670718f, 0.0595727f, 0.0521647f, 0.045081f, 0.0386034f, 0.0330633f, 0.0287348f, 0.02564f, 0.023703f}, + {0.1369f, 0.128462f, 0.12035f, 0.112294f, 0.1041f, 0.0957545f, 0.0871753f, 0.0784003f, 0.0694858f, 0.0606027f, 0.0519945f, 0.0441119f, 0.0373651f, 0.0321274f, 0.0284908f, 0.026334f}, + {0.160162f, 0.150978f, 0.141954f, 0.132734f, 0.123254f, 0.11346f, 0.103254f, 0.0926985f, 0.0818751f, 0.0709259f, 0.0602656f, 0.0503989f, 0.0419584f, 0.0354631f, 0.0310839f, 0.0286161f}, + {0.190862f, 0.180558f, 0.170108f, 0.159361f, 0.148103f, 0.136265f, 0.123912f, 0.110906f, 0.0974297f, 0.0836426f, 0.0700573f, 0.0574097f, 0.0466516f, 0.038535f, 0.0332341f, 0.030428f}, + {0.231255f, 0.219316f, 0.207055f, 0.194057f, 0.180354f, 0.165884f, 0.15049f, 0.134171f, 0.116903f, 0.0990739f, 0.081292f, 0.0648239f, 0.0510695f, 0.041032f, 0.0347829f, 0.031684f}, + {0.284273f, 0.270056f, 0.254988f, 0.239084f, 0.222136f, 0.204019f, 0.184535f, 0.163455f, 0.140737f, 0.116945f, 0.0933454f, 0.0719059f, 0.0547005f, 0.0427281f, 0.0356989f, 0.0324525f}, + {0.353047f, 0.335381f, 0.31662f, 0.296801f, 0.275672f, 0.252696f, 0.227271f, 0.198977f, 0.167965f, 0.135662f, 0.104571f, 0.0776515f, 0.0571057f, 0.0435924f, 0.0360905f, 0.0328519f}, + {0.440703f, 0.417495f, 0.393722f, 0.369475f, 0.343199f, 0.312998f, 0.277765f, 0.237802f, 0.194883f, 0.152123f, 0.113164f, 0.0812787f, 0.0582238f, 0.0437738f, 0.0361006f, 0.0329945f}, + {0.547713f, 0.515359f, 0.487926f, 0.459618f, 0.424305f, 0.379991f, 0.328129f, 0.272005f, 0.215612f, 0.163081f, 0.117939f, 0.0827963f, 0.0583819f, 0.0435706f, 0.0359518f, 0.0330141f}, + {0.666307f, 0.628751f, 0.603217f, 0.561218f, 0.502851f, 0.434804f, 0.363191f, 0.292537f, 0.226539f, 0.168122f, 0.119749f, 0.0831136f, 0.0581898f, 0.0433205f, 0.0358002f, 0.0329838f}, + {0.786583f, 0.766754f, 0.710744f, 0.631306f, 0.545511f, 0.459889f, 0.377407f, 0.300144f, 0.230236f, 0.16959f, 0.120156f, 0.0830272f, 0.0579986f, 0.0431714f, 0.0357315f, 0.0329736f}, + {0.916039f, 0.842245f, 0.744891f, 0.648415f, 0.554738f, 0.464995f, 0.380115f, 0.301602f, 0.230869f, 0.169818f, 0.12015f, 0.0829735f, 0.0579435f, 0.0431294f, 0.0357031f, 0.0329647f} + }, + { + {0.0981625f, 0.0892539f, 0.0818178f, 0.0750794f, 0.0687249f, 0.0626799f, 0.0568324f, 0.0511863f, 0.0457492f, 0.0405501f, 0.0356807f, 0.0312738f, 0.0274039f, 0.0241437f, 0.0214994f, 0.0193932f}, + {0.104896f, 0.0962186f, 0.0888389f, 0.0819913f, 0.0755049f, 0.069194f, 0.0630562f, 0.0570554f, 0.051231f, 0.0456402f, 0.0403724f, 0.0355759f, 0.0313967f, 0.0279044f, 0.0251351f, 0.0229823f}, + {0.113342f, 0.104848f, 0.0974075f, 0.090382f, 0.0836008f, 0.0769436f, 0.0704028f, 0.0639284f, 0.0575857f, 0.0514345f, 0.0456317f, 0.0403345f, 0.0357444f, 0.0319649f, 0.0290427f, 0.0269045f}, + {0.124153f, 0.115669f, 0.108054f, 0.100678f, 0.0934787f, 0.0863385f, 0.0791883f, 0.0720757f, 0.0650182f, 0.0581114f, 0.0515791f, 0.0456044f, 0.0404544f, 0.036275f, 0.0331504f, 0.0310184f}, + {0.138061f, 0.129426f, 0.121419f, 0.113592f, 0.105754f, 0.0978858f, 0.0899266f, 0.081886f, 0.0738524f, 0.0659413f, 0.0583869f, 0.0514633f, 0.0454908f, 0.040757f, 0.0373134f, 0.0351297f}, + {0.15613f, 0.147112f, 0.138467f, 0.129888f, 0.121177f, 0.112308f, 0.103214f, 0.0939393f, 0.0845523f, 0.07524f, 0.0662407f, 0.0579924f, 0.0508817f, 0.0452875f, 0.0413425f, 0.0389805f}, + {0.179631f, 0.169944f, 0.16045f, 0.150767f, 0.140822f, 0.13056f, 0.119893f, 0.108903f, 0.0976866f, 0.086396f, 0.0754428f, 0.0652944f, 0.0565412f, 0.0497014f, 0.0450084f, 0.0423321f}, + {0.210455f, 0.199721f, 0.188863f, 0.177706f, 0.16604f, 0.153794f, 0.141052f, 0.127695f, 0.113933f, 0.0999227f, 0.0861578f, 0.0733073f, 0.0622534f, 0.0537512f, 0.0480695f, 0.0450104f}, + {0.250765f, 0.238462f, 0.225848f, 0.212499f, 0.198453f, 0.183659f, 0.167986f, 0.151445f, 0.134035f, 0.11613f, 0.098294f, 0.0816827f, 0.0676002f, 0.0570696f, 0.0503226f, 0.0468971f}, + {0.303357f, 0.288829f, 0.273457f, 0.257269f, 0.240081f, 0.221779f, 0.202177f, 0.181061f, 0.158392f, 0.134711f, 0.111187f, 0.08963f, 0.0720008f, 0.0593793f, 0.0517214f, 0.0480824f}, + {0.371176f, 0.353231f, 0.334214f, 0.314218f, 0.293023f, 0.270078f, 0.244771f, 0.216682f, 0.185957f, 0.153982f, 0.123109f, 0.0960767f, 0.0749851f, 0.0606631f, 0.0524191f, 0.0487398f}, + {0.457151f, 0.43362f, 0.409672f, 0.385472f, 0.359419f, 0.329529f, 0.294679f, 0.255218f, 0.212933f, 0.170807f, 0.132228f, 0.100208f, 0.0764683f, 0.061069f, 0.0525688f, 0.0490036f}, + {0.561511f, 0.528708f, 0.501392f, 0.473516f, 0.4387f, 0.394994f, 0.34394f, 0.288823f, 0.233525f, 0.181949f, 0.13731f, 0.101999f, 0.0767982f, 0.0609496f, 0.0524627f, 0.0490672f}, + {0.676168f, 0.638437f, 0.613568f, 0.572243f, 0.514769f, 0.447933f, 0.377794f, 0.308737f, 0.244268f, 0.187052f, 0.139264f, 0.102435f, 0.0766688f, 0.0607181f, 0.0523128f, 0.0490438f}, + {0.791881f, 0.772692f, 0.71755f, 0.639511f, 0.555468f, 0.471796f, 0.391333f, 0.316044f, 0.247886f, 0.188548f, 0.139726f, 0.102389f, 0.0764923f, 0.0605677f, 0.0522415f, 0.0490355f}, + {0.917899f, 0.845494f, 0.750079f, 0.655691f, 0.564168f, 0.476608f, 0.393894f, 0.317438f, 0.248507f, 0.188784f, 0.139733f, 0.102344f, 0.0764393f, 0.0605235f, 0.0522096f, 0.0490251f} + }, + { + {0.11751f, 0.107624f, 0.0993338f, 0.0917856f, 0.0846319f, 0.0777925f, 0.0711485f, 0.0647043f, 0.0584743f, 0.0524925f, 0.0468619f, 0.0417259f, 0.0371605f, 0.0332496f, 0.0300086f, 0.0273659f}, + {0.124306f, 0.114785f, 0.106666f, 0.0991106f, 0.0919247f, 0.0849085f, 0.0780616f, 0.071347f, 0.0648108f, 0.0585228f, 0.0525764f, 0.0471269f, 0.0423307f, 0.0382568f, 0.0349603f, 0.0323352f}, + {0.132779f, 0.123572f, 0.115507f, 0.107873f, 0.100486f, 0.0932153f, 0.0860537f, 0.0789544f, 0.0719909f, 0.0652289f, 0.0588412f, 0.0529878f, 0.0478756f, 0.0436113f, 0.040256f, 0.0377502f}, + {0.143578f, 0.134508f, 0.126371f, 0.118483f, 0.110768f, 0.103105f, 0.0954216f, 0.0877739f, 0.080187f, 0.0727685f, 0.0657556f, 0.0593361f, 0.0537804f, 0.0492324f, 0.0457926f, 0.0434156f}, + {0.157411f, 0.148305f, 0.139872f, 0.131628f, 0.123364f, 0.115059f, 0.106656f, 0.0981693f, 0.0897029f, 0.0813887f, 0.0734711f, 0.0662311f, 0.0599818f, 0.0550111f, 0.0513753f, 0.0490691f}, + {0.175309f, 0.165929f, 0.156949f, 0.148038f, 0.138991f, 0.129771f, 0.12032f, 0.110698f, 0.100983f, 0.091388f, 0.0821612f, 0.0737418f, 0.0664975f, 0.060792f, 0.0567621f, 0.0543656f}, + {0.198507f, 0.18855f, 0.17881f, 0.168882f, 0.158683f, 0.148159f, 0.137228f, 0.125995f, 0.114578f, 0.103149f, 0.0921318f, 0.0819751f, 0.0732283f, 0.0663765f, 0.0616617f, 0.0589862f}, + {0.228824f, 0.217911f, 0.206893f, 0.19557f, 0.183737f, 0.171323f, 0.158429f, 0.144959f, 0.131157f, 0.117193f, 0.103557f, 0.0908711f, 0.0799427f, 0.0714806f, 0.0657739f, 0.0626964f}, + {0.268352f, 0.255955f, 0.243255f, 0.229826f, 0.215707f, 0.200861f, 0.185183f, 0.16871f, 0.151472f, 0.13384f, 0.116353f, 0.100071f, 0.0861941f, 0.0756888f, 0.0688507f, 0.0653426f}, + {0.319796f, 0.305249f, 0.289862f, 0.273678f, 0.256534f, 0.238341f, 0.218941f, 0.198147f, 0.175927f, 0.1528f, 0.129853f, 0.108758f, 0.0913441f, 0.0786728f, 0.0708283f, 0.0670383f}, + {0.386009f, 0.368111f, 0.349132f, 0.329238f, 0.308253f, 0.285658f, 0.260863f, 0.233437f, 0.203497f, 0.17237f, 0.142289f, 0.115814f, 0.0949101f, 0.0804427f, 0.0719178f, 0.0680263f}, + {0.46989f, 0.446402f, 0.422523f, 0.398572f, 0.373009f, 0.343849f, 0.309915f, 0.271516f, 0.230398f, 0.189433f, 0.151832f, 0.120404f, 0.0967766f, 0.0811275f, 0.0722626f, 0.0684499f}, + {0.571682f, 0.538755f, 0.511551f, 0.484265f, 0.450423f, 0.407959f, 0.358314f, 0.304695f, 0.250908f, 0.200723f, 0.157165f, 0.122444f, 0.0972951f, 0.0811272f, 0.072231f, 0.068575f}, + {0.683197f, 0.645011f, 0.620823f, 0.580826f, 0.524971f, 0.45986f, 0.391505f, 0.324258f, 0.261537f, 0.205867f, 0.159228f, 0.122988f, 0.0972399f, 0.0809346f, 0.0720988f, 0.0685651f}, + {0.795212f, 0.776459f, 0.723058f, 0.646906f, 0.564805f, 0.483121f, 0.40467f, 0.331375f, 0.265093f, 0.207375f, 0.159729f, 0.12298f, 0.0970849f, 0.0807918f, 0.0720306f, 0.0685604f}, + {0.919114f, 0.848547f, 0.7551f, 0.662733f, 0.573261f, 0.487776f, 0.407142f, 0.332723f, 0.265702f, 0.207614f, 0.159746f, 0.122942f, 0.0970357f, 0.0807477f, 0.0719968f, 0.0685491f} + }, + { + {0.138345f, 0.127624f, 0.118581f, 0.110295f, 0.102388f, 0.0947759f, 0.0873342f, 0.0800672f, 0.0730019f, 0.0661816f, 0.0597308f, 0.0538126f, 0.0485111f, 0.0439208f, 0.0400601f, 0.0368569f}, + {0.145028f, 0.134816f, 0.126075f, 0.117903f, 0.110086f, 0.102411f, 0.0948807f, 0.0874554f, 0.0801934f, 0.0731821f, 0.0665282f, 0.0604029f, 0.0549808f, 0.0503269f, 0.0465094f, 0.0434137f}, + {0.153312f, 0.143555f, 0.134999f, 0.126867f, 0.118965f, 0.111153f, 0.103423f, 0.0957312f, 0.088163f, 0.0807961f, 0.0738278f, 0.0674315f, 0.061826f, 0.0571178f, 0.0533733f, 0.0505359f}, + {0.163836f, 0.154354f, 0.145843f, 0.137574f, 0.129457f, 0.121368f, 0.113231f, 0.10511f, 0.0970424f, 0.0891524f, 0.0817001f, 0.0748907f, 0.0690031f, 0.0641757f, 0.0605112f, 0.0579665f}, + {0.177276f, 0.167883f, 0.159189f, 0.150678f, 0.142126f, 0.133503f, 0.124765f, 0.115926f, 0.107107f, 0.0984665f, 0.0902685f, 0.0828149f, 0.0764174f, 0.0713564f, 0.0676733f, 0.0653667f}, + {0.194623f, 0.185075f, 0.175939f, 0.166865f, 0.157643f, 0.148219f, 0.138548f, 0.128702f, 0.118775f, 0.109014f, 0.0996898f, 0.0912584f, 0.0840744f, 0.0784716f, 0.0745621f, 0.0722969f}, + {0.217071f, 0.207049f, 0.197256f, 0.187272f, 0.177003f, 0.166389f, 0.15536f, 0.144039f, 0.132574f, 0.121169f, 0.110274f, 0.100335f, 0.091865f, 0.0852916f, 0.0808225f, 0.0783506f}, + {0.24637f, 0.235492f, 0.224522f, 0.213243f, 0.201446f, 0.18906f, 0.176208f, 0.162812f, 0.149166f, 0.135464f, 0.122211f, 0.109998f, 0.0995521f, 0.0915013f, 0.0860959f, 0.0832286f}, + {0.284556f, 0.272287f, 0.259727f, 0.246442f, 0.23247f, 0.217788f, 0.202323f, 0.186146f, 0.169326f, 0.152253f, 0.13545f, 0.119896f, 0.106675f, 0.096646f, 0.0900913f, 0.0867407f}, + {0.334276f, 0.31995f, 0.304786f, 0.28884f, 0.271966f, 0.254109f, 0.235156f, 0.214962f, 0.193513f, 0.171307f, 0.149356f, 0.129209f, 0.112548f, 0.100347f, 0.0927249f, 0.0890255f}, + {0.398369f, 0.380784f, 0.362086f, 0.342515f, 0.321946f, 0.299938f, 0.275954f, 0.249555f, 0.22081f, 0.190968f, 0.162159f, 0.136797f, 0.116693f, 0.102656f, 0.094281f, 0.0904092f}, + {0.479828f, 0.45669f, 0.433076f, 0.409521f, 0.384633f, 0.356519f, 0.323922f, 0.287045f, 0.247536f, 0.208175f, 0.17205f, 0.14181f, 0.118956f, 0.103664f, 0.0948691f, 0.0910267f}, + {0.579117f, 0.546343f, 0.519233f, 0.492627f, 0.460121f, 0.419408f, 0.371663f, 0.319956f, 0.268029f, 0.2196f, 0.177595f, 0.144079f, 0.119673f, 0.10381f, 0.0949387f, 0.0912277f}, + {0.688119f, 0.649231f, 0.625702f, 0.587546f, 0.533917f, 0.470966f, 0.404661f, 0.3394f, 0.278611f, 0.224776f, 0.179743f, 0.14472f, 0.119698f, 0.103671f, 0.0948371f, 0.0912364f}, + {0.797056f, 0.778532f, 0.727609f, 0.653779f, 0.573794f, 0.494139f, 0.417701f, 0.346418f, 0.282121f, 0.226284f, 0.18027f, 0.144745f, 0.119568f, 0.103543f, 0.0947767f, 0.0912366f}, + {0.919821f, 0.851517f, 0.760096f, 0.669722f, 0.582236f, 0.498746f, 0.420129f, 0.347736f, 0.282717f, 0.226521f, 0.180293f, 0.144714f, 0.119524f, 0.1035f, 0.0947425f, 0.0912247f} + }, + { + {0.160543f, 0.149143f, 0.13946f, 0.130523f, 0.121924f, 0.113571f, 0.105338f, 0.0972271f, 0.0892811f, 0.0815582f, 0.074218f, 0.0674548f, 0.0613702f, 0.0560701f, 0.0515703f, 0.0477901f}, + {0.166967f, 0.15622f, 0.146979f, 0.13829f, 0.129917f, 0.121637f, 0.113452f, 0.105319f, 0.0973119f, 0.0895414f, 0.082139f, 0.0753037f, 0.0692376f, 0.0640003f, 0.0596678f, 0.0561079f}, + {0.174881f, 0.164734f, 0.155816f, 0.147299f, 0.138974f, 0.130692f, 0.122446f, 0.114189f, 0.106023f, 0.0980447f, 0.0904852f, 0.0835441f, 0.077461f, 0.0723396f, 0.0682445f, 0.0651114f}, + {0.184912f, 0.17518f, 0.166435f, 0.15791f, 0.149497f, 0.141073f, 0.132556f, 0.124015f, 0.1155f, 0.107162f, 0.0992916f, 0.0921272f, 0.0859626f, 0.0809279f, 0.0771172f, 0.0744755f}, + {0.197702f, 0.188185f, 0.179378f, 0.170733f, 0.162018f, 0.153186f, 0.14421f, 0.135094f, 0.125984f, 0.11707f, 0.108649f, 0.101058f, 0.0946137f, 0.0895836f, 0.0859776f, 0.0837792f}, + {0.21419f, 0.204641f, 0.195505f, 0.186414f, 0.177156f, 0.167657f, 0.157881f, 0.147912f, 0.137861f, 0.128018f, 0.118694f, 0.110374f, 0.103407f, 0.0980853f, 0.0944718f, 0.0924835f}, + {0.235531f, 0.225612f, 0.215932f, 0.206048f, 0.195863f, 0.185308f, 0.174316f, 0.163027f, 0.151631f, 0.14037f, 0.12974f, 0.120201f, 0.112229f, 0.106176f, 0.102181f, 0.100091f}, + {0.263402f, 0.252733f, 0.241984f, 0.230921f, 0.219326f, 0.207132f, 0.194474f, 0.181295f, 0.16795f, 0.154673f, 0.142004f, 0.130514f, 0.120846f, 0.113517f, 0.108692f, 0.106236f}, + {0.299799f, 0.287839f, 0.275601f, 0.262645f, 0.248996f, 0.23465f, 0.219562f, 0.203847f, 0.18763f, 0.171334f, 0.155486f, 0.140987f, 0.128797f, 0.119623f, 0.113672f, 0.110692f}, + {0.347333f, 0.333422f, 0.318676f, 0.303159f, 0.286729f, 0.269377f, 0.251051f, 0.231658f, 0.211221f, 0.190226f, 0.169619f, 0.150824f, 0.13536f, 0.124064f, 0.117016f, 0.113625f}, + {0.408889f, 0.391835f, 0.37362f, 0.35455f, 0.334547f, 0.31329f, 0.290327f, 0.265226f, 0.237998f, 0.209799f, 0.182661f, 0.158873f, 0.140076f, 0.126952f, 0.119099f, 0.115458f}, + {0.487652f, 0.465114f, 0.441944f, 0.418893f, 0.394792f, 0.367938f, 0.336996f, 0.302003f, 0.264464f, 0.227073f, 0.192842f, 0.164283f, 0.142743f, 0.128316f, 0.119968f, 0.116296f}, + {0.584467f, 0.55209f, 0.525082f, 0.499175f, 0.468244f, 0.429675f, 0.384234f, 0.334784f, 0.285009f, 0.238636f, 0.198574f, 0.166763f, 0.143663f, 0.128627f, 0.120159f, 0.116583f}, + {0.691448f, 0.651687f, 0.62873f, 0.592783f, 0.541889f, 0.481483f, 0.417463f, 0.354331f, 0.295618f, 0.243842f, 0.200786f, 0.167488f, 0.14377f, 0.128552f, 0.120097f, 0.116613f}, + {0.797777f, 0.779238f, 0.731402f, 0.660309f, 0.582619f, 0.505038f, 0.430609f, 0.361339f, 0.299099f, 0.245343f, 0.201327f, 0.167541f, 0.143667f, 0.128441f, 0.120048f, 0.116619f}, + {0.920111f, 0.854479f, 0.765174f, 0.676798f, 0.591257f, 0.5097f, 0.433035f, 0.362639f, 0.299683f, 0.245575f, 0.201354f, 0.167517f, 0.143628f, 0.128402f, 0.120015f, 0.116607f} + }, + { + {0.183925f, 0.172005f, 0.161812f, 0.152324f, 0.143108f, 0.134064f, 0.125061f, 0.116094f, 0.107223f, 0.0985268f, 0.0902175f, 0.0825365f, 0.0756155f, 0.0695739f, 0.0644191f, 0.0600524f}, + {0.189968f, 0.178844f, 0.16923f, 0.16013f, 0.151287f, 0.142465f, 0.133663f, 0.124832f, 0.116057f, 0.107483f, 0.0992795f, 0.0916883f, 0.0849513f, 0.0791224f, 0.0742802f, 0.0702652f}, + {0.19737f, 0.186983f, 0.177832f, 0.169041f, 0.160387f, 0.151712f, 0.143002f, 0.134212f, 0.125448f, 0.11684f, 0.108663f, 0.10116f, 0.0946025f, 0.0890889f, 0.0846751f, 0.0812787f}, + {0.206737f, 0.196899f, 0.188049f, 0.179386f, 0.17078f, 0.162107f, 0.153281f, 0.144367f, 0.135428f, 0.126647f, 0.118363f, 0.110859f, 0.104453f, 0.0992669f, 0.0953736f, 0.0926945f}, + {0.218671f, 0.209173f, 0.200386f, 0.191726f, 0.182958f, 0.174018f, 0.164887f, 0.155561f, 0.146202f, 0.137045f, 0.128433f, 0.120755f, 0.11434f, 0.109436f, 0.106007f, 0.104006f}, + {0.234062f, 0.224649f, 0.215647f, 0.206663f, 0.197489f, 0.18803f, 0.178242f, 0.168233f, 0.158121f, 0.148249f, 0.138989f, 0.130871f, 0.124243f, 0.119344f, 0.116167f, 0.114574f}, + {0.254017f, 0.244337f, 0.234904f, 0.225252f, 0.215279f, 0.204906f, 0.194061f, 0.182899f, 0.171649f, 0.160614f, 0.150349f, 0.141348f, 0.134049f, 0.128712f, 0.125375f, 0.12381f}, + {0.280141f, 0.269818f, 0.259427f, 0.248721f, 0.237463f, 0.22559f, 0.213248f, 0.20039f, 0.187442f, 0.1747f, 0.162761f, 0.15219f, 0.143539f, 0.137182f, 0.133162f, 0.13128f}, + {0.314399f, 0.302888f, 0.291117f, 0.278639f, 0.265452f, 0.251575f, 0.236983f, 0.221846f, 0.206351f, 0.190985f, 0.176299f, 0.163119f, 0.152265f, 0.144251f, 0.139164f, 0.136728f}, + {0.359383f, 0.346035f, 0.331867f, 0.316926f, 0.30108f, 0.284357f, 0.266771f, 0.24831f, 0.229047f, 0.209477f, 0.19049f, 0.173379f, 0.159478f, 0.149438f, 0.14325f, 0.140346f}, + {0.418061f, 0.401703f, 0.384151f, 0.365722f, 0.346395f, 0.325989f, 0.304172f, 0.280547f, 0.255071f, 0.228795f, 0.203655f, 0.181823f, 0.164748f, 0.152931f, 0.145904f, 0.14267f}, + {0.493888f, 0.472147f, 0.449606f, 0.427134f, 0.403872f, 0.378393f, 0.349318f, 0.316475f, 0.281192f, 0.24607f, 0.214076f, 0.187605f, 0.167824f, 0.154673f, 0.147081f, 0.143746f}, + {0.588219f, 0.55646f, 0.529618f, 0.504351f, 0.475117f, 0.438965f, 0.396153f, 0.349244f, 0.301861f, 0.257786f, 0.219979f, 0.190282f, 0.168946f, 0.155158f, 0.147405f, 0.144124f}, + {0.693558f, 0.652854f, 0.630304f, 0.596789f, 0.549046f, 0.491535f, 0.430014f, 0.369127f, 0.312581f, 0.263028f, 0.22224f, 0.191079f, 0.169133f, 0.155151f, 0.147388f, 0.144176f}, + {0.797663f, 0.778804f, 0.734538f, 0.666599f, 0.591398f, 0.515947f, 0.443505f, 0.376217f, 0.316055f, 0.264516f, 0.222784f, 0.191155f, 0.169056f, 0.155062f, 0.147351f, 0.144186f}, + {0.920066f, 0.857486f, 0.770404f, 0.684067f, 0.600448f, 0.520762f, 0.445972f, 0.377513f, 0.316628f, 0.264739f, 0.222812f, 0.191135f, 0.169022f, 0.155026f, 0.147319f, 0.144174f} + }, + { + {0.208271f, 0.195993f, 0.185429f, 0.175501f, 0.165763f, 0.1561f, 0.146368f, 0.136549f, 0.126713f, 0.116969f, 0.1076f, 0.0989169f, 0.0911003f, 0.084285f, 0.0784627f, 0.0735062f}, + {0.213842f, 0.202487f, 0.192636f, 0.183233f, 0.174017f, 0.164733f, 0.155363f, 0.145854f, 0.136294f, 0.126867f, 0.117795f, 0.109389f, 0.101946f, 0.0955135f, 0.0901661f, 0.0857069f}, + {0.220621f, 0.21013f, 0.200873f, 0.191919f, 0.183033f, 0.174051f, 0.164935f, 0.155647f, 0.146283f, 0.137018f, 0.128184f, 0.120088f, 0.113046f, 0.107152f, 0.102444f, 0.098812f}, + {0.229193f, 0.219374f, 0.210544f, 0.201848f, 0.193147f, 0.184316f, 0.17525f, 0.166011f, 0.156663f, 0.147434f, 0.138717f, 0.13087f, 0.124243f, 0.118944f, 0.115017f, 0.112347f}, + {0.240119f, 0.230755f, 0.222108f, 0.213535f, 0.204815f, 0.195861f, 0.186653f, 0.177175f, 0.167597f, 0.158209f, 0.149414f, 0.141673f, 0.135338f, 0.130631f, 0.127457f, 0.125719f}, + {0.254234f, 0.245066f, 0.236313f, 0.227536f, 0.218549f, 0.209229f, 0.199515f, 0.189531f, 0.179402f, 0.169528f, 0.160363f, 0.152503f, 0.146303f, 0.141934f, 0.139301f, 0.13819f}, + {0.272596f, 0.263258f, 0.254182f, 0.244863f, 0.235208f, 0.22512f, 0.214514f, 0.203551f, 0.192497f, 0.181729f, 0.171888f, 0.16352f, 0.157028f, 0.152557f, 0.150015f, 0.149082f}, + {0.296735f, 0.286859f, 0.276936f, 0.266692f, 0.25588f, 0.244435f, 0.2325f, 0.220036f, 0.207537f, 0.195389f, 0.184273f, 0.174769f, 0.167321f, 0.162131f, 0.159086f, 0.1579f}, + {0.328587f, 0.317627f, 0.306438f, 0.29455f, 0.281933f, 0.268629f, 0.254618f, 0.240126f, 0.225413f, 0.211065f, 0.197685f, 0.186032f, 0.176758f, 0.170146f, 0.166119f, 0.164357f}, + {0.370739f, 0.358061f, 0.344603f, 0.330349f, 0.315192f, 0.29919f, 0.282409f, 0.264942f, 0.246937f, 0.22893f, 0.211773f, 0.196616f, 0.184572f, 0.176065f, 0.170955f, 0.168676f}, + {0.426266f, 0.410716f, 0.393993f, 0.376311f, 0.357741f, 0.338242f, 0.317616f, 0.295552f, 0.271977f, 0.247831f, 0.224949f, 0.205387f, 0.190375f, 0.180173f, 0.174209f, 0.171518f}, + {0.498944f, 0.478136f, 0.456429f, 0.434587f, 0.412177f, 0.388098f, 0.360993f, 0.330479f, 0.297658f, 0.265036f, 0.235563f, 0.211521f, 0.193858f, 0.182306f, 0.175709f, 0.172841f}, + {0.590743f, 0.55979f, 0.53326f, 0.508515f, 0.480983f, 0.447398f, 0.40746f, 0.363325f, 0.318528f, 0.276934f, 0.24163f, 0.21438f, 0.195177f, 0.182969f, 0.17617f, 0.173308f}, + {0.694721f, 0.653117f, 0.630746f, 0.599736f, 0.55546f, 0.501161f, 0.44235f, 0.383795f, 0.329462f, 0.282226f, 0.243926f, 0.215236f, 0.195439f, 0.183031f, 0.1762f, 0.173381f}, + {0.796946f, 0.777413f, 0.737044f, 0.672694f, 0.600192f, 0.52694f, 0.456453f, 0.391079f, 0.332955f, 0.283699f, 0.244465f, 0.21533f, 0.195385f, 0.182961f, 0.176174f, 0.173394f}, + {0.919721f, 0.860566f, 0.775828f, 0.691594f, 0.609891f, 0.532017f, 0.459009f, 0.392386f, 0.333517f, 0.283911f, 0.244491f, 0.215313f, 0.195357f, 0.182929f, 0.176145f, 0.173382f} + }, + { + {0.233345f, 0.22086f, 0.210077f, 0.199823f, 0.189677f, 0.179491f, 0.169098f, 0.158453f, 0.147627f, 0.136759f, 0.126225f, 0.116444f, 0.107665f, 0.100043f, 0.0935449f, 0.088001f}, + {0.238375f, 0.226926f, 0.216973f, 0.207378f, 0.197895f, 0.188246f, 0.178381f, 0.168226f, 0.157875f, 0.147538f, 0.13752f, 0.128228f, 0.120034f, 0.112982f, 0.107133f, 0.102242f}, + {0.244451f, 0.233977f, 0.224739f, 0.215724f, 0.206708f, 0.197512f, 0.188066f, 0.178321f, 0.168365f, 0.158408f, 0.14886f, 0.140123f, 0.132574f, 0.126303f, 0.121321f, 0.117476f}, + {0.252138f, 0.242441f, 0.233745f, 0.225111f, 0.216411f, 0.207513f, 0.198284f, 0.188768f, 0.179029f, 0.169332f, 0.160149f, 0.151936f, 0.145088f, 0.139702f, 0.135776f, 0.13315f}, + {0.261947f, 0.252808f, 0.244407f, 0.236006f, 0.227423f, 0.21855f, 0.209337f, 0.199763f, 0.189992f, 0.180366f, 0.171372f, 0.163568f, 0.157343f, 0.152882f, 0.150014f, 0.148586f}, + {0.274662f, 0.265818f, 0.257413f, 0.248919f, 0.240202f, 0.231116f, 0.221556f, 0.211648f, 0.201533f, 0.19166f, 0.182589f, 0.175014f, 0.169302f, 0.165539f, 0.163524f, 0.162952f}, + {0.291286f, 0.282361f, 0.273731f, 0.264822f, 0.255567f, 0.245853f, 0.235567f, 0.224853f, 0.214024f, 0.203532f, 0.194131f, 0.186454f, 0.180866f, 0.177369f, 0.17572f, 0.175488f}, + {0.313271f, 0.303909f, 0.294539f, 0.284834f, 0.274553f, 0.26362f, 0.252168f, 0.240141f, 0.228112f, 0.216569f, 0.206319f, 0.197982f, 0.191879f, 0.188001f, 0.18605f, 0.18564f}, + {0.342526f, 0.332183f, 0.321664f, 0.310442f, 0.298482f, 0.28583f, 0.272465f, 0.258641f, 0.244722f, 0.231416f, 0.219425f, 0.209452f, 0.201953f, 0.196923f, 0.194098f, 0.193098f}, + {0.381633f, 0.369694f, 0.357053f, 0.343564f, 0.329179f, 0.313965f, 0.298023f, 0.281547f, 0.264811f, 0.248428f, 0.233245f, 0.22026f, 0.210311f, 0.203547f, 0.199673f, 0.198112f}, + {0.433793f, 0.419121f, 0.403378f, 0.386517f, 0.368769f, 0.350206f, 0.330755f, 0.310245f, 0.288629f, 0.266745f, 0.246321f, 0.229288f, 0.216617f, 0.20827f, 0.203539f, 0.201486f}, + {0.503137f, 0.483345f, 0.462695f, 0.44151f, 0.419955f, 0.397224f, 0.372085f, 0.343987f, 0.313753f, 0.283801f, 0.257079f, 0.235752f, 0.220502f, 0.210798f, 0.205367f, 0.203058f}, + {0.592324f, 0.56232f, 0.53634f, 0.511965f, 0.486048f, 0.45505f, 0.418131f, 0.376965f, 0.334901f, 0.295919f, 0.263309f, 0.238781f, 0.222011f, 0.211635f, 0.205965f, 0.203611f}, + {0.695136f, 0.652781f, 0.630336f, 0.601762f, 0.561141f, 0.51034f, 0.454456f, 0.398306f, 0.346176f, 0.301288f, 0.265631f, 0.239684f, 0.222339f, 0.211762f, 0.206038f, 0.203699f}, + {0.795819f, 0.775221f, 0.738895f, 0.67858f, 0.60902f, 0.538053f, 0.469481f, 0.40592f, 0.349727f, 0.302746f, 0.266157f, 0.239788f, 0.222307f, 0.211711f, 0.206024f, 0.203713f}, + {0.919101f, 0.86371f, 0.781466f, 0.699412f, 0.619639f, 0.543528f, 0.472186f, 0.407257f, 0.350284f, 0.302945f, 0.266177f, 0.239773f, 0.222282f, 0.211683f, 0.205997f, 0.203701f} + }, + { + {0.258907f, 0.246356f, 0.235502f, 0.225041f, 0.214616f, 0.204028f, 0.193072f, 0.181656f, 0.169838f, 0.157772f, 0.145956f, 0.134961f, 0.125146f, 0.116685f, 0.109506f, 0.103382f}, + {0.263349f, 0.251927f, 0.242005f, 0.232324f, 0.222689f, 0.212789f, 0.202522f, 0.191782f, 0.180648f, 0.169348f, 0.158293f, 0.148023f, 0.139025f, 0.131334f, 0.124989f, 0.119678f}, + {0.26867f, 0.258315f, 0.24921f, 0.240227f, 0.231186f, 0.221882f, 0.212196f, 0.202055f, 0.191523f, 0.180837f, 0.170507f, 0.16106f, 0.152972f, 0.146321f, 0.141076f, 0.137036f}, + {0.275412f, 0.265922f, 0.257459f, 0.248968f, 0.240365f, 0.231488f, 0.222188f, 0.212457f, 0.202347f, 0.192157f, 0.182455f, 0.17383f, 0.16675f, 0.161288f, 0.157387f, 0.154826f}, + {0.284035f, 0.27519f, 0.267124f, 0.258963f, 0.250598f, 0.241898f, 0.232756f, 0.223148f, 0.213207f, 0.203323f, 0.194092f, 0.1862f, 0.180093f, 0.175908f, 0.17338f, 0.172288f}, + {0.295274f, 0.286808f, 0.278826f, 0.270681f, 0.262297f, 0.253533f, 0.244202f, 0.23442f, 0.224343f, 0.214453f, 0.205448f, 0.198153f, 0.192962f, 0.189855f, 0.188503f, 0.188502f}, + {0.310069f, 0.301603f, 0.293482f, 0.285039f, 0.276244f, 0.26698f, 0.257092f, 0.246671f, 0.236076f, 0.225837f, 0.216858f, 0.209892f, 0.205272f, 0.202825f, 0.202128f, 0.202634f}, + {0.329793f, 0.320985f, 0.312223f, 0.303105f, 0.293424f, 0.283068f, 0.272163f, 0.260612f, 0.24904f, 0.238068f, 0.228677f, 0.221566f, 0.216913f, 0.214449f, 0.213668f, 0.214076f}, + {0.356322f, 0.346634f, 0.336842f, 0.326332f, 0.315095f, 0.303163f, 0.290492f, 0.27734f, 0.264178f, 0.251874f, 0.241298f, 0.233115f, 0.22754f, 0.224227f, 0.222693f, 0.222503f}, + {0.392238f, 0.381076f, 0.369321f, 0.35665f, 0.343095f, 0.328732f, 0.313643f, 0.298115f, 0.282585f, 0.267806f, 0.25468f, 0.244043f, 0.236381f, 0.231516f, 0.228979f, 0.228194f}, + {0.440867f, 0.427111f, 0.412452f, 0.396466f, 0.379608f, 0.362005f, 0.343667f, 0.324622f, 0.304928f, 0.285361f, 0.267539f, 0.253254f, 0.243153f, 0.236841f, 0.233458f, 0.232102f}, + {0.506717f, 0.487997f, 0.468576f, 0.448089f, 0.427412f, 0.405926f, 0.382646f, 0.356947f, 0.329352f, 0.302177f, 0.278386f, 0.260022f, 0.247431f, 0.23976f, 0.23561f, 0.233916f}, + {0.593192f, 0.564277f, 0.539059f, 0.514959f, 0.4905f, 0.461974f, 0.428121f, 0.390063f, 0.350845f, 0.314561f, 0.284786f, 0.263211f, 0.249118f, 0.240763f, 0.236337f, 0.234546f}, + {0.69495f, 0.652106f, 0.629305f, 0.602994f, 0.566049f, 0.518994f, 0.466269f, 0.4126f, 0.362632f, 0.320051f, 0.287129f, 0.264149f, 0.249505f, 0.240948f, 0.23645f, 0.234644f}, + {0.79443f, 0.77234f, 0.740076f, 0.684182f, 0.617848f, 0.549283f, 0.482602f, 0.420725f, 0.366297f, 0.321495f, 0.287634f, 0.264256f, 0.249489f, 0.240914f, 0.236443f, 0.234657f}, + {0.918215f, 0.866875f, 0.787313f, 0.707521f, 0.62971f, 0.555326f, 0.485537f, 0.42212f, 0.36685f, 0.321679f, 0.287645f, 0.264241f, 0.249468f, 0.240889f, 0.236419f, 0.234644f} + } +}; + +static const float table_ggx_dielectric_inv_E[16][16][16] = { + { + {0.00235046f, 0.000951943f, 0.000961408f, 0.000944843f, 0.000942617f, 0.000910931f, 0.000859474f, 0.000767562f, 0.000483162f, 0.000109375f, 2.0597e-05f, 8.06816e-06f, 4.16443e-06f, 2.50755e-06f, 1.72255e-06f, 1.30155e-06f}, + {0.00292426f, 0.00126262f, 0.00125521f, 0.00125754f, 0.00122733f, 0.00121732f, 0.00114463f, 0.000989368f, 0.000632914f, 0.000142431f, 2.66276e-05f, 1.02422e-05f, 5.15253e-06f, 3.05061e-06f, 2.06668e-06f, 1.56083e-06f}, + {0.00379196f, 0.00171564f, 0.00171269f, 0.00165289f, 0.00165397f, 0.00163529f, 0.00152361f, 0.00136859f, 0.000883173f, 0.000198944f, 3.48297e-05f, 1.30138e-05f, 6.42139e-06f, 3.68929e-06f, 2.45527e-06f, 1.84825e-06f}, + {0.00489294f, 0.00234044f, 0.00235165f, 0.00228443f, 0.00231354f, 0.0022399f, 0.00210313f, 0.00188593f, 0.00122852f, 0.000277262f, 4.53518e-05f, 1.67627e-05f, 7.96693e-06f, 4.44151e-06f, 2.86604e-06f, 2.15288e-06f}, + {0.00654822f, 0.00330384f, 0.00326599f, 0.00332878f, 0.00324631f, 0.00311872f, 0.00296925f, 0.00264568f, 0.00170292f, 0.000382511f, 6.16924e-05f, 2.16883e-05f, 9.80968e-06f, 5.31534e-06f, 3.31121e-06f, 2.44751e-06f}, + {0.00913796f, 0.00477424f, 0.00471521f, 0.00465233f, 0.00456819f, 0.00453247f, 0.00432436f, 0.00385269f, 0.00251536f, 0.000564706f, 8.36937e-05f, 2.81617e-05f, 1.21565e-05f, 6.21127e-06f, 3.73044e-06f, 2.71501e-06f}, + {0.013057f, 0.00697927f, 0.00696658f, 0.00691162f, 0.00678196f, 0.00671759f, 0.00633212f, 0.00567344f, 0.00374109f, 0.00082046f, 0.000113712f, 3.64343e-05f, 1.48833e-05f, 7.16424e-06f, 4.11499e-06f, 2.93366e-06f}, + {0.0196329f, 0.0106535f, 0.0106754f, 0.0105994f, 0.0104252f, 0.0101732f, 0.00979063f, 0.00870428f, 0.00580175f, 0.0012363f, 0.000156536f, 4.63773e-05f, 1.78193e-05f, 8.01439e-06f, 4.40462e-06f, 3.10493e-06f}, + {0.0307183f, 0.017078f, 0.0170033f, 0.0168447f, 0.0166372f, 0.0162504f, 0.015506f, 0.014051f, 0.0091717f, 0.00191149f, 0.000213538f, 5.78316e-05f, 2.03798e-05f, 8.56422e-06f, 4.52944e-06f, 3.18388e-06f}, + {0.0498417f, 0.0284268f, 0.0283445f, 0.0282314f, 0.0277786f, 0.0271021f, 0.0259388f, 0.0230949f, 0.0149652f, 0.00295227f, 0.000283693f, 6.87379e-05f, 2.22055e-05f, 8.80754e-06f, 4.52383e-06f, 3.21753e-06f}, + {0.0850979f, 0.0499708f, 0.0496497f, 0.0493275f, 0.0489081f, 0.0475654f, 0.0451105f, 0.0399589f, 0.0250828f, 0.00439737f, 0.000354752f, 7.63431e-05f, 2.2707e-05f, 8.61899e-06f, 4.40055e-06f, 3.20354e-06f}, + {0.148511f, 0.0910268f, 0.0905886f, 0.0901549f, 0.0886084f, 0.0862489f, 0.0814294f, 0.0714472f, 0.041587f, 0.00605564f, 0.000405501f, 7.80517e-05f, 2.20026e-05f, 8.2124e-06f, 4.23526e-06f, 3.17388e-06f}, + {0.256514f, 0.167553f, 0.166978f, 0.16535f, 0.162499f, 0.157414f, 0.147243f, 0.124061f, 0.0627375f, 0.00674164f, 0.000406886f, 7.47395e-05f, 2.06823e-05f, 7.70742e-06f, 4.08045e-06f, 3.1554e-06f}, + {0.421582f, 0.29785f, 0.295744f, 0.292154f, 0.284839f, 0.270982f, 0.244869f, 0.188637f, 0.0713664f, 0.00569746f, 0.000377401f, 6.98215e-05f, 1.95624e-05f, 7.38927e-06f, 3.98503e-06f, 3.12683e-06f}, + {0.626533f, 0.482942f, 0.47802f, 0.466367f, 0.443574f, 0.402265f, 0.329363f, 0.204388f, 0.052521f, 0.0041677f, 0.000353535f, 6.71368e-05f, 1.89508e-05f, 7.22614e-06f, 3.94896e-06f, 3.12279e-06f}, + {0.846947f, 0.743587f, 0.698557f, 0.628086f, 0.533342f, 0.41755f, 0.285614f, 0.146935f, 0.0364554f, 0.00362315f, 0.000344775f, 6.62138e-05f, 1.88029e-05f, 7.19353e-06f, 3.9378e-06f, 3.12169e-06f} + }, + { + {0.0244329f, 0.00842994f, 0.006394f, 0.00640485f, 0.00633785f, 0.00624147f, 0.00604983f, 0.00565578f, 0.00498872f, 0.00337949f, 0.0013252f, 0.000348669f, 0.000147759f, 8.35719e-05f, 5.55069e-05f, 4.12674e-05f}, + {0.0299837f, 0.0109985f, 0.00847027f, 0.00841811f, 0.00843469f, 0.00824875f, 0.00801624f, 0.00759303f, 0.00664631f, 0.0045765f, 0.00177292f, 0.000447897f, 0.000184027f, 0.000101736f, 6.64771e-05f, 4.92692e-05f}, + {0.0370611f, 0.0147832f, 0.0113699f, 0.0114045f, 0.0112426f, 0.0110887f, 0.0108451f, 0.0101365f, 0.00892974f, 0.00620864f, 0.00240134f, 0.000588074f, 0.000230868f, 0.000123335f, 7.87936e-05f, 5.8044e-05f}, + {0.0470884f, 0.0196336f, 0.0154454f, 0.0154247f, 0.0153079f, 0.0150225f, 0.0146064f, 0.0138626f, 0.0122651f, 0.00844913f, 0.00324915f, 0.000772161f, 0.00028898f, 0.000148694f, 9.20002e-05f, 6.72561e-05f}, + {0.0607736f, 0.0269073f, 0.0213857f, 0.0213109f, 0.0211384f, 0.0208545f, 0.020306f, 0.0192818f, 0.0170124f, 0.0118553f, 0.00458119f, 0.00101911f, 0.000359396f, 0.000178073f, 0.000106031f, 7.625e-05f}, + {0.081171f, 0.0375754f, 0.0300765f, 0.03013f, 0.0297314f, 0.0293184f, 0.028634f, 0.0270088f, 0.0240609f, 0.0167986f, 0.00634564f, 0.00136142f, 0.000447205f, 0.000208822f, 0.000119347f, 8.4328e-05f}, + {0.110621f, 0.0534742f, 0.0431979f, 0.042905f, 0.0426605f, 0.0419236f, 0.0409884f, 0.0389714f, 0.0344307f, 0.0239731f, 0.00889508f, 0.0018045f, 0.000549877f, 0.000240845f, 0.000131173f, 9.08705e-05f}, + {0.154343f, 0.0776604f, 0.0630826f, 0.0630305f, 0.0622461f, 0.0614756f, 0.059931f, 0.0568346f, 0.0501378f, 0.0345007f, 0.0124085f, 0.00229981f, 0.000658126f, 0.000269135f, 0.00013977f, 9.56597e-05f}, + {0.218105f, 0.115695f, 0.0940303f, 0.0935214f, 0.0930068f, 0.0916361f, 0.0890005f, 0.0843393f, 0.0741019f, 0.0500846f, 0.0169989f, 0.002889f, 0.000751429f, 0.000286759f, 0.000143284f, 9.79578e-05f}, + {0.309745f, 0.174004f, 0.141545f, 0.141101f, 0.139981f, 0.137816f, 0.133782f, 0.126079f, 0.109716f, 0.0711239f, 0.02197f, 0.00339885f, 0.000811512f, 0.000292177f, 0.000142314f, 9.86812e-05f}, + {0.432884f, 0.261728f, 0.213141f, 0.21237f, 0.210333f, 0.206437f, 0.199598f, 0.186483f, 0.158926f, 0.095884f, 0.0258213f, 0.00359798f, 0.000817069f, 0.000283412f, 0.000137777f, 9.81187e-05f}, + {0.582453f, 0.38569f, 0.312282f, 0.310865f, 0.307326f, 0.30057f, 0.288063f, 0.264968f, 0.215487f, 0.115438f, 0.0260455f, 0.00346903f, 0.000776098f, 0.000266992f, 0.000131878f, 9.71014e-05f}, + {0.73921f, 0.536662f, 0.432523f, 0.429408f, 0.422737f, 0.410008f, 0.387164f, 0.343455f, 0.256244f, 0.113904f, 0.0215896f, 0.00304996f, 0.000713029f, 0.000248363f, 0.000126622f, 9.62588e-05f}, + {0.872866f, 0.684184f, 0.555088f, 0.548767f, 0.535485f, 0.510279f, 0.464582f, 0.381586f, 0.243471f, 0.0880175f, 0.0159727f, 0.00263818f, 0.000662592f, 0.00023626f, 0.000123267f, 9.5507e-05f}, + {0.959391f, 0.805625f, 0.67916f, 0.664178f, 0.631547f, 0.571153f, 0.472016f, 0.334013f, 0.181333f, 0.062308f, 0.0127135f, 0.00243179f, 0.000636559f, 0.000230455f, 0.000121931f, 9.53293e-05f}, + {0.995178f, 0.921013f, 0.829452f, 0.756155f, 0.650956f, 0.525634f, 0.39339f, 0.265033f, 0.146666f, 0.0541665f, 0.0119003f, 0.00237358f, 0.000630409f, 0.000229067f, 0.000121523f, 9.52288e-05f} + }, + { + {0.0751656f, 0.0367766f, 0.019101f, 0.0168419f, 0.016786f, 0.0166478f, 0.0163151f, 0.0158158f, 0.0149666f, 0.0132243f, 0.00974355f, 0.0048222f, 0.0016387f, 0.000675244f, 0.000409438f, 0.000292956f}, + {0.0894614f, 0.0465185f, 0.0249504f, 0.0220886f, 0.021999f, 0.0217885f, 0.0214024f, 0.0208124f, 0.0196682f, 0.0174213f, 0.0128789f, 0.0064365f, 0.00210836f, 0.000827055f, 0.000488908f, 0.000347008f}, + {0.108132f, 0.0593809f, 0.0328083f, 0.0291563f, 0.0291384f, 0.02888f, 0.0284616f, 0.0276406f, 0.0261488f, 0.0232205f, 0.0171749f, 0.00849331f, 0.00271977f, 0.00100872f, 0.000578115f, 0.000405619f}, + {0.132802f, 0.0767836f, 0.043639f, 0.0390422f, 0.038907f, 0.0385462f, 0.0381019f, 0.0369371f, 0.0350749f, 0.0309741f, 0.023102f, 0.0113499f, 0.00350794f, 0.00122447f, 0.00067375f, 0.000466471f}, + {0.165866f, 0.100828f, 0.0588934f, 0.0527454f, 0.0524788f, 0.0521715f, 0.0513304f, 0.0499157f, 0.0472961f, 0.0420834f, 0.0311871f, 0.0153008f, 0.00446775f, 0.00147497f, 0.000774432f, 0.000525244f}, + {0.210055f, 0.134164f, 0.0800222f, 0.0719804f, 0.0717665f, 0.0713139f, 0.070094f, 0.0681393f, 0.0646811f, 0.0574924f, 0.0424442f, 0.0203313f, 0.00564984f, 0.00173703f, 0.000868731f, 0.000577233f}, + {0.268108f, 0.18056f, 0.110085f, 0.0992329f, 0.0987635f, 0.0978436f, 0.0965255f, 0.0938618f, 0.0888379f, 0.078708f, 0.0577296f, 0.0267312f, 0.00705713f, 0.00200662f, 0.000950174f, 0.0006183f}, + {0.343828f, 0.2451f, 0.152077f, 0.13708f, 0.136523f, 0.135426f, 0.133423f, 0.129364f, 0.12248f, 0.107812f, 0.0774975f, 0.0343422f, 0.00849988f, 0.00223365f, 0.00100541f, 0.000646534f}, + {0.437388f, 0.332662f, 0.211163f, 0.18931f, 0.188563f, 0.186922f, 0.183696f, 0.178102f, 0.167266f, 0.145955f, 0.101239f, 0.0418692f, 0.00947501f, 0.00235196f, 0.00102217f, 0.000658775f}, + {0.545163f, 0.446723f, 0.289934f, 0.258759f, 0.257352f, 0.254701f, 0.249871f, 0.241149f, 0.224767f, 0.19176f, 0.125957f, 0.0467954f, 0.00978588f, 0.00235237f, 0.00100425f, 0.00066008f}, + {0.657315f, 0.584786f, 0.389181f, 0.343744f, 0.341835f, 0.337639f, 0.32988f, 0.315875f, 0.289908f, 0.237973f, 0.142579f, 0.0466273f, 0.0091475f, 0.00222421f, 0.000960668f, 0.000654003f}, + {0.760562f, 0.733439f, 0.502646f, 0.437962f, 0.434678f, 0.427794f, 0.415218f, 0.392508f, 0.350177f, 0.269557f, 0.141523f, 0.0400829f, 0.0078249f, 0.00203728f, 0.000908712f, 0.000645139f}, + {0.846733f, 0.866769f, 0.616993f, 0.531188f, 0.525637f, 0.51422f, 0.493019f, 0.454742f, 0.385057f, 0.265782f, 0.118204f, 0.030316f, 0.00638598f, 0.00183471f, 0.0008641f, 0.000637678f}, + {0.916567f, 0.955333f, 0.722745f, 0.621582f, 0.611615f, 0.590612f, 0.551808f, 0.482835f, 0.370677f, 0.220863f, 0.0871105f, 0.0226231f, 0.00540626f, 0.00171013f, 0.000836098f, 0.000632195f}, + {0.968631f, 0.991759f, 0.820946f, 0.723191f, 0.700359f, 0.652293f, 0.568187f, 0.446373f, 0.303762f, 0.167936f, 0.0675108f, 0.0189695f, 0.00495632f, 0.00165292f, 0.000824656f, 0.000630514f}, + {0.995687f, 0.999509f, 0.926352f, 0.841634f, 0.754113f, 0.637517f, 0.508604f, 0.380662f, 0.258826f, 0.148263f, 0.0622874f, 0.0181671f, 0.00486165f, 0.00163969f, 0.00082149f, 0.000629823f} + }, + { + {0.147887f, 0.0887551f, 0.0525506f, 0.0336697f, 0.0320708f, 0.0319812f, 0.0316011f, 0.0311545f, 0.0302589f, 0.0285675f, 0.0253974f, 0.0194028f, 0.0109172f, 0.00423459f, 0.00179321f, 0.00115721f}, + {0.172219f, 0.108738f, 0.0668147f, 0.0434863f, 0.0415335f, 0.0412836f, 0.0408824f, 0.040265f, 0.0390682f, 0.0369916f, 0.0329611f, 0.0252202f, 0.0139996f, 0.00534759f, 0.00214176f, 0.00135621f}, + {0.202753f, 0.134704f, 0.0853529f, 0.0565107f, 0.0538888f, 0.0536067f, 0.0532631f, 0.052446f, 0.0508731f, 0.0482355f, 0.0429877f, 0.0327421f, 0.0181888f, 0.00663745f, 0.00253168f, 0.0015688f}, + {0.24096f, 0.168221f, 0.109942f, 0.0737677f, 0.0705636f, 0.0701521f, 0.0696892f, 0.0686022f, 0.0667101f, 0.0631255f, 0.0561702f, 0.04286f, 0.023411f, 0.00824675f, 0.0029488f, 0.00178627f}, + {0.289319f, 0.211379f, 0.142638f, 0.097021f, 0.0929139f, 0.0923694f, 0.0916507f, 0.0902359f, 0.0877175f, 0.0829596f, 0.0739655f, 0.0560281f, 0.0298796f, 0.0100867f, 0.003386f, 0.00199171f}, + {0.348651f, 0.26769f, 0.186389f, 0.127819f, 0.12236f, 0.121796f, 0.120808f, 0.118847f, 0.11558f, 0.109217f, 0.0968423f, 0.0727608f, 0.0377663f, 0.0119591f, 0.0037803f, 0.00216842f}, + {0.419802f, 0.339148f, 0.24474f, 0.16864f, 0.16129f, 0.160593f, 0.159048f, 0.156579f, 0.151899f, 0.14329f, 0.126402f, 0.093001f, 0.0464131f, 0.0138692f, 0.00410832f, 0.00230137f}, + {0.50202f, 0.427135f, 0.32085f, 0.221678f, 0.21154f, 0.210483f, 0.208505f, 0.204823f, 0.19837f, 0.186229f, 0.162298f, 0.116091f, 0.0544602f, 0.0152887f, 0.00429646f, 0.00238356f}, + {0.590805f, 0.529984f, 0.417997f, 0.28796f, 0.273544f, 0.272273f, 0.269371f, 0.264244f, 0.254641f, 0.237279f, 0.202921f, 0.13829f, 0.0598109f, 0.0154655f, 0.00428314f, 0.00240749f}, + {0.680075f, 0.641818f, 0.534622f, 0.36668f, 0.346549f, 0.344474f, 0.340224f, 0.332542f, 0.318505f, 0.292676f, 0.242488f, 0.153857f, 0.0596481f, 0.0145358f, 0.00411044f, 0.0023916f}, + {0.761356f, 0.752583f, 0.66489f, 0.453291f, 0.424808f, 0.421695f, 0.415246f, 0.403503f, 0.382529f, 0.343708f, 0.27069f, 0.154824f, 0.0529199f, 0.0126267f, 0.00381654f, 0.00235378f}, + {0.828679f, 0.852804f, 0.792013f, 0.542644f, 0.503055f, 0.498088f, 0.488193f, 0.470136f, 0.437773f, 0.378636f, 0.275176f, 0.137074f, 0.0418347f, 0.0103108f, 0.00350289f, 0.0023083f}, + {0.882398f, 0.93324f, 0.894998f, 0.629542f, 0.577138f, 0.569241f, 0.553434f, 0.524452f, 0.472406f, 0.382528f, 0.246334f, 0.106754f, 0.0309094f, 0.00825209f, 0.00324481f, 0.00227136f}, + {0.930465f, 0.981104f, 0.959582f, 0.715904f, 0.652872f, 0.639048f, 0.610964f, 0.559312f, 0.471807f, 0.342853f, 0.195018f, 0.0790131f, 0.0236881f, 0.00710443f, 0.00309393f, 0.00224701f}, + {0.971888f, 0.997444f, 0.988897f, 0.808936f, 0.743055f, 0.712149f, 0.649785f, 0.548452f, 0.416932f, 0.277413f, 0.153749f, 0.0646395f, 0.0206423f, 0.00660389f, 0.00303106f, 0.00223869f}, + {0.995977f, 0.999908f, 0.998167f, 0.917771f, 0.837809f, 0.739119f, 0.616399f, 0.488237f, 0.363493f, 0.246053f, 0.140903f, 0.0612141f, 0.0199892f, 0.00650528f, 0.0030159f, 0.002236f} + }, + { + {0.234099f, 0.157694f, 0.107168f, 0.0700248f, 0.0530869f, 0.0526462f, 0.0523807f, 0.0519568f, 0.0511113f, 0.0496138f, 0.0468662f, 0.0416525f, 0.0319327f, 0.0185243f, 0.00761253f, 0.00346402f}, + {0.267094f, 0.188349f, 0.132347f, 0.0880624f, 0.0675447f, 0.0668504f, 0.066486f, 0.065846f, 0.0649024f, 0.0628994f, 0.0595416f, 0.0528147f, 0.0404812f, 0.0231104f, 0.00912842f, 0.00401013f}, + {0.306616f, 0.226182f, 0.164165f, 0.111474f, 0.0858023f, 0.0849425f, 0.0846839f, 0.0838376f, 0.0825208f, 0.0801044f, 0.0757554f, 0.0671588f, 0.0511811f, 0.028788f, 0.0109045f, 0.00458291f}, + {0.353746f, 0.273178f, 0.204727f, 0.141714f, 0.109333f, 0.108355f, 0.107773f, 0.106837f, 0.105241f, 0.102064f, 0.0964199f, 0.0854883f, 0.0645148f, 0.0354868f, 0.0127577f, 0.00516251f}, + {0.409344f, 0.329885f, 0.255636f, 0.180314f, 0.139468f, 0.138281f, 0.137515f, 0.136282f, 0.134046f, 0.130071f, 0.122808f, 0.108229f, 0.0807627f, 0.0431881f, 0.0147009f, 0.00568418f}, + {0.473484f, 0.398349f, 0.319811f, 0.229676f, 0.177615f, 0.175845f, 0.174969f, 0.173416f, 0.170356f, 0.165266f, 0.155393f, 0.13621f, 0.099696f, 0.0509202f, 0.0162805f, 0.00611045f}, + {0.544024f, 0.477611f, 0.398766f, 0.291978f, 0.224712f, 0.222418f, 0.22119f, 0.218979f, 0.21512f, 0.207861f, 0.194804f, 0.16886f, 0.120189f, 0.0580256f, 0.0174809f, 0.00639845f}, + {0.61913f, 0.565312f, 0.492898f, 0.369287f, 0.281146f, 0.277875f, 0.276402f, 0.273429f, 0.268044f, 0.25815f, 0.240075f, 0.204322f, 0.139353f, 0.0626336f, 0.0177423f, 0.0065324f}, + {0.693559f, 0.656233f, 0.59942f, 0.461165f, 0.345586f, 0.341257f, 0.339151f, 0.334856f, 0.327185f, 0.31358f, 0.287947f, 0.238509f, 0.152605f, 0.0625432f, 0.0169536f, 0.00649506f}, + {0.763041f, 0.743727f, 0.711084f, 0.56582f, 0.41485f, 0.408813f, 0.405645f, 0.399721f, 0.388695f, 0.369022f, 0.332624f, 0.263691f, 0.154396f, 0.056694f, 0.0151914f, 0.00635182f}, + {0.821954f, 0.823152f, 0.817676f, 0.675577f, 0.484669f, 0.476055f, 0.471564f, 0.462704f, 0.44677f, 0.418203f, 0.365716f, 0.271369f, 0.141171f, 0.0467529f, 0.0129973f, 0.00616609f}, + {0.867861f, 0.892188f, 0.905515f, 0.781705f, 0.553059f, 0.540725f, 0.533987f, 0.520815f, 0.496942f, 0.454198f, 0.378046f, 0.254509f, 0.115678f, 0.0357247f, 0.0109052f, 0.00597637f}, + {0.904108f, 0.95007f, 0.96385f, 0.87034f, 0.619949f, 0.602477f, 0.591961f, 0.571272f, 0.533573f, 0.467464f, 0.358432f, 0.212738f, 0.0865194f, 0.0264459f, 0.00934221f, 0.00582978f}, + {0.939797f, 0.986301f, 0.990713f, 0.933622f, 0.693342f, 0.668972f, 0.650542f, 0.614118f, 0.549052f, 0.444674f, 0.305216f, 0.164058f, 0.0651231f, 0.02118f, 0.00845222f, 0.00573999f}, + {0.974394f, 0.998266f, 0.998705f, 0.971664f, 0.783765f, 0.749853f, 0.708978f, 0.631827f, 0.516941f, 0.380589f, 0.246571f, 0.132988f, 0.0552879f, 0.0190579f, 0.00811435f, 0.00570859f}, + {0.996243f, 0.999946f, 0.999957f, 0.991948f, 0.898737f, 0.820613f, 0.711671f, 0.586169f, 0.459343f, 0.337761f, 0.224085f, 0.124623f, 0.0531018f, 0.0186455f, 0.00804229f, 0.00570015f} + }, + { + {0.326322f, 0.237317f, 0.175876f, 0.12756f, 0.08937f, 0.0794428f, 0.0791837f, 0.0788149f, 0.0782239f, 0.0768283f, 0.0744818f, 0.0703003f, 0.0618115f, 0.0461797f, 0.0256488f, 0.00993646f}, + {0.364919f, 0.276697f, 0.211547f, 0.1564f, 0.110704f, 0.0983882f, 0.098256f, 0.097825f, 0.0968578f, 0.0952844f, 0.0923921f, 0.0870316f, 0.0764738f, 0.0565963f, 0.0307442f, 0.0113955f}, + {0.409444f, 0.323566f, 0.254946f, 0.192381f, 0.137405f, 0.122148f, 0.121922f, 0.121183f, 0.120217f, 0.118206f, 0.114513f, 0.107883f, 0.0942293f, 0.069078f, 0.0363954f, 0.0128678f}, + {0.460018f, 0.378327f, 0.307211f, 0.236976f, 0.170393f, 0.151448f, 0.151089f, 0.150393f, 0.148968f, 0.146371f, 0.141815f, 0.133181f, 0.115927f, 0.0836839f, 0.0423456f, 0.0143597f}, + {0.516658f, 0.441038f, 0.369831f, 0.292194f, 0.211015f, 0.187271f, 0.186809f, 0.18583f, 0.184044f, 0.180689f, 0.17477f, 0.163569f, 0.141176f, 0.0997764f, 0.0482789f, 0.0155482f}, + {0.578018f, 0.511321f, 0.443457f, 0.359345f, 0.260433f, 0.230084f, 0.229472f, 0.228195f, 0.225764f, 0.221658f, 0.213866f, 0.199247f, 0.169913f, 0.116296f, 0.0531081f, 0.0164137f}, + {0.641619f, 0.587164f, 0.527168f, 0.439617f, 0.3194f, 0.280145f, 0.279198f, 0.277659f, 0.27447f, 0.268731f, 0.258472f, 0.239081f, 0.200245f, 0.131266f, 0.0559141f, 0.0167672f}, + {0.705877f, 0.664212f, 0.618225f, 0.533205f, 0.387809f, 0.336064f, 0.335074f, 0.33275f, 0.328609f, 0.320892f, 0.30711f, 0.280748f, 0.228737f, 0.141218f, 0.0556433f, 0.0165623f}, + {0.766043f, 0.738383f, 0.711006f, 0.636383f, 0.463718f, 0.395721f, 0.394383f, 0.39118f, 0.385345f, 0.374908f, 0.35585f, 0.319774f, 0.250036f, 0.142241f, 0.0514129f, 0.0158781f}, + {0.819727f, 0.804792f, 0.799333f, 0.742458f, 0.544725f, 0.455263f, 0.453239f, 0.448977f, 0.440863f, 0.42618f, 0.39961f, 0.349531f, 0.257523f, 0.131572f, 0.0440529f, 0.0149301f}, + {0.863146f, 0.862708f, 0.87643f, 0.83996f, 0.627929f, 0.512899f, 0.510173f, 0.50404f, 0.492387f, 0.471469f, 0.433636f, 0.364198f, 0.246257f, 0.110952f, 0.0355121f, 0.0138963f}, + {0.895522f, 0.913487f, 0.937446f, 0.91933f, 0.711217f, 0.568171f, 0.564166f, 0.555063f, 0.537968f, 0.507053f, 0.45194f, 0.35554f, 0.214034f, 0.0857041f, 0.0275724f, 0.0129888f}, + {0.920489f, 0.959231f, 0.97764f, 0.968991f, 0.787946f, 0.622884f, 0.616625f, 0.602621f, 0.575861f, 0.527986f, 0.44518f, 0.317454f, 0.168511f, 0.0629685f, 0.0219673f, 0.0123398f}, + {0.947351f, 0.989263f, 0.994774f, 0.991564f, 0.857934f, 0.686057f, 0.675252f, 0.650729f, 0.604228f, 0.52402f, 0.40323f, 0.257833f, 0.12816f, 0.0488968f, 0.0189727f, 0.0119794f}, + {0.976613f, 0.998772f, 0.999335f, 0.998762f, 0.917634f, 0.76965f, 0.746013f, 0.692329f, 0.599465f, 0.473535f, 0.336441f, 0.208975f, 0.106678f, 0.0430084f, 0.0178256f, 0.0118565f}, + {0.996496f, 0.999962f, 0.999981f, 0.999958f, 0.969935f, 0.875241f, 0.789262f, 0.672406f, 0.545605f, 0.421197f, 0.302763f, 0.19345f, 0.101512f, 0.0417932f, 0.0175873f, 0.0118287f} + }, + { + {0.4178f, 0.321643f, 0.253033f, 0.196916f, 0.14778f, 0.114968f, 0.112698f, 0.112542f, 0.111936f, 0.110872f, 0.108918f, 0.105425f, 0.0985664f, 0.08448f, 0.0590056f, 0.0272137f}, + {0.459266f, 0.366832f, 0.297123f, 0.23568f, 0.178743f, 0.139151f, 0.136307f, 0.136093f, 0.135296f, 0.134009f, 0.131659f, 0.127321f, 0.11882f, 0.101096f, 0.0693955f, 0.0308438f}, + {0.505272f, 0.418439f, 0.348338f, 0.282091f, 0.216317f, 0.168111f, 0.164614f, 0.164171f, 0.163434f, 0.161678f, 0.15877f, 0.153426f, 0.142889f, 0.120549f, 0.080913f, 0.0343671f}, + {0.555067f, 0.476052f, 0.407398f, 0.337213f, 0.261299f, 0.202519f, 0.198423f, 0.197759f, 0.196755f, 0.194572f, 0.19094f, 0.184245f, 0.170751f, 0.142719f, 0.0928972f, 0.037582f}, + {0.608245f, 0.538798f, 0.474411f, 0.402399f, 0.3154f, 0.243251f, 0.23766f, 0.237f, 0.235493f, 0.233008f, 0.22834f, 0.219783f, 0.202494f, 0.166761f, 0.104536f, 0.0401457f}, + {0.663529f, 0.605003f, 0.548505f, 0.477763f, 0.379232f, 0.289475f, 0.282604f, 0.281619f, 0.279902f, 0.276593f, 0.27052f, 0.259414f, 0.237165f, 0.191092f, 0.11404f, 0.0413962f}, + {0.71836f, 0.672436f, 0.626925f, 0.562112f, 0.453294f, 0.341467f, 0.33243f, 0.331225f, 0.328874f, 0.324343f, 0.316598f, 0.301931f, 0.27282f, 0.213199f, 0.119482f, 0.041063f}, + {0.771377f, 0.737092f, 0.706233f, 0.653006f, 0.537417f, 0.397007f, 0.38521f, 0.383645f, 0.380565f, 0.374684f, 0.364288f, 0.344772f, 0.306171f, 0.22939f, 0.118518f, 0.0392006f}, + {0.819566f, 0.795914f, 0.781435f, 0.744897f, 0.627982f, 0.453955f, 0.438649f, 0.436488f, 0.43212f, 0.424367f, 0.410159f, 0.383862f, 0.332099f, 0.234084f, 0.109683f, 0.0358741f}, + {0.861272f, 0.846474f, 0.849208f, 0.830732f, 0.721333f, 0.509741f, 0.48907f, 0.486258f, 0.480367f, 0.469569f, 0.450136f, 0.413952f, 0.344625f, 0.223159f, 0.0941158f, 0.0318545f}, + {0.893781f, 0.889538f, 0.906589f, 0.901515f, 0.811664f, 0.565494f, 0.538077f, 0.534047f, 0.525791f, 0.510615f, 0.483189f, 0.432798f, 0.339807f, 0.196909f, 0.0750987f, 0.0281018f}, + {0.916967f, 0.928056f, 0.952651f, 0.95546f, 0.891426f, 0.62134f, 0.584718f, 0.578819f, 0.566817f, 0.544554f, 0.504692f, 0.432669f, 0.311163f, 0.15866f, 0.0571654f, 0.0249806f}, + {0.93371f, 0.965543f, 0.984134f, 0.984963f, 0.948403f, 0.679691f, 0.632162f, 0.623131f, 0.60451f, 0.570084f, 0.508621f, 0.40557f, 0.259927f, 0.119399f, 0.0439549f, 0.0228667f}, + {0.953781f, 0.991452f, 0.996725f, 0.996541f, 0.982505f, 0.746117f, 0.689189f, 0.673492f, 0.641111f, 0.581826f, 0.483737f, 0.347913f, 0.202973f, 0.0915104f, 0.0366374f, 0.0217775f}, + {0.97858f, 0.999134f, 0.999654f, 0.999522f, 0.996762f, 0.826366f, 0.765724f, 0.731078f, 0.661596f, 0.552974f, 0.419804f, 0.284661f, 0.16641f, 0.0788318f, 0.0338895f, 0.0214004f}, + {0.996735f, 0.999974f, 0.999992f, 0.99998f, 0.999865f, 0.925031f, 0.84534f, 0.74417f, 0.621607f, 0.495845f, 0.374385f, 0.259803f, 0.156444f, 0.076019f, 0.033306f, 0.021326f} + }, + { + {0.504721f, 0.405656f, 0.333871f, 0.27326f, 0.218098f, 0.168263f, 0.153204f, 0.152959f, 0.152613f, 0.151675f, 0.150045f, 0.147501f, 0.141915f, 0.130455f, 0.105276f, 0.0608581f}, + {0.546314f, 0.454163f, 0.383238f, 0.319359f, 0.257925f, 0.198927f, 0.180583f, 0.180298f, 0.179739f, 0.178791f, 0.176811f, 0.173406f, 0.166785f, 0.152599f, 0.121462f, 0.0677835f}, + {0.590617f, 0.506754f, 0.438464f, 0.372616f, 0.304466f, 0.234308f, 0.212233f, 0.21193f, 0.21129f, 0.209959f, 0.207612f, 0.203546f, 0.195293f, 0.17761f, 0.139042f, 0.0743825f}, + {0.637251f, 0.563469f, 0.499414f, 0.43351f, 0.35882f, 0.275688f, 0.248375f, 0.248021f, 0.247283f, 0.245785f, 0.242865f, 0.237589f, 0.227375f, 0.205188f, 0.156803f, 0.0800607f}, + {0.68492f, 0.622157f, 0.565315f, 0.501912f, 0.42159f, 0.322982f, 0.289239f, 0.288775f, 0.287606f, 0.285657f, 0.28215f, 0.275532f, 0.262504f, 0.234414f, 0.174306f, 0.0840276f}, + {0.732458f, 0.681506f, 0.634346f, 0.576929f, 0.493426f, 0.376116f, 0.333776f, 0.33324f, 0.33184f, 0.32946f, 0.324757f, 0.316235f, 0.299635f, 0.26381f, 0.188694f, 0.0850079f}, + {0.778672f, 0.738894f, 0.703401f, 0.655946f, 0.573393f, 0.434698f, 0.381001f, 0.380294f, 0.37853f, 0.375203f, 0.369309f, 0.358344f, 0.336485f, 0.290291f, 0.197258f, 0.0829682f}, + {0.821923f, 0.792118f, 0.769567f, 0.735898f, 0.659137f, 0.497213f, 0.428794f, 0.427797f, 0.4256f, 0.421204f, 0.413409f, 0.398963f, 0.37059f, 0.310524f, 0.196959f, 0.0773996f}, + {0.86055f, 0.838697f, 0.829455f, 0.811241f, 0.746586f, 0.562444f, 0.475222f, 0.473851f, 0.47079f, 0.465083f, 0.454572f, 0.435262f, 0.39741f, 0.319244f, 0.185245f, 0.0690026f}, + {0.893095f, 0.877285f, 0.881631f, 0.877635f, 0.828495f, 0.628048f, 0.517484f, 0.515733f, 0.511624f, 0.50387f, 0.489596f, 0.463272f, 0.41237f, 0.312031f, 0.162469f, 0.0591605f}, + {0.917615f, 0.909531f, 0.925471f, 0.929835f, 0.89966f, 0.69672f, 0.559404f, 0.556982f, 0.5512f, 0.540334f, 0.520498f, 0.483786f, 0.413898f, 0.287332f, 0.132796f, 0.050193f}, + {0.934032f, 0.939085f, 0.962051f, 0.97022f, 0.953749f, 0.764512f, 0.599388f, 0.595758f, 0.58752f, 0.571677f, 0.542717f, 0.48957f, 0.393361f, 0.243657f, 0.102006f, 0.0429349f}, + {0.944519f, 0.970496f, 0.988256f, 0.991154f, 0.983414f, 0.827743f, 0.641835f, 0.636383f, 0.623603f, 0.599039f, 0.554061f, 0.474473f, 0.346497f, 0.190479f, 0.0773776f, 0.038138f}, + {0.95928f, 0.9932f, 0.997978f, 0.998305f, 0.995804f, 0.883858f, 0.69604f, 0.686486f, 0.6644f, 0.621603f, 0.545756f, 0.427881f, 0.280957f, 0.145884f, 0.0628985f, 0.0357136f}, + {0.980295f, 0.999433f, 0.999861f, 0.999815f, 0.999411f, 0.932279f, 0.773851f, 0.752873f, 0.70396f, 0.616439f, 0.494353f, 0.357097f, 0.228204f, 0.123006f, 0.0572407f, 0.0348617f}, + {0.996954f, 0.999987f, 0.999999f, 0.999991f, 0.999972f, 0.975302f, 0.879834f, 0.799428f, 0.686377f, 0.561806f, 0.438543f, 0.320973f, 0.211457f, 0.117482f, 0.0559932f, 0.034697f} + }, + { + {0.584384f, 0.486759f, 0.414569f, 0.35226f, 0.294182f, 0.237678f, 0.201169f, 0.200033f, 0.199862f, 0.199145f, 0.198018f, 0.195833f, 0.191789f, 0.18265f, 0.160953f, 0.11217f}, + {0.623963f, 0.535209f, 0.466013f, 0.402629f, 0.340092f, 0.275f, 0.231413f, 0.23002f, 0.229534f, 0.228906f, 0.227486f, 0.22481f, 0.219569f, 0.208694f, 0.182215f, 0.122782f}, + {0.664828f, 0.586377f, 0.521816f, 0.459039f, 0.392321f, 0.317447f, 0.26513f, 0.263508f, 0.262985f, 0.261942f, 0.260289f, 0.257189f, 0.250868f, 0.237132f, 0.204427f, 0.132702f}, + {0.706323f, 0.638963f, 0.581118f, 0.52111f, 0.451331f, 0.365574f, 0.30242f, 0.300352f, 0.299899f, 0.298696f, 0.29654f, 0.292524f, 0.284802f, 0.267865f, 0.226956f, 0.140564f}, + {0.747964f, 0.691893f, 0.642522f, 0.587635f, 0.517204f, 0.420172f, 0.342916f, 0.340351f, 0.339621f, 0.338141f, 0.335483f, 0.33054f, 0.320698f, 0.299487f, 0.248286f, 0.145339f}, + {0.788377f, 0.743281f, 0.703635f, 0.657164f, 0.589507f, 0.480625f, 0.385678f, 0.382457f, 0.381606f, 0.379809f, 0.376218f, 0.369935f, 0.357479f, 0.33069f, 0.266428f, 0.145712f}, + {0.826339f, 0.79143f, 0.762619f, 0.727238f, 0.666304f, 0.546651f, 0.429381f, 0.425347f, 0.42421f, 0.421685f, 0.417389f, 0.409095f, 0.392994f, 0.358587f, 0.277596f, 0.140842f}, + {0.861355f, 0.834821f, 0.816762f, 0.794142f, 0.744211f, 0.617062f, 0.47219f, 0.466988f, 0.465523f, 0.462368f, 0.456606f, 0.445924f, 0.424955f, 0.380023f, 0.279387f, 0.130409f}, + {0.892361f, 0.871503f, 0.864226f, 0.854361f, 0.818558f, 0.690242f, 0.51295f, 0.505941f, 0.503913f, 0.499854f, 0.492203f, 0.477961f, 0.450299f, 0.391215f, 0.267588f, 0.115213f}, + {0.917825f, 0.900846f, 0.904614f, 0.906182f, 0.883343f, 0.762659f, 0.549526f, 0.540403f, 0.537682f, 0.532118f, 0.521691f, 0.502502f, 0.465247f, 0.38793f, 0.241679f, 0.0973322f}, + {0.936621f, 0.925078f, 0.93872f, 0.946062f, 0.936093f, 0.835981f, 0.587729f, 0.575563f, 0.571634f, 0.563977f, 0.549603f, 0.522838f, 0.471081f, 0.368888f, 0.204316f, 0.0810579f}, + {0.947769f, 0.947779f, 0.968657f, 0.978432f, 0.974073f, 0.900961f, 0.625401f, 0.608581f, 0.60304f, 0.59182f, 0.570893f, 0.531865f, 0.458406f, 0.327451f, 0.161453f, 0.0675697f}, + {0.953547f, 0.974397f, 0.991229f, 0.994646f, 0.99207f, 0.949355f, 0.668031f, 0.644966f, 0.636347f, 0.619022f, 0.586274f, 0.526404f, 0.42144f, 0.267644f, 0.122802f, 0.0587093f}, + {0.963916f, 0.994649f, 0.998944f, 0.999283f, 0.998317f, 0.980541f, 0.723671f, 0.693064f, 0.678242f, 0.647756f, 0.590977f, 0.49482f, 0.356676f, 0.207624f, 0.0978133f, 0.0541279f}, + {0.981768f, 0.999674f, 1.00001f, 0.999968f, 0.999821f, 0.99555f, 0.801076f, 0.763079f, 0.729892f, 0.663386f, 0.55787f, 0.425017f, 0.289535f, 0.171399f, 0.0872914f, 0.0524877f}, + {0.997144f, 0.999995f, 1.0f, 0.999997f, 0.999986f, 0.999621f, 0.909389f, 0.838171f, 0.739119f, 0.619323f, 0.495702f, 0.376435f, 0.263665f, 0.161767f, 0.0849567f, 0.0521766f} + }, + { + {0.655346f, 0.561906f, 0.491755f, 0.430295f, 0.371617f, 0.313226f, 0.260674f, 0.253407f, 0.253217f, 0.252764f, 0.251786f, 0.250303f, 0.247113f, 0.24021f, 0.223402f, 0.178662f}, + {0.691674f, 0.608208f, 0.542899f, 0.482245f, 0.420802f, 0.355338f, 0.293422f, 0.284524f, 0.284123f, 0.283469f, 0.282603f, 0.280591f, 0.276717f, 0.268524f, 0.247739f, 0.19242f}, + {0.728044f, 0.655948f, 0.596639f, 0.538255f, 0.475305f, 0.402536f, 0.329049f, 0.318026f, 0.317658f, 0.316949f, 0.315771f, 0.313315f, 0.308647f, 0.298611f, 0.272722f, 0.204541f}, + {0.764272f, 0.703399f, 0.651827f, 0.597987f, 0.534968f, 0.454861f, 0.367411f, 0.354038f, 0.353594f, 0.352687f, 0.351086f, 0.34804f, 0.342341f, 0.329798f, 0.297636f, 0.213817f}, + {0.799481f, 0.749541f, 0.706707f, 0.65972f, 0.599422f, 0.512711f, 0.408077f, 0.391621f, 0.390916f, 0.389937f, 0.387961f, 0.384355f, 0.377045f, 0.361351f, 0.321132f, 0.21874f}, + {0.833064f, 0.79325f, 0.759696f, 0.721739f, 0.667386f, 0.576018f, 0.450583f, 0.429854f, 0.429303f, 0.428047f, 0.425468f, 0.420758f, 0.411582f, 0.391712f, 0.341006f, 0.218386f}, + {0.864227f, 0.833129f, 0.80903f, 0.781518f, 0.736449f, 0.643705f, 0.493718f, 0.467414f, 0.466667f, 0.464997f, 0.46178f, 0.455711f, 0.443946f, 0.418506f, 0.353892f, 0.21037f}, + {0.892507f, 0.868179f, 0.852712f, 0.836384f, 0.803063f, 0.713932f, 0.536262f, 0.502752f, 0.501796f, 0.499473f, 0.495427f, 0.487581f, 0.47234f, 0.439281f, 0.357252f, 0.194765f}, + {0.917192f, 0.897168f, 0.890272f, 0.884494f, 0.86404f, 0.784655f, 0.578154f, 0.534738f, 0.533426f, 0.530553f, 0.525126f, 0.514691f, 0.494508f, 0.450769f, 0.347364f, 0.172457f}, + {0.937506f, 0.919316f, 0.921779f, 0.925287f, 0.914427f, 0.85005f, 0.617343f, 0.562246f, 0.560465f, 0.556599f, 0.549083f, 0.535223f, 0.508035f, 0.449988f, 0.321718f, 0.146235f}, + {0.951647f, 0.937322f, 0.948661f, 0.956573f, 0.954769f, 0.911411f, 0.662395f, 0.591633f, 0.589082f, 0.583729f, 0.573388f, 0.553868f, 0.515911f, 0.437037f, 0.282522f, 0.121081f}, + {0.958864f, 0.954679f, 0.973608f, 0.98378f, 0.983817f, 0.957867f, 0.707989f, 0.619116f, 0.615467f, 0.607609f, 0.592542f, 0.564133f, 0.509188f, 0.402266f, 0.231036f, 0.0995307f}, + {0.961019f, 0.977555f, 0.993463f, 0.996912f, 0.996041f, 0.984132f, 0.756614f, 0.65085f, 0.645144f, 0.63297f, 0.609357f, 0.565112f, 0.482834f, 0.344187f, 0.178426f, 0.0847629f}, + {0.967802f, 0.995793f, 0.999663f, 0.999945f, 0.999463f, 0.995844f, 0.81039f, 0.695695f, 0.685924f, 0.664452f, 0.62278f, 0.547687f, 0.426479f, 0.273225f, 0.140307f, 0.0770456f}, + {0.983009f, 0.999887f, 1.00013f, 1.00006f, 0.999994f, 0.999406f, 0.870621f, 0.766047f, 0.744002f, 0.695415f, 0.609439f, 0.487306f, 0.349639f, 0.22162f, 0.122491f, 0.0742164f}, + {0.997307f, 1.0f, 1.00001f, 1.0f, 0.99999f, 0.999976f, 0.945438f, 0.86249f, 0.77964f, 0.668525f, 0.54669f, 0.42664f, 0.312222f, 0.206047f, 0.118426f, 0.0736859f} + }, + { + {0.717024f, 0.629416f, 0.563068f, 0.504133f, 0.447055f, 0.389116f, 0.329939f, 0.311599f, 0.311606f, 0.311333f, 0.310731f, 0.309635f, 0.30734f, 0.302617f, 0.290487f, 0.255316f}, + {0.749472f, 0.672512f, 0.612249f, 0.555209f, 0.497025f, 0.433789f, 0.364375f, 0.34236f, 0.342367f, 0.342028f, 0.34136f, 0.339841f, 0.33723f, 0.331458f, 0.316339f, 0.270967f}, + {0.781054f, 0.71557f, 0.661956f, 0.608976f, 0.550978f, 0.482414f, 0.401394f, 0.374746f, 0.374662f, 0.37394f, 0.373224f, 0.371561f, 0.368083f, 0.36114f, 0.342029f, 0.284234f}, + {0.811791f, 0.757438f, 0.711551f, 0.66402f, 0.608324f, 0.535764f, 0.440889f, 0.40826f, 0.408071f, 0.40734f, 0.406247f, 0.404107f, 0.400046f, 0.391082f, 0.367097f, 0.293858f}, + {0.841362f, 0.797037f, 0.759584f, 0.719557f, 0.668209f, 0.593443f, 0.482114f, 0.442201f, 0.44176f, 0.441072f, 0.439664f, 0.437092f, 0.43185f, 0.420519f, 0.390315f, 0.298541f}, + {0.869095f, 0.833649f, 0.804563f, 0.773131f, 0.729441f, 0.654612f, 0.525256f, 0.475706f, 0.475274f, 0.474519f, 0.472573f, 0.469213f, 0.462522f, 0.448148f, 0.410042f, 0.296346f}, + {0.894231f, 0.866535f, 0.845465f, 0.823267f, 0.789172f, 0.718658f, 0.569663f, 0.507364f, 0.506963f, 0.505776f, 0.503467f, 0.499171f, 0.490712f, 0.472192f, 0.423022f, 0.285576f}, + {0.917082f, 0.894465f, 0.880735f, 0.868064f, 0.84491f, 0.782923f, 0.614419f, 0.536301f, 0.535686f, 0.534104f, 0.53122f, 0.525615f, 0.514531f, 0.490305f, 0.427026f, 0.266185f}, + {0.936875f, 0.91735f, 0.910328f, 0.906478f, 0.894135f, 0.844683f, 0.659437f, 0.5616f, 0.560719f, 0.558791f, 0.55493f, 0.547462f, 0.532755f, 0.500824f, 0.41945f, 0.237678f}, + {0.953016f, 0.934042f, 0.934904f, 0.938939f, 0.93384f, 0.897741f, 0.703858f, 0.582755f, 0.581633f, 0.578905f, 0.573616f, 0.563623f, 0.543844f, 0.501145f, 0.396504f, 0.203638f}, + {0.963656f, 0.947091f, 0.956302f, 0.96408f, 0.965802f, 0.945544f, 0.75495f, 0.606576f, 0.604926f, 0.601196f, 0.5939f, 0.579855f, 0.552057f, 0.493028f, 0.359716f, 0.169652f}, + {0.9679f, 0.960212f, 0.977415f, 0.987604f, 0.989493f, 0.978001f, 0.803694f, 0.628576f, 0.626227f, 0.620804f, 0.61008f, 0.589458f, 0.549002f, 0.465776f, 0.305211f, 0.13878f}, + {0.967103f, 0.980129f, 0.99518f, 0.99856f, 0.998354f, 0.993188f, 0.849293f, 0.655377f, 0.651673f, 0.643181f, 0.626331f, 0.593953f, 0.531686f, 0.41476f, 0.242081f, 0.116379f}, + {0.970966f, 0.996743f, 1.00022f, 1.00044f, 1.00014f, 0.998565f, 0.891697f, 0.696166f, 0.689799f, 0.674749f, 0.644613f, 0.587956f, 0.487892f, 0.340297f, 0.18901f, 0.104251f}, + {0.984048f, 1.00006f, 1.00022f, 1.00015f, 1.0001f, 0.99981f, 0.930966f, 0.764673f, 0.750195f, 0.715529f, 0.648841f, 0.542535f, 0.408366f, 0.272834f, 0.161263f, 0.0996967f}, + {0.997442f, 1.00001f, 1.00001f, 1.0f, 0.999994f, 0.99999f, 0.97264f, 0.8756f, 0.808881f, 0.709364f, 0.592202f, 0.472449f, 0.357247f, 0.248946f, 0.154496f, 0.0988209f} + }, + { + {0.769871f, 0.689358f, 0.627584f, 0.572104f, 0.518044f, 0.462697f, 0.403642f, 0.375197f, 0.375208f, 0.374881f, 0.37468f, 0.374081f, 0.372454f, 0.369723f, 0.361991f, 0.33683f}, + {0.798124f, 0.728298f, 0.672992f, 0.620648f, 0.566709f, 0.507253f, 0.439053f, 0.404243f, 0.403978f, 0.403802f, 0.403317f, 0.402477f, 0.400742f, 0.396893f, 0.387081f, 0.352897f}, + {0.825115f, 0.766163f, 0.717828f, 0.670222f, 0.617968f, 0.555261f, 0.476575f, 0.433554f, 0.433479f, 0.433122f, 0.432645f, 0.431507f, 0.429259f, 0.424441f, 0.411694f, 0.366138f}, + {0.85076f, 0.802301f, 0.761656f, 0.719927f, 0.671158f, 0.606706f, 0.516142f, 0.463324f, 0.463138f, 0.462642f, 0.461979f, 0.460497f, 0.457908f, 0.451586f, 0.435076f, 0.374836f}, + {0.875255f, 0.835573f, 0.802846f, 0.768598f, 0.725074f, 0.661379f, 0.557937f, 0.492816f, 0.49242f, 0.491944f, 0.49083f, 0.48917f, 0.485439f, 0.477549f, 0.456088f, 0.378419f}, + {0.897746f, 0.866182f, 0.840701f, 0.814111f, 0.77861f, 0.71813f, 0.601478f, 0.520608f, 0.520355f, 0.519798f, 0.518462f, 0.516121f, 0.511446f, 0.501312f, 0.473759f, 0.374762f}, + {0.91815f, 0.892929f, 0.874334f, 0.85577f, 0.829255f, 0.775655f, 0.646708f, 0.54623f, 0.545959f, 0.545143f, 0.543627f, 0.540567f, 0.534353f, 0.521363f, 0.48535f, 0.361865f}, + {0.936524f, 0.91553f, 0.902491f, 0.892213f, 0.875269f, 0.831788f, 0.693279f, 0.568605f, 0.568203f, 0.567106f, 0.565102f, 0.561302f, 0.553341f, 0.536083f, 0.488935f, 0.339029f}, + {0.952488f, 0.933362f, 0.925954f, 0.922905f, 0.915303f, 0.883465f, 0.74087f, 0.587614f, 0.587009f, 0.58568f, 0.582985f, 0.577754f, 0.567187f, 0.544174f, 0.482603f, 0.306824f}, + {0.965242f, 0.945747f, 0.945117f, 0.949104f, 0.946766f, 0.925382f, 0.78788f, 0.602833f, 0.602024f, 0.600146f, 0.596527f, 0.589396f, 0.575154f, 0.544244f, 0.462883f, 0.26691f}, + {0.973308f, 0.954882f, 0.962187f, 0.969527f, 0.973024f, 0.963323f, 0.841465f, 0.62141f, 0.620176f, 0.617676f, 0.612518f, 0.602507f, 0.582535f, 0.538926f, 0.431196f, 0.225171f}, + {0.975153f, 0.964628f, 0.980321f, 0.990392f, 0.993245f, 0.987548f, 0.888355f, 0.638089f, 0.636404f, 0.632612f, 0.625101f, 0.610312f, 0.580971f, 0.518192f, 0.378572f, 0.184814f}, + {0.972027f, 0.982191f, 0.996574f, 0.999778f, 0.999904f, 0.997118f, 0.927903f, 0.659922f, 0.657192f, 0.651337f, 0.639339f, 0.615987f, 0.569953f, 0.476777f, 0.310403f, 0.153466f}, + {0.97356f, 0.997506f, 1.00066f, 1.00082f, 1.00061f, 0.999683f, 0.959278f, 0.6963f, 0.69161f, 0.681151f, 0.659574f, 0.617809f, 0.539042f, 0.406354f, 0.243328f, 0.135378f}, + {0.984902f, 1.0002f, 1.0003f, 1.00021f, 1.00016f, 0.999968f, 0.981188f, 0.761976f, 0.75154f, 0.727094f, 0.677205f, 0.589543f, 0.464942f, 0.325271f, 0.202468f, 0.128341f}, + {0.997554f, 1.00001f, 1.00002f, 1.00001f, 0.999996f, 0.999998f, 0.994412f, 0.881581f, 0.828661f, 0.742074f, 0.632541f, 0.514752f, 0.39931f, 0.290058f, 0.191668f, 0.126935f} + }, + { + {0.814758f, 0.741125f, 0.684642f, 0.633259f, 0.582873f, 0.531109f, 0.477065f, 0.443401f, 0.442813f, 0.442904f, 0.442498f, 0.442225f, 0.441227f, 0.439691f, 0.435269f, 0.417015f}, + {0.838806f, 0.775662f, 0.725511f, 0.678048f, 0.628714f, 0.574278f, 0.512131f, 0.469462f, 0.46859f, 0.468478f, 0.468359f, 0.467467f, 0.4667f, 0.46437f, 0.458047f, 0.432703f}, + {0.86129f, 0.808418f, 0.765381f, 0.722842f, 0.676102f, 0.619945f, 0.548744f, 0.495036f, 0.493954f, 0.49382f, 0.493683f, 0.493065f, 0.491526f, 0.488416f, 0.479841f, 0.445139f}, + {0.882499f, 0.839144f, 0.803179f, 0.766443f, 0.724031f, 0.667945f, 0.587382f, 0.520371f, 0.518904f, 0.518543f, 0.51827f, 0.517291f, 0.515409f, 0.51154f, 0.500236f, 0.452714f}, + {0.902463f, 0.867095f, 0.838218f, 0.808457f, 0.771749f, 0.717693f, 0.628463f, 0.544602f, 0.542498f, 0.542471f, 0.541704f, 0.540785f, 0.538058f, 0.532832f, 0.517994f, 0.454845f}, + {0.920638f, 0.892218f, 0.869788f, 0.846858f, 0.817576f, 0.768655f, 0.671021f, 0.567116f, 0.564754f, 0.564285f, 0.563504f, 0.561863f, 0.558675f, 0.551678f, 0.532307f, 0.44925f}, + {0.93715f, 0.914212f, 0.897206f, 0.88129f, 0.860228f, 0.818965f, 0.715804f, 0.58707f, 0.584019f, 0.583419f, 0.582523f, 0.580453f, 0.576138f, 0.566912f, 0.541263f, 0.434966f}, + {0.951935f, 0.93222f, 0.919714f, 0.910863f, 0.898083f, 0.866636f, 0.762016f, 0.604117f, 0.600054f, 0.599183f, 0.597978f, 0.595252f, 0.589719f, 0.577581f, 0.543471f, 0.41024f}, + {0.96479f, 0.946055f, 0.938243f, 0.935514f, 0.930665f, 0.90952f, 0.809207f, 0.618167f, 0.612895f, 0.611866f, 0.609978f, 0.606374f, 0.598907f, 0.582638f, 0.53728f, 0.375768f}, + {0.974998f, 0.955059f, 0.953115f, 0.956797f, 0.956078f, 0.942822f, 0.854768f, 0.629529f, 0.622202f, 0.620983f, 0.618442f, 0.613586f, 0.603451f, 0.58139f, 0.520351f, 0.33251f}, + {0.980931f, 0.961102f, 0.96679f, 0.973625f, 0.978029f, 0.973807f, 0.905751f, 0.645629f, 0.635384f, 0.633787f, 0.630137f, 0.623134f, 0.608961f, 0.577404f, 0.494014f, 0.285684f}, + {0.981041f, 0.968183f, 0.982609f, 0.992523f, 0.995859f, 0.992981f, 0.946246f, 0.660864f, 0.64658f, 0.644005f, 0.638785f, 0.628265f, 0.607339f, 0.561256f, 0.447135f, 0.237069f}, + {0.976072f, 0.983846f, 0.997663f, 1.0007f, 1.00099f, 0.999286f, 0.974897f, 0.682563f, 0.662538f, 0.658535f, 0.650056f, 0.633432f, 0.600014f, 0.529113f, 0.380074f, 0.196042f}, + {0.975703f, 0.998117f, 1.00102f, 1.00109f, 1.00093f, 1.00027f, 0.991798f, 0.719735f, 0.692488f, 0.685253f, 0.669926f, 0.639738f, 0.5803f, 0.468494f, 0.302512f, 0.170093f}, + {0.985592f, 1.00031f, 1.00036f, 1.00025f, 1.00021f, 1.00006f, 0.998674f, 0.783198f, 0.749927f, 0.732759f, 0.696328f, 0.627581f, 0.518127f, 0.379354f, 0.245944f, 0.159461f}, + {0.997649f, 1.00001f, 1.00002f, 1.00001f, 0.999999f, 1.0f, 0.999956f, 0.895882f, 0.840801f, 0.767192f, 0.667696f, 0.554176f, 0.439151f, 0.329469f, 0.228984f, 0.157272f} + }, + { + {0.852327f, 0.785528f, 0.734096f, 0.687209f, 0.641027f, 0.593755f, 0.546174f, 0.51173f, 0.510117f, 0.510153f, 0.509981f, 0.509668f, 0.509121f, 0.508165f, 0.505485f, 0.492402f}, + {0.872297f, 0.815385f, 0.770401f, 0.727489f, 0.683047f, 0.634238f, 0.579255f, 0.534697f, 0.532008f, 0.532121f, 0.531778f, 0.531399f, 0.530904f, 0.529383f, 0.525889f, 0.507332f}, + {0.890813f, 0.843368f, 0.804953f, 0.76727f, 0.725805f, 0.676213f, 0.613642f, 0.556795f, 0.553167f, 0.552991f, 0.55288f, 0.552383f, 0.55162f, 0.549473f, 0.544027f, 0.518023f}, + {0.908163f, 0.869398f, 0.837442f, 0.805183f, 0.768303f, 0.719709f, 0.650113f, 0.577676f, 0.572943f, 0.572831f, 0.572546f, 0.571959f, 0.570641f, 0.568212f, 0.560795f, 0.524445f}, + {0.924225f, 0.892494f, 0.866992f, 0.841054f, 0.809644f, 0.764273f, 0.688854f, 0.597581f, 0.591033f, 0.590918f, 0.590508f, 0.589924f, 0.588226f, 0.584562f, 0.574635f, 0.524951f}, + {0.938927f, 0.913222f, 0.89305f, 0.873231f, 0.848644f, 0.808965f, 0.728769f, 0.615773f, 0.607238f, 0.607084f, 0.60647f, 0.60548f, 0.603273f, 0.598426f, 0.585214f, 0.518078f}, + {0.952227f, 0.93095f, 0.915501f, 0.901369f, 0.884093f, 0.852348f, 0.771079f, 0.631519f, 0.620656f, 0.620219f, 0.619534f, 0.618267f, 0.615283f, 0.609169f, 0.591182f, 0.5024f}, + {0.964165f, 0.945556f, 0.933442f, 0.925354f, 0.915528f, 0.892248f, 0.814168f, 0.645156f, 0.630719f, 0.63017f, 0.62928f, 0.627568f, 0.623698f, 0.615359f, 0.591313f, 0.47741f}, + {0.974607f, 0.956249f, 0.94788f, 0.945207f, 0.942051f, 0.92778f, 0.857753f, 0.657009f, 0.637844f, 0.637232f, 0.635956f, 0.633445f, 0.628438f, 0.617073f, 0.584543f, 0.442566f}, + {0.982774f, 0.962428f, 0.959415f, 0.962767f, 0.962868f, 0.954528f, 0.897842f, 0.667502f, 0.642285f, 0.6415f, 0.63974f, 0.636305f, 0.629316f, 0.613794f, 0.569622f, 0.397893f}, + {0.987038f, 0.966109f, 0.970437f, 0.976756f, 0.981732f, 0.980547f, 0.941763f, 0.685037f, 0.650733f, 0.649664f, 0.647199f, 0.642303f, 0.632398f, 0.610232f, 0.548225f, 0.348698f}, + {0.985768f, 0.971035f, 0.984446f, 0.994179f, 0.997767f, 0.996413f, 0.972495f, 0.702212f, 0.657113f, 0.655356f, 0.651749f, 0.644367f, 0.629671f, 0.59674f, 0.508643f, 0.29426f}, + {0.979327f, 0.985186f, 0.998527f, 1.00143f, 1.00178f, 1.0007f, 0.989801f, 0.725573f, 0.6682f, 0.665496f, 0.659519f, 0.647838f, 0.624135f, 0.572206f, 0.447623f, 0.243758f}, + {0.977426f, 0.998615f, 1.00131f, 1.00132f, 1.00116f, 1.00067f, 0.997402f, 0.760523f, 0.693225f, 0.688248f, 0.677438f, 0.655999f, 0.612563f, 0.524092f, 0.365975f, 0.208373f}, + {0.986154f, 1.00041f, 1.00041f, 1.00028f, 1.00025f, 1.00012f, 0.99966f, 0.81433f, 0.746767f, 0.734741f, 0.708517f, 0.656763f, 0.56608f, 0.434755f, 0.292263f, 0.192491f}, + {0.997724f, 1.00002f, 1.00002f, 1.00001f, 1.0f, 1.0f, 0.999985f, 0.910766f, 0.847327f, 0.78563f, 0.697528f, 0.590867f, 0.477544f, 0.367598f, 0.265921f, 0.189085f} + }, + { + {0.883327f, 0.823046f, 0.776506f, 0.733979f, 0.691976f, 0.649752f, 0.608825f, 0.576155f, 0.57289f, 0.573092f, 0.572784f, 0.572826f, 0.572366f, 0.572023f, 0.570457f, 0.561059f}, + {0.899867f, 0.848583f, 0.808166f, 0.769833f, 0.730047f, 0.686601f, 0.639202f, 0.5961f, 0.591385f, 0.591372f, 0.591531f, 0.590989f, 0.590727f, 0.589719f, 0.587649f, 0.574216f}, + {0.914702f, 0.872192f, 0.838023f, 0.804332f, 0.76784f, 0.724301f, 0.671011f, 0.614624f, 0.608101f, 0.608023f, 0.608036f, 0.607736f, 0.607255f, 0.605917f, 0.602552f, 0.583313f}, + {0.928678f, 0.893883f, 0.865533f, 0.837081f, 0.80493f, 0.76325f, 0.704159f, 0.632201f, 0.62328f, 0.623173f, 0.623051f, 0.622691f, 0.621768f, 0.620302f, 0.61557f, 0.588069f}, + {0.941761f, 0.913061f, 0.890285f, 0.867467f, 0.840397f, 0.802503f, 0.739201f, 0.64837f, 0.636323f, 0.63623f, 0.636018f, 0.635646f, 0.634398f, 0.632164f, 0.625594f, 0.58763f}, + {0.953561f, 0.930088f, 0.911763f, 0.894184f, 0.873458f, 0.841109f, 0.776012f, 0.663084f, 0.647355f, 0.647067f, 0.646616f, 0.645915f, 0.64462f, 0.64136f, 0.632563f, 0.580104f}, + {0.964211f, 0.944464f, 0.930175f, 0.917402f, 0.902854f, 0.877985f, 0.81423f, 0.676033f, 0.655247f, 0.654978f, 0.654488f, 0.653611f, 0.651794f, 0.647689f, 0.635603f, 0.564149f}, + {0.973853f, 0.956149f, 0.944373f, 0.936734f, 0.928832f, 0.911411f, 0.853037f, 0.687418f, 0.660033f, 0.659729f, 0.659155f, 0.657991f, 0.655424f, 0.649853f, 0.633327f, 0.539656f}, + {0.982351f, 0.964341f, 0.955586f, 0.95286f, 0.950798f, 0.941015f, 0.891335f, 0.69814f, 0.662124f, 0.661781f, 0.660878f, 0.659265f, 0.65584f, 0.648102f, 0.625612f, 0.5052f}, + {0.988952f, 0.968325f, 0.96444f, 0.967371f, 0.968036f, 0.962705f, 0.925212f, 0.709201f, 0.662153f, 0.661613f, 0.660451f, 0.658072f, 0.653265f, 0.642637f, 0.611725f, 0.461376f}, + {0.991959f, 0.970119f, 0.973337f, 0.979199f, 0.98447f, 0.985309f, 0.961876f, 0.728023f, 0.666309f, 0.665624f, 0.663906f, 0.660604f, 0.65375f, 0.638546f, 0.594483f, 0.412469f}, + {0.989519f, 0.97335f, 0.985904f, 0.99545f, 0.999169f, 0.99877f, 0.98506f, 0.745811f, 0.66816f, 0.666953f, 0.664467f, 0.659379f, 0.649173f, 0.6263f, 0.561755f, 0.354944f}, + {0.981936f, 0.986245f, 0.999204f, 1.00201f, 1.00237f, 1.00164f, 0.995568f, 0.76775f, 0.674487f, 0.672633f, 0.668485f, 0.660392f, 0.643848f, 0.607072f, 0.510117f, 0.296613f}, + {0.978822f, 0.999025f, 1.00154f, 1.0015f, 1.00134f, 1.00093f, 0.999166f, 0.797407f, 0.694352f, 0.69094f, 0.683395f, 0.668275f, 0.63744f, 0.571235f, 0.431593f, 0.250548f}, + {0.986614f, 1.00048f, 1.00045f, 1.00031f, 1.00028f, 1.00017f, 0.99993f, 0.840878f, 0.743025f, 0.734606f, 0.715882f, 0.678046f, 0.606931f, 0.490118f, 0.342267f, 0.227105f}, + {0.997786f, 1.00002f, 1.00002f, 1.00001f, 1.0f, 1.0f, 0.999993f, 0.922434f, 0.849686f, 0.798615f, 0.722072f, 0.624626f, 0.515012f, 0.404997f, 0.302312f, 0.221706f} + }, + { + {0.908777f, 0.854384f, 0.812559f, 0.774051f, 0.736146f, 0.699431f, 0.664242f, 0.63405f, 0.629809f, 0.630031f, 0.629793f, 0.629788f, 0.629543f, 0.629351f, 0.628492f, 0.621726f}, + {0.922329f, 0.876034f, 0.839799f, 0.805637f, 0.770072f, 0.732134f, 0.691576f, 0.651315f, 0.644846f, 0.644999f, 0.645152f, 0.644587f, 0.644625f, 0.643953f, 0.642912f, 0.633059f}, + {0.934245f, 0.895915f, 0.865258f, 0.835403f, 0.803007f, 0.76574f, 0.719893f, 0.667021f, 0.658051f, 0.657961f, 0.657993f, 0.657579f, 0.657408f, 0.656702f, 0.654529f, 0.641246f}, + {0.945225f, 0.913804f, 0.888536f, 0.8634f, 0.835159f, 0.799765f, 0.749825f, 0.681578f, 0.668974f, 0.669052f, 0.66903f, 0.668625f, 0.6683f, 0.667226f, 0.664361f, 0.644478f}, + {0.955719f, 0.929663f, 0.909191f, 0.888967f, 0.865438f, 0.833685f, 0.781174f, 0.694763f, 0.677719f, 0.677763f, 0.677502f, 0.677448f, 0.676727f, 0.67519f, 0.67113f, 0.642978f}, + {0.965226f, 0.943646f, 0.926888f, 0.911003f, 0.893341f, 0.866882f, 0.813775f, 0.70664f, 0.684231f, 0.684125f, 0.683785f, 0.683343f, 0.682502f, 0.68041f, 0.67479f, 0.635121f}, + {0.973718f, 0.955286f, 0.941803f, 0.930142f, 0.917794f, 0.898077f, 0.847817f, 0.717774f, 0.687636f, 0.687466f, 0.687157f, 0.686587f, 0.685361f, 0.682743f, 0.674868f, 0.619579f}, + {0.981619f, 0.96454f, 0.953089f, 0.945808f, 0.939315f, 0.926109f, 0.882041f, 0.727626f, 0.687965f, 0.687738f, 0.687316f, 0.686664f, 0.684934f, 0.68118f, 0.670404f, 0.59585f}, + {0.988563f, 0.970828f, 0.961739f, 0.95891f, 0.957574f, 0.95089f, 0.915232f, 0.73794f, 0.685755f, 0.685524f, 0.68496f, 0.683814f, 0.681587f, 0.676341f, 0.661425f, 0.562842f}, + {0.993927f, 0.973118f, 0.96846f, 0.971f, 0.972021f, 0.968701f, 0.943292f, 0.748986f, 0.681809f, 0.681423f, 0.680556f, 0.679091f, 0.675801f, 0.668686f, 0.647866f, 0.521485f}, + {0.995891f, 0.973316f, 0.975657f, 0.981135f, 0.98663f, 0.98869f, 0.974103f, 0.768672f, 0.682094f, 0.681626f, 0.680575f, 0.678309f, 0.67367f, 0.663332f, 0.633382f, 0.474851f}, + {0.992571f, 0.975232f, 0.987073f, 0.996472f, 1.00028f, 1.00045f, 0.991904f, 0.785766f, 0.67977f, 0.678969f, 0.677275f, 0.673797f, 0.666775f, 0.651266f, 0.606504f, 0.41762f}, + {0.984047f, 0.987106f, 0.999766f, 1.00247f, 1.00283f, 1.0023f, 0.998521f, 0.804636f, 0.68154f, 0.680271f, 0.677421f, 0.671838f, 0.660441f, 0.635024f, 0.564735f, 0.354542f}, + {0.979943f, 0.999351f, 1.00173f, 1.00163f, 1.00148f, 1.00114f, 1.00004f, 0.828857f, 0.696212f, 0.693853f, 0.68862f, 0.678021f, 0.656535f, 0.609464f, 0.495948f, 0.297586f}, + {0.986983f, 1.00054f, 1.00048f, 1.00033f, 1.0003f, 1.0002f, 1.00005f, 0.863552f, 0.739261f, 0.733375f, 0.720073f, 0.692985f, 0.639816f, 0.542789f, 0.397024f, 0.263567f}, + {0.997835f, 1.00002f, 1.00002f, 1.00001f, 1.0f, 1.0f, 0.999998f, 0.93191f, 0.849138f, 0.807179f, 0.74174f, 0.654896f, 0.551606f, 0.442358f, 0.338392f, 0.254625f} + } +}; + +static const float table_clearcoat_E[16][16] = { + {0.0957937f, 0.107269f, 0.124314f, 0.145841f, 0.171902f, 0.202507f, 0.237239f, 0.274857f, 0.313117f, 0.348864f, 0.378594f, 0.399369f, 0.409696f, 0.409948f, 0.401807f, 0.387712f}, + {0.103913f, 0.118336f, 0.138516f, 0.163634f, 0.193917f, 0.229433f, 0.269794f, 0.313709f, 0.358702f, 0.40124f, 0.437384f, 0.463666f, 0.478306f, 0.481542f, 0.475314f, 0.462174f}, + {0.114001f, 0.131792f, 0.155509f, 0.184656f, 0.219564f, 0.260417f, 0.30679f, 0.357311f, 0.409259f, 0.458766f, 0.501395f, 0.533305f, 0.552494f, 0.559133f, 0.55525f, 0.543762f}, + {0.126718f, 0.148352f, 0.17616f, 0.209868f, 0.24991f, 0.296499f, 0.349183f, 0.406439f, 0.465305f, 0.521516f, 0.570303f, 0.607454f, 0.630828f, 0.640633f, 0.639167f, 0.629563f}, + {0.142942f, 0.169096f, 0.201677f, 0.240591f, 0.28632f, 0.339067f, 0.398261f, 0.462106f, 0.527417f, 0.589522f, 0.643291f, 0.684462f, 0.710811f, 0.722861f, 0.72308f, 0.715033f}, + {0.163824f, 0.195379f, 0.233628f, 0.278595f, 0.330697f, 0.390005f, 0.455709f, 0.525685f, 0.596293f, 0.662552f, 0.719195f, 0.762062f, 0.789222f, 0.801605f, 0.802171f, 0.794678f}, + {0.190934f, 0.22908f, 0.274143f, 0.326182f, 0.385488f, 0.451664f, 0.523495f, 0.598289f, 0.671959f, 0.739469f, 0.795561f, 0.836672f, 0.86164f, 0.872011f, 0.871178f, 0.863261f}, + {0.226325f, 0.272583f, 0.325986f, 0.38642f, 0.453616f, 0.526553f, 0.603038f, 0.679948f, 0.75296f, 0.81709f, 0.868099f, 0.903421f, 0.923006f, 0.929287f, 0.925963f, 0.917004f}, + {0.272522f, 0.328901f, 0.392562f, 0.462815f, 0.538096f, 0.61602f, 0.69377f, 0.767744f, 0.834187f, 0.889376f, 0.930485f, 0.95656f, 0.968832f, 0.970247f, 0.964471f, 0.954985f}, + {0.332556f, 0.401548f, 0.477887f, 0.55866f, 0.639798f, 0.717851f, 0.789919f, 0.853651f, 0.906877f, 0.947986f, 0.976068f, 0.991628f, 0.996712f, 0.994261f, 0.987344f, 0.978504f}, + {0.409615f, 0.494384f, 0.585635f, 0.674102f, 0.753563f, 0.82181f, 0.878802f, 0.925017f, 0.960756f, 0.986191f, 1.0019f, 1.00903f, 1.00942f, 1.00538f, 0.99908f, 0.992107f}, + {0.506354f, 0.611394f, 0.715256f, 0.799046f, 0.86226f, 0.909737f, 0.945706f, 0.97248f, 0.99164f, 1.00413f, 1.01079f, 1.01265f, 1.01105f, 1.00732f, 1.00272f, 0.998148f}, + {0.623822f, 0.753034f, 0.849494f, 0.907052f, 0.942889f, 0.966663f, 0.983133f, 0.994624f, 1.00237f, 1.00692f, 1.00888f, 1.00874f, 1.00721f, 1.00488f, 1.00236f, 0.999994f}, + {0.762026f, 0.895731f, 0.949127f, 0.971914f, 0.984199f, 0.991853f, 0.996957f, 1.00045f, 1.00264f, 1.00378f, 1.0041f, 1.00375f, 1.00303f, 1.00205f, 1.00108f, 1.00021f}, + {0.905247f, 0.980365f, 0.991431f, 0.995528f, 0.997658f, 0.999011f, 0.999864f, 1.00045f, 1.00079f, 1.00093f, 1.00094f, 1.00083f, 1.00064f, 1.00045f, 1.00025f, 1.00006f}, + {0.989008f, 0.999275f, 0.999681f, 0.999839f, 0.999929f, 0.99998f, 1.00001f, 1.00003f, 1.00004f, 1.00005f, 1.00005f, 1.00004f, 1.00003f, 1.00002f, 1.00002f, 1.0f} +}; diff --git a/intern/cycles/scene/shader_graph.cpp b/intern/cycles/scene/shader_graph.cpp index ef3f142ed4e..99c34f5b5ac 100644 --- a/intern/cycles/scene/shader_graph.cpp +++ b/intern/cycles/scene/shader_graph.cpp @@ -1129,10 +1129,8 @@ int ShaderGraph::get_num_closures() else if (CLOSURE_IS_GLASS(closure_type)) { num_closures += 2; } - else if (CLOSURE_IS_BSDF_MULTISCATTER(closure_type)) { - num_closures += 2; - } else if (CLOSURE_IS_PRINCIPLED(closure_type)) { + /* TODO adjust */ num_closures += 8; } else if (CLOSURE_IS_VOLUME(closure_type)) { diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp index a9cd453947b..1a83737c738 100644 --- a/intern/cycles/scene/shader_nodes.cpp +++ b/intern/cycles/scene/shader_nodes.cpp @@ -2726,7 +2726,8 @@ NODE_DEFINE(PrincipledBsdfNode) static NodeEnum distribution_enum; distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); - distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_FRESNEL_ID); + distribution_enum.insert("Principled v2", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); SOCKET_ENUM( distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); @@ -2743,7 +2744,9 @@ NODE_DEFINE(PrincipledBsdfNode) SOCKET_IN_COLOR(base_color, "Base Color", make_float3(0.8f, 0.8f, 0.8f)); SOCKET_IN_COLOR(subsurface_color, "Subsurface Color", make_float3(0.8f, 0.8f, 0.8f)); SOCKET_IN_FLOAT(metallic, "Metallic", 0.0f); + SOCKET_IN_COLOR(metallic_edge, "Metallic Edge", make_float3(1.0f, 1.0f, 1.0f)); SOCKET_IN_FLOAT(subsurface, "Subsurface", 0.0f); + SOCKET_IN_FLOAT(subsurface_scale, "Subsurface Scale", 0.0f); SOCKET_IN_VECTOR(subsurface_radius, "Subsurface Radius", make_float3(0.1f, 0.1f, 0.1f)); SOCKET_IN_FLOAT(subsurface_ior, "Subsurface IOR", 1.4f); SOCKET_IN_FLOAT(subsurface_anisotropy, "Subsurface Anisotropy", 0.0f); @@ -2753,8 +2756,10 @@ NODE_DEFINE(PrincipledBsdfNode) SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f); SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f); SOCKET_IN_FLOAT(sheen_tint, "Sheen Tint", 0.0f); + SOCKET_IN_FLOAT(sheen_roughness, "Sheen Roughness", 0.5f); SOCKET_IN_FLOAT(clearcoat, "Clearcoat", 0.0f); SOCKET_IN_FLOAT(clearcoat_roughness, "Clearcoat Roughness", 0.03f); + SOCKET_IN_COLOR(clearcoat_tint, "Clearcoat Tint", make_float3(1.0f, 1.0f, 1.0f)); SOCKET_IN_FLOAT(ior, "IOR", 0.0f); SOCKET_IN_FLOAT(transmission, "Transmission", 0.0f); SOCKET_IN_FLOAT(transmission_roughness, "Transmission Roughness", 0.0f); @@ -2781,6 +2786,8 @@ PrincipledBsdfNode::PrincipledBsdfNode() : BsdfBaseNode(get_node_type()) void PrincipledBsdfNode::expand(ShaderGraph *graph) { + /* TODO: Disconnect unused depending on model */ + ShaderOutput *principled_out = output("BSDF"); ShaderInput *emission_in = input("Emission"); @@ -2852,98 +2859,96 @@ void PrincipledBsdfNode::attributes(Shader *shader, AttributeRequestSet *attribu ShaderNode::attributes(shader, attributes); } -void PrincipledBsdfNode::compile(SVMCompiler &compiler, - ShaderInput *p_metallic, - ShaderInput *p_subsurface, - ShaderInput *p_subsurface_radius, - ShaderInput *p_subsurface_ior, - ShaderInput *p_subsurface_anisotropy, - ShaderInput *p_specular, - ShaderInput *p_roughness, - ShaderInput *p_specular_tint, - ShaderInput *p_anisotropic, - ShaderInput *p_sheen, - ShaderInput *p_sheen_tint, - ShaderInput *p_clearcoat, - ShaderInput *p_clearcoat_roughness, - ShaderInput *p_ior, - ShaderInput *p_transmission, - ShaderInput *p_anisotropic_rotation, - ShaderInput *p_transmission_roughness) -{ - ShaderInput *base_color_in = input("Base Color"); - ShaderInput *subsurface_color_in = input("Subsurface Color"); - ShaderInput *normal_in = input("Normal"); - ShaderInput *clearcoat_normal_in = input("Clearcoat Normal"); - ShaderInput *tangent_in = input("Tangent"); - - float3 weight = one_float3(); - - compiler.add_node(NODE_CLOSURE_SET_WEIGHT, weight); - - int normal_offset = compiler.stack_assign_if_linked(normal_in); - int clearcoat_normal_offset = compiler.stack_assign_if_linked(clearcoat_normal_in); - int tangent_offset = compiler.stack_assign_if_linked(tangent_in); - int specular_offset = compiler.stack_assign(p_specular); - int roughness_offset = compiler.stack_assign(p_roughness); - int specular_tint_offset = compiler.stack_assign(p_specular_tint); - int anisotropic_offset = compiler.stack_assign(p_anisotropic); - int sheen_offset = compiler.stack_assign(p_sheen); - int sheen_tint_offset = compiler.stack_assign(p_sheen_tint); - int clearcoat_offset = compiler.stack_assign(p_clearcoat); - int clearcoat_roughness_offset = compiler.stack_assign(p_clearcoat_roughness); - int ior_offset = compiler.stack_assign(p_ior); - int transmission_offset = compiler.stack_assign(p_transmission); - int transmission_roughness_offset = compiler.stack_assign(p_transmission_roughness); - int anisotropic_rotation_offset = compiler.stack_assign(p_anisotropic_rotation); - int subsurface_radius_offset = compiler.stack_assign(p_subsurface_radius); - int subsurface_ior_offset = compiler.stack_assign(p_subsurface_ior); - int subsurface_anisotropy_offset = compiler.stack_assign(p_subsurface_anisotropy); - - compiler.add_node(NODE_CLOSURE_BSDF, - compiler.encode_uchar4(closure, - compiler.stack_assign(p_metallic), - compiler.stack_assign(p_subsurface), - compiler.closure_mix_weight_offset()), - __float_as_int((p_metallic) ? get_float(p_metallic->socket_type) : 0.0f), - __float_as_int((p_subsurface) ? get_float(p_subsurface->socket_type) : 0.0f)); - - compiler.add_node( - normal_offset, - tangent_offset, - compiler.encode_uchar4( - specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset), - compiler.encode_uchar4( - sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_roughness_offset)); - - compiler.add_node(compiler.encode_uchar4(ior_offset, - transmission_offset, - anisotropic_rotation_offset, - transmission_roughness_offset), - distribution, - subsurface_method, - SVM_STACK_INVALID); - - float3 bc_default = get_float3(base_color_in->socket_type); - - compiler.add_node( - ((base_color_in->link) ? compiler.stack_assign(base_color_in) : SVM_STACK_INVALID), - __float_as_int(bc_default.x), - __float_as_int(bc_default.y), - __float_as_int(bc_default.z)); - - compiler.add_node(clearcoat_normal_offset, - subsurface_radius_offset, - subsurface_ior_offset, - subsurface_anisotropy_offset); +void PrincipledBsdfNode::compile(SVMCompiler &compiler) +{ + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, one_float3()); - float3 ss_default = get_float3(subsurface_color_in->socket_type); + if (distribution == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) { + compile_v2(compiler); + } + else { + compile_v1(compiler); + } +} + +void PrincipledBsdfNode::compile_v1(SVMCompiler &compiler) +{ + /* TODO skip generation of stack entries (normal, tangent, default vals.) if possible */ + /* If we ever have more than 255 closures, the packing here needs to change. */ + static_assert(NBUILTIN_CLOSURES < SVM_STACK_SIZE); + + uint base_1 = compiler.encode_uchar4(closure, + compiler.stack_assign(input("Base Color")), + compiler.stack_assign_if_linked(input("Normal")), + compiler.closure_mix_weight_offset()); + uint base_2 = compiler.encode_uchar4(compiler.stack_assign(input("Roughness")), + compiler.stack_assign(input("Metallic")), + compiler.stack_assign(input("Transmission")), + compiler.stack_assign(input("Specular Tint"))); + uint sss_1 = compiler.encode_uchar4(subsurface_method, + compiler.stack_assign(input("Subsurface")), + compiler.stack_assign(input("Subsurface Anisotropy")), + compiler.stack_assign(input("Subsurface Radius"))); + uint sss_2 = compiler.encode_uchar4(compiler.stack_assign(input("Subsurface Color")), + compiler.stack_assign(input("Subsurface IOR")), + SVM_STACK_INVALID, + distribution); + uint specular = compiler.encode_uchar4(compiler.stack_assign(input("Specular")), + compiler.stack_assign(input("Anisotropic")), + compiler.stack_assign(input("Anisotropic Rotation")), + compiler.stack_assign_if_linked(input("Tangent"))); + uint sheen_glass = compiler.encode_uchar4( + compiler.stack_assign(input("IOR")), + compiler.stack_assign(input("Sheen")), + compiler.stack_assign(input("Sheen Tint")), + compiler.stack_assign(input("Transmission Roughness"))); + uint clearcoat = compiler.encode_uchar4( + compiler.stack_assign(input("Clearcoat")), + compiler.stack_assign(input("Clearcoat Roughness")), + compiler.stack_assign_if_linked(input("Clearcoat Normal")), + SVM_STACK_INVALID); - compiler.add_node(((subsurface_color_in->link) ? compiler.stack_assign(subsurface_color_in) : - SVM_STACK_INVALID), - __float_as_int(ss_default.x), - __float_as_int(ss_default.y), - __float_as_int(ss_default.z)); + compiler.add_node(NODE_CLOSURE_BSDF, base_1, base_2, sss_1); + compiler.add_node(sss_2, specular, sheen_glass, clearcoat); +} + +void PrincipledBsdfNode::compile_v2(SVMCompiler &compiler) +{ + /* If we ever have more than 255 closures, the packing here needs to change. */ + static_assert(NBUILTIN_CLOSURES < SVM_STACK_SIZE); + + uint base_1 = compiler.encode_uchar4(closure, + compiler.stack_assign(input("Base Color")), + compiler.stack_assign_if_linked(input("Normal")), + compiler.closure_mix_weight_offset()); + uint base_2 = compiler.encode_uchar4(compiler.stack_assign(input("Roughness")), + compiler.stack_assign(input("Metallic")), + compiler.stack_assign(input("IOR")), + compiler.stack_assign(input("Transmission"))); + uint sss = compiler.encode_uchar4(compiler.stack_assign(input("Subsurface Scale")), + compiler.stack_assign(input("Subsurface Anisotropy")), + compiler.stack_assign(input("Subsurface Radius")), + subsurface_method); + uint metallic = compiler.encode_uchar4(SVM_STACK_INVALID, + compiler.stack_assign(input("Metallic Edge")), + SVM_STACK_INVALID, + distribution); + uint specular = compiler.encode_uchar4(compiler.stack_assign(input("Anisotropic")), + compiler.stack_assign(input("Anisotropic Rotation")), + compiler.stack_assign_if_linked(input("Tangent")), + SVM_STACK_INVALID); + uint sheen = compiler.encode_uchar4(compiler.stack_assign(input("IOR")), + compiler.stack_assign(input("Sheen")), + compiler.stack_assign(input("Sheen Tint")), + compiler.stack_assign(input("Sheen Roughness"))); + uint clearcoat = compiler.encode_uchar4( + compiler.stack_assign(input("Clearcoat")), + compiler.stack_assign(input("Clearcoat Roughness")), + compiler.stack_assign(input("Clearcoat Tint")), + compiler.stack_assign_if_linked(input("Clearcoat Normal"))); + + compiler.add_node(NODE_CLOSURE_BSDF, base_1, base_2, sss); + compiler.add_node(metallic, specular, sheen, clearcoat); } bool PrincipledBsdfNode::has_integrator_dependency() @@ -2952,28 +2957,6 @@ bool PrincipledBsdfNode::has_integrator_dependency() return !roughness_input->link && roughness <= 1e-4f; } -void PrincipledBsdfNode::compile(SVMCompiler &compiler) -{ - compile(compiler, - input("Metallic"), - input("Subsurface"), - input("Subsurface Radius"), - input("Subsurface IOR"), - input("Subsurface Anisotropy"), - input("Specular"), - input("Roughness"), - input("Specular Tint"), - input("Anisotropic"), - input("Sheen"), - input("Sheen Tint"), - input("Clearcoat"), - input("Clearcoat Roughness"), - input("IOR"), - input("Transmission"), - input("Anisotropic Rotation"), - input("Transmission Roughness")); -} - void PrincipledBsdfNode::compile(OSLCompiler &compiler) { compiler.parameter(this, "distribution"); diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h index cc3a71a0697..d0982980877 100644 --- a/intern/cycles/scene/shader_nodes.h +++ b/intern/cycles/scene/shader_nodes.h @@ -529,24 +529,6 @@ class PrincipledBsdfNode : public BsdfBaseNode { void expand(ShaderGraph *graph); bool has_surface_bssrdf(); bool has_bssrdf_bump(); - void compile(SVMCompiler &compiler, - ShaderInput *metallic, - ShaderInput *subsurface, - ShaderInput *subsurface_radius, - ShaderInput *subsurface_ior, - ShaderInput *subsurface_anisotropy, - ShaderInput *specular, - ShaderInput *roughness, - ShaderInput *specular_tint, - ShaderInput *anisotropic, - ShaderInput *sheen, - ShaderInput *sheen_tint, - ShaderInput *clearcoat, - ShaderInput *clearcoat_roughness, - ShaderInput *ior, - ShaderInput *transmission, - ShaderInput *anisotropic_rotation, - ShaderInput *transmission_roughness); NODE_SOCKET_API(float3, base_color) NODE_SOCKET_API(float3, subsurface_color) @@ -554,15 +536,19 @@ class PrincipledBsdfNode : public BsdfBaseNode { NODE_SOCKET_API(float, subsurface_ior) NODE_SOCKET_API(float, subsurface_anisotropy) NODE_SOCKET_API(float, metallic) + NODE_SOCKET_API(float3, metallic_edge) NODE_SOCKET_API(float, subsurface) + NODE_SOCKET_API(float, subsurface_scale) NODE_SOCKET_API(float, specular) NODE_SOCKET_API(float, roughness) NODE_SOCKET_API(float, specular_tint) NODE_SOCKET_API(float, anisotropic) NODE_SOCKET_API(float, sheen) NODE_SOCKET_API(float, sheen_tint) + NODE_SOCKET_API(float, sheen_roughness) NODE_SOCKET_API(float, clearcoat) NODE_SOCKET_API(float, clearcoat_roughness) + NODE_SOCKET_API(float3, clearcoat_tint) NODE_SOCKET_API(float, ior) NODE_SOCKET_API(float, transmission) NODE_SOCKET_API(float, anisotropic_rotation) @@ -580,6 +566,9 @@ class PrincipledBsdfNode : public BsdfBaseNode { private: ClosureType distribution_orig; + void compile_v1(SVMCompiler &compiler); + void compile_v2(SVMCompiler &compiler); + public: bool has_integrator_dependency(); void attributes(Shader *shader, AttributeRequestSet *attributes); diff --git a/intern/cycles/util/math_float2.h b/intern/cycles/util/math_float2.h index 542dad93467..4070314d520 100644 --- a/intern/cycles/util/math_float2.h +++ b/intern/cycles/util/math_float2.h @@ -41,6 +41,7 @@ ccl_device_inline float distance(const float2 &a, const float2 &b); ccl_device_inline float dot(const float2 &a, const float2 &b); ccl_device_inline float cross(const float2 &a, const float2 &b); ccl_device_inline float len(const float2 a); +ccl_device_inline float len_squared(const float2 a); ccl_device_inline float2 normalize(const float2 &a); ccl_device_inline float2 normalize_len(const float2 &a, float *t); ccl_device_inline float2 safe_normalize(const float2 &a); @@ -251,6 +252,11 @@ ccl_device_inline float len(const float2 a) return sqrtf(dot(a, a)); } +ccl_device_inline float len_squared(const float2 a) +{ + return dot(a, a); +} + ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b) { return (b != 0.0f) ? a / b : zero_float2(); diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 1a8fec49516..f3dd0ca9a46 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -1870,7 +1870,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) STREQ(node->idname, "ShaderNodeEeveeMetallic")) { node->type = SH_NODE_BSDF_PRINCIPLED; BLI_strncpy(node->idname, "ShaderNodeBsdfPrincipled", sizeof(node->idname)); - node->custom1 = SHD_GLOSSY_MULTI_GGX; + node->custom1 = SHD_PRINCIPLED_MULTI_GGX; error |= NTREE_DOVERSION_TRANSPARENCY_EMISSION; } } diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl index 0833809cc42..bc5c20b2a4a 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_principled.glsl @@ -15,11 +15,13 @@ float principled_sheen(float NV) void node_bsdf_principled(vec4 base_color, float subsurface, + float subsurface_scale, // todo vec3 subsurface_radius, vec4 subsurface_color, float subsurface_ior, float subsurface_anisotropy, float metallic, + vec4 metallic_edge, // todo float specular, float specular_tint, float roughness, @@ -27,8 +29,10 @@ void node_bsdf_principled(vec4 base_color, float anisotropic_rotation, float sheen, float sheen_tint, + float sheen_roughness, // todo float clearcoat, float clearcoat_roughness, + vec4 clearcoat_tint, // todo float ior, float transmission, float transmission_roughness, diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index c7962db8198..bf2c9b2eb61 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1669,6 +1669,12 @@ typedef struct NodeShaderMix { #define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3 #define SHD_GLOSSY_MULTI_GGX 4 +/* principled bsdf mode + * Note: GGX and MULTI_GGX must align with SHD_GLOSSY for backwards compatibility */ +#define SHD_PRINCIPLED_V2 0 /* TODO: Better name */ +#define SHD_PRINCIPLED_GGX 2 +#define SHD_PRINCIPLED_MULTI_GGX 4 + /* vector transform */ #define SHD_VECT_TRANSFORM_TYPE_VECTOR 0 #define SHD_VECT_TRANSFORM_TYPE_POINT 1 diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 865399df9ef..9ae6b25360a 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4665,13 +4665,9 @@ static EnumPropertyItem node_ies_mode_items[] = { }; static const EnumPropertyItem node_principled_distribution_items[] = { - {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, - {SHD_GLOSSY_MULTI_GGX, - "MULTI_GGX", - 0, - "Multiscatter GGX", - "Slower than GGX but gives a more energy conserving results, which would otherwise be " - "visible as excessive darkening"}, + {SHD_PRINCIPLED_GGX, "GGX", 0, "GGX", ""}, + {SHD_PRINCIPLED_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, + {SHD_PRINCIPLED_V2, "V2", 0, "Principled v2", ""}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index adf2a9e8a19..468527c57a0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -10,12 +10,15 @@ namespace blender::nodes::node_shader_bsdf_principled_cc { static void node_declare(NodeDeclarationBuilder &b) { + /* TODO: Tooltips depending on old/new model. */ b.add_input<decl::Color>(N_("Base Color")).default_value({0.8f, 0.8f, 0.8f, 1.0f}); b.add_input<decl::Float>(N_("Subsurface")) .default_value(0.0f) .min(0.0f) .max(1.0f) .subtype(PROP_FACTOR); + /* TODO: Somehow merge with "Subsurface". Needs different subtype though... */ + b.add_input<decl::Float>(N_("Subsurface Scale")).default_value(0.0f).min(0.0f).max(100.0f); b.add_input<decl::Vector>(N_("Subsurface Radius")) .default_value({1.0f, 0.2f, 0.1f}) .min(0.0f) @@ -37,11 +40,15 @@ static void node_declare(NodeDeclarationBuilder &b) .min(0.0f) .max(1.0f) .subtype(PROP_FACTOR); + /* TODO: Also add support to Principled v1? Would be compatible at defaults afaics. */ + b.add_input<decl::Color>(N_("Metallic Edge")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); b.add_input<decl::Float>(N_("Specular")) .default_value(0.5f) .min(0.0f) .max(1.0f) .subtype(PROP_FACTOR); + /* TODO: Should be a color input in v2. Any way to keep compatibility? + * Maybe change to color everywhere and detect special case when float is connected? */ b.add_input<decl::Float>(N_("Specular Tint")) .default_value(0.0f) .min(0.0f) @@ -67,11 +74,18 @@ static void node_declare(NodeDeclarationBuilder &b) .min(0.0f) .max(1.0f) .subtype(PROP_FACTOR); + /* TODO: Should be a color input in v2. Any way to keep compatibility? + * Maybe change to color everywhere and detect special case when float is connected? */ b.add_input<decl::Float>(N_("Sheen Tint")) .default_value(0.5f) .min(0.0f) .max(1.0f) .subtype(PROP_FACTOR); + b.add_input<decl::Float>(N_("Sheen Roughness")) + .default_value(0.5f) + .min(0.0f) + .max(1.0f) + .subtype(PROP_FACTOR); b.add_input<decl::Float>(N_("Clearcoat")) .default_value(0.0f) .min(0.0f) @@ -82,6 +96,9 @@ static void node_declare(NodeDeclarationBuilder &b) .min(0.0f) .max(1.0f) .subtype(PROP_FACTOR); + /* TODO: Also add support to Principled v1? Would remain compatible and reduce differences. */ + b.add_input<decl::Color>(N_("Clearcoat Tint")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + /* TODO: Restrict min/max (e.g. 0.1 to 10) */ b.add_input<decl::Float>(N_("IOR")).default_value(1.45f).min(0.0f).max(1000.0f); b.add_input<decl::Float>(N_("Transmission")) .default_value(0.0f) @@ -93,6 +110,7 @@ static void node_declare(NodeDeclarationBuilder &b) .min(0.0f) .max(1.0f) .subtype(PROP_FACTOR); + /* TODO: Swap defaults (white, strength 0)? */ b.add_input<decl::Color>(N_("Emission")).default_value({0.0f, 0.0f, 0.0f, 1.0f}); b.add_input<decl::Float>(N_("Emission Strength")).default_value(1.0).min(0.0f).max(1000000.0f); b.add_input<decl::Float>(N_("Alpha")) @@ -115,7 +133,7 @@ static void node_shader_buts_principled(uiLayout *layout, bContext * /*C*/, Poin static void node_shader_init_principled(bNodeTree * /*ntree*/, bNode *node) { - node->custom1 = SHD_GLOSSY_GGX; + node->custom1 = SHD_PRINCIPLED_V2; node->custom2 = SHD_SUBSURFACE_RANDOM_WALK; } @@ -196,7 +214,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, use_subsurf = GPU_material_sss_profile_create(mat, &socket_data->value[1]); } - float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f; + float use_multi_scatter = (node->custom1 != SHD_PRINCIPLED_GGX) ? 1.0f : 0.0f; float use_sss = (use_subsurf) ? 1.0f : 0.0f; float use_diffuse_f = (use_diffuse) ? 1.0f : 0.0f; float use_clear_f = (use_clear) ? 1.0f : 0.0f; @@ -222,12 +240,40 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node) const int sss_method = node->custom2; LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { + const bool is_v2 = (distribution == SHD_PRINCIPLED_V2); if (STREQ(sock->name, "Transmission Roughness")) { - nodeSetSocketAvailability(ntree, sock, distribution == SHD_GLOSSY_GGX); + /* Only supported by the old separable glass model. */ + nodeSetSocketAvailability(ntree, sock, distribution == SHD_PRINCIPLED_GGX); + } + + if (STR_ELEM(sock->name, "Subsurface Anisotropy")) { + /* Only available with random-walk SSS. + * Principled v2 always uses random-walk SSS, so enable regardless of sss_method there. */ + nodeSetSocketAvailability(ntree, sock, is_v2 || (sss_method != SHD_SUBSURFACE_BURLEY)); + } + + if (STR_ELEM(sock->name, "Subsurface IOR")) { + /* Only available with random-walk SSS. Principled v2 uses the regular IOR input, however. */ + nodeSetSocketAvailability(ntree, sock, !is_v2 && (sss_method != SHD_SUBSURFACE_BURLEY)); + } + + if (STR_ELEM(sock->name, + "Subsurface", + "Subsurface Color", + "Specular", + "Specular Tint", + "Sheen Tint")) { + /* Sockets exclusive to Principled v1. */ + nodeSetSocketAvailability(ntree, sock, !is_v2); } - if (STR_ELEM(sock->name, "Subsurface IOR", "Subsurface Anisotropy")) { - nodeSetSocketAvailability(ntree, sock, sss_method != SHD_SUBSURFACE_BURLEY); + if (STR_ELEM(sock->name, + "Subsurface Scale", + "Clearcoat Tint", + "Sheen Roughness", + "Metallic Edge")) { + /* Sockets exclusive to Principled v2. */ + nodeSetSocketAvailability(ntree, sock, is_v2); } } } |