diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b38740e26d..bdb631b425e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -496,6 +496,7 @@ option(WITH_CYCLES_DEBUG "Build Cycles with options useful for debug option(WITH_CYCLES_STANDALONE "Build Cycles standalone application" OFF) option(WITH_CYCLES_STANDALONE_GUI "Build Cycles standalone with GUI" OFF) +option(WITH_CYCLES_PRECOMPUTE "Build Cycles data precomputation tool" OFF) option(WITH_CYCLES_HYDRA_RENDER_DELEGATE "Build Cycles Hydra render delegate" OFF) @@ -507,6 +508,7 @@ mark_as_advanced(WITH_CYCLES_KERNEL_ASAN) mark_as_advanced(WITH_CYCLES_LOGGING) mark_as_advanced(WITH_CYCLES_DEBUG_NAN) mark_as_advanced(WITH_CYCLES_NATIVE_ONLY) +mark_as_advanced(WITH_CYCLES_PRECOMPUTE) # NVIDIA CUDA & OptiX if(NOT APPLE) diff --git a/intern/cycles/app/CMakeLists.txt b/intern/cycles/app/CMakeLists.txt index 89181b0eb7e..7a96e193496 100644 --- a/intern/cycles/app/CMakeLists.txt +++ b/intern/cycles/app/CMakeLists.txt @@ -119,3 +119,22 @@ if(WITH_CYCLES_STANDALONE) $ DESTINATION ${CMAKE_INSTALL_PREFIX}) endif() + +if(WITH_CYCLES_PRECOMPUTE) + set(SRC + cycles_precompute.cpp + ) + + add_executable(cycles_precompute ${SRC} ${INC} ${INC_SYS}) + unset(SRC) + + target_link_libraries(cycles_precompute PRIVATE ${LIB}) + + if(UNIX AND NOT APPLE) + set_target_properties(cycles_precompute PROPERTIES INSTALL_RPATH $ORIGIN/lib) + endif() + + install(PROGRAMS + $ + DESTINATION ${CMAKE_INSTALL_PREFIX}) +endif() diff --git a/intern/cycles/app/cycles_precompute.cpp b/intern/cycles/app/cycles_precompute.cpp new file mode 100644 index 00000000000..9bb41c71d09 --- /dev/null +++ b/intern/cycles/app/cycles_precompute.cpp @@ -0,0 +1,192 @@ +#include "util/math.h" +#include "util/string.h" +#include "util/system.h" + +#include "util/array.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 + +CCL_NAMESPACE_BEGIN + +static float precompute_ggx_E(float rough, float mu, float3 rand) +{ + MicrofacetBsdf bsdf; + bsdf.weight = one_float3(); + 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.T = make_float3(1.0f, 0.0f, 0.0f); + + bsdf_microfacet_ggx_setup(&bsdf); + + float3 omega_in; + Spectrum eval; + float pdf = 0.0f, sampled_eta; + float2 sampled_roughness; + bsdf_microfacet_ggx_sample((ShaderClosure *)&bsdf, + 0, + make_float3(0.0f, 0.0f, 1.0f), + make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu), + rand, + &eval, + &omega_in, + &pdf, + &sampled_roughness, + &sampled_eta); + if (pdf != 0.0f) { + return average(eval) / pdf; + } + return 0.0f; +} + +static float precompute_ggx_glass_E(float rough, float mu, float eta, float3 rand) +{ + MicrofacetBsdf bsdf; + bsdf.weight = one_float3(); + 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.T = make_float3(1.0f, 0.0f, 0.0f); + + bsdf_microfacet_ggx_glass_setup(&bsdf); + + float3 omega_in; + Spectrum eval; + float pdf = 0.0f, sampled_eta; + float2 sampled_roughness; + bsdf_microfacet_ggx_sample((ShaderClosure *)&bsdf, + 0, + make_float3(0.0f, 0.0f, 1.0f), + make_float3(sqrtf(1.0f - sqr(mu)), 0.0f, mu), + rand, + &eval, + &omega_in, + &pdf, + &sampled_roughness, + &sampled_eta); + if (pdf != 0.0f) { + return average(eval) / pdf; + } + return 0.0f; +} + +struct PrecomputeTerm { + int samples; + int nx, ny, nz; + std::function evaluation; +}; + +static bool cycles_precompute(std::string name) +{ + std::map precompute_terms; + precompute_terms["ggx_E"] = { + 1 << 23, 32, 32, 1, [](float rough, float mu, float ior, float3 rand) { + return precompute_ggx_E(rough, mu, rand); + }}; + precompute_terms["ggx_Eavg"] = { + 1 << 26, 32, 1, 1, [](float rough, float mu, float ior, float3 rand) { + return 2.0f * mu * precompute_ggx_E(rough, mu, rand); + }}; + precompute_terms["ggx_glass_E"] = { + 1 << 23, 16, 16, 16, [](float rough, float mu, float ior, float3 rand) { + return precompute_ggx_glass_E(rough, mu, ior, rand); + }}; + precompute_terms["ggx_glass_Eavg"] = { + 1 << 26, 16, 1, 16, [](float rough, float mu, float ior, float3 rand) { + return 2.0f * mu * precompute_ggx_glass_E(rough, mu, ior, rand); + }}; + precompute_terms["ggx_glass_inv_E"] = { + 1 << 23, 16, 16, 16, [](float rough, float mu, float ior, float3 rand) { + return precompute_ggx_glass_E(rough, mu, 1.0f / ior, rand); + }}; + precompute_terms["ggx_glass_inv_Eavg"] = { + 1 << 26, 16, 1, 16, [](float rough, float mu, float ior, float3 rand) { + return 2.0f * mu * precompute_ggx_glass_E(rough, mu, 1.0f / ior, rand); + }}; + + if (precompute_terms.count(name) == 0) { + return false; + } + + const PrecomputeTerm &term = precompute_terms[name]; + + const int samples = term.samples; + const int nz = term.nz, ny = term.ny, nx = term.nx; + + std::cout << "static const float table_" << name << "[" << nz * ny * nx << "] = {" << std::endl; + for (int z = 0; z < nz; z++) { + array data(nx * ny); + parallel_for(0, nx * ny, [&](int64_t i) { + int y = i / nx, x = i % nx; + uint seed = hash_uint2(x, y); + double sum = 0.0; + for (int sample = 0; sample < samples; sample++) { + float4 rand = sobol_burley_sample_4D(sample, 0, seed, 0xffffffff); + + float rough = (nx == 1) ? 0.0f : clamp(float(x) / float(nx - 1), 1e-4f, 1.0f); + float mu = (ny == 1) ? rand.w : clamp(float(y) / float(ny - 1), 1e-4f, 1.0f); + float ior = (nz == 1) ? 0.0f : clamp(float(z) / float(nz - 1), 1e-4f, 0.99f); + /* This parametrization ensures that the entire [1..inf] range of IORs is covered + * and that most precision is allocated to the common areas (1-2). */ + ior = ior_from_F0(sqr(sqr(ior))); + + float value = term.evaluation(rough, mu, ior, float4_to_float3(rand)); + if (isnan(value)) { + value = 0.0f; + } + sum += (double)value; + } + data[y * nx + x] = saturatef(float(sum / double(samples))); + }); + + /* Print data formatted as C++ array */ + for (int y = 0; y < ny; y++) { + std::cout << " "; + for (int x = 0; x < nx; x++) { + std::cout << std::to_string(data[y * nx + x]); + if (x + 1 < nx) { + /* Next number will follow in same line */ + std::cout << "f, "; + } + else if (y + 1 < ny || z + 1 < nz) { + /* Next number will follow in next line */ + std::cout << "f,"; + } + else { + /* No next number */ + std::cout << "f"; + } + } + std::cout << std::endl; + } + /* If the array is three-dimensional, put an empty line between each slice. */ + if (ny > 1 && z + 1 < nz) { + std::cout << std::endl; + } + } + std::cout << "};" << std::endl; + + return true; +} + +CCL_NAMESPACE_END + +int main(int argc, const char **argv) +{ + if (argc < 2) { + return 1; + } + return ccl::cycles_precompute(argv[1]) ? 0 : 1; +} diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index d1c62598612..314d4c7cfab 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -123,8 +123,6 @@ 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_oren_nayar.h closure/bsdf_phong_ramp.h closure/bsdf_toon.h diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index 5c4f44f38c3..9ffb149a0b8 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -10,7 +10,6 @@ #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_transparent.h" #include "kernel/closure/bsdf_ashikhmin_shirley.h" #include "kernel/closure/bsdf_toon.h" @@ -170,34 +169,6 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg, label = bsdf_microfacet_ggx_sample( sc, path_flag, Ng, sd->wi, rand, eval, wo, pdf, sampled_roughness, eta); break; - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: - label = bsdf_microfacet_multi_ggx_sample(kg, - sc, - Ng, - sd->wi, - rand.x, - rand.y, - eval, - wo, - pdf, - &sd->lcg_state, - sampled_roughness, - eta); - break; - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: - label = bsdf_microfacet_multi_ggx_glass_sample(kg, - sc, - Ng, - sd->wi, - rand.x, - rand.y, - eval, - wo, - pdf, - &sd->lcg_state, - sampled_roughness, - eta); - break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: @@ -339,13 +310,6 @@ ccl_device_inline void bsdf_roughness_eta(const KernelGlobals kg, *eta = CLOSURE_IS_REFRACTIVE(bsdf->type) ? 1.0f / bsdf->ior : bsdf->ior; break; } - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_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_ASHIKHMIN_SHIRLEY_ID: { ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; *roughness = make_float2(bsdf->alpha_x, bsdf->alpha_y); @@ -433,13 +397,11 @@ ccl_device_inline int bsdf_label(const KernelGlobals kg, case CLOSURE_BSDF_SHARP_GLASS_ID: case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID: - case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: { + case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: { ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; label = ((bsdf_is_transmission(sc, wo)) ? LABEL_TRANSMIT : LABEL_REFLECT) | ((bsdf->alpha_x * bsdf->alpha_y <= 1e-7f) ? LABEL_SINGULAR : LABEL_GLOSSY); @@ -542,12 +504,6 @@ ccl_device_inline case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID: eval = bsdf_microfacet_ggx_eval(sc, sd->N, sd->wi, wo, pdf); break; - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: - eval = bsdf_microfacet_multi_ggx_eval(sc, sd->N, sd->wi, wo, pdf, &sd->lcg_state); - break; - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: - eval = bsdf_microfacet_multi_ggx_glass_eval(sc, sd->wi, wo, pdf, &sd->lcg_state); - break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: @@ -613,14 +569,11 @@ 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_GLASS_ID: - bsdf_microfacet_multi_ggx_blur(sc, roughness); - break; case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID: + /* TODO: Recompute energy preservation after blur? */ bsdf_microfacet_ggx_blur(sc, roughness); break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index bbf1d1c602e..e2b63d95bcb 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -28,19 +28,8 @@ enum MicrofacetFresnel { DIELECTRIC_TINT, /* used by the OSL MaterialX closures */ CONDUCTOR, GENERALIZED_SCHLICK, - CONSTANT, /* only needed by MultiGGX */ - PRINCIPLED_V1, }; -typedef struct FresnelPrincipledV1 { - Spectrum color; /* only needed by MultiGGX */ - Spectrum cspec0; -} FresnelPrincipledV1; - -typedef struct FresnelConstant { - Spectrum color; -} FresnelConstant; - typedef struct FresnelDielectricTint { Spectrum reflection_tint; Spectrum transmission_tint; @@ -53,7 +42,9 @@ typedef struct FresnelConductor { typedef struct FresnelGeneralizedSchlick { Spectrum reflection_tint; Spectrum transmission_tint; + /* Reflectivity at perpendicular (F0) and glancing (F90) angles. */ Spectrum f0, f90; + /* Negative exponent signals a special case where the real Fresnel is remapped to F0...F90. */ float exponent; } FresnelGeneralizedSchlick; @@ -61,8 +52,18 @@ typedef struct MicrofacetBsdf { SHADER_CLOSURE_BASE; float alpha_x, alpha_y, ior; + + /* Used to account for missing energy due to the single-scattering microfacet model. + * This could be included in bsdf->weight as well, but there it would mess up the color + * channels. + * Note that this is currently only used by GGX. */ + float energy_scale; + + /* Fresnel model to apply, as well as the extra data for it. + * For NONE and DIELECTRIC, no extra storage is needed, so the pointer is NULL for them. */ int fresnel_type; ccl_private void *fresnel; + float3 T; } MicrofacetBsdf; @@ -218,12 +219,7 @@ ccl_device_forceinline Spectrum microfacet_fresnel(ccl_private const MicrofacetB const float3 H, const bool refraction) { - if (bsdf->fresnel_type == MicrofacetFresnel::PRINCIPLED_V1) { - kernel_assert(!refraction); - ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel; - return interpolate_fresnel_color(wi, H, bsdf->ior, fresnel->cspec0); - } - else if (bsdf->fresnel_type == MicrofacetFresnel::DIELECTRIC) { + if (bsdf->fresnel_type == MicrofacetFresnel::DIELECTRIC) { const float F = fresnel_dielectric_cos(dot(wi, H), bsdf->ior); return make_spectrum(refraction ? 1.0f - F : F); } @@ -241,18 +237,29 @@ ccl_device_forceinline Spectrum microfacet_fresnel(ccl_private const MicrofacetB else if (bsdf->fresnel_type == MicrofacetFresnel::GENERALIZED_SCHLICK) { ccl_private FresnelGeneralizedSchlick *fresnel = (ccl_private FresnelGeneralizedSchlick *) bsdf->fresnel; - float cosI = dot(wi, H); - if (bsdf->ior < 1.0f) { - /* When going from a higher to a lower IOR, we must use the transmitted angle. */ - float sinT2 = (1.0f - sqr(cosI)) / sqr(bsdf->ior); - if (sinT2 >= 1.0f) { - /* Total internal reflection */ - return refraction ? zero_spectrum() : fresnel->reflection_tint; - } - cosI = safe_sqrtf(1.0f - sinT2); + float s; + if (fresnel->exponent < 0.0f) { + /* Special case: Use real Fresnel curve to determine the interpolation between F0 and F90. + * Used by Principled v1. */ + const float F_real = fresnel_dielectric_cos(dot(wi, H), bsdf->ior); + const float F0_real = F0_from_ior(bsdf->ior); + s = inverse_lerp(F0_real, 1.0f, F_real); + } + else { + /* Regular case: Generalized Schlick term. */ + float cosI = dot(wi, H); + if (bsdf->ior < 1.0f) { + /* When going from a higher to a lower IOR, we must use the transmitted angle. */ + const float sinT2 = (1.0f - sqr(cosI)) / sqr(bsdf->ior); + if (sinT2 >= 1.0f) { + /* Total internal reflection */ + return refraction ? zero_spectrum() : fresnel->reflection_tint; + } + cosI = safe_sqrtf(1.0f - sinT2); + } + /* TODO(lukas): Is a special case for exponent==5 worth it? */ + s = powf(1.0f - cosI, fresnel->exponent); } - /* TODO(lukas): Is a special case for exponent==5 worth it? */ - const float s = powf(1.0f - cosI, fresnel->exponent); const Spectrum F = mix(fresnel->f0, fresnel->f90, s); if (refraction) { return (one_spectrum() - F) * fresnel->transmission_tint; @@ -261,23 +268,75 @@ ccl_device_forceinline Spectrum microfacet_fresnel(ccl_private const MicrofacetB return F * fresnel->reflection_tint; } } - else if (bsdf->fresnel_type == MicrofacetFresnel::CONSTANT) { - /* CONSTANT is only used my MultiGGX, which doesn't call this function. - * Therefore, this case only happens when determining the albedo of a MultiGGX closure. - * In that case, return 1.0 since the constant color is already baked into the weight. */ - return one_spectrum(); - } else { return one_spectrum(); } } +ccl_device_inline void microfacet_ggx_preserve_energy(KernelGlobals kg, + ccl_private MicrofacetBsdf *bsdf, + ccl_private const ShaderData *sd, + const Spectrum Fss) +{ + const float mu = dot(sd->wi, bsdf->N); + const float rough = sqrtf(sqrtf(bsdf->alpha_x * bsdf->alpha_y)); + + float E, E_avg; + if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_ID) { + E = lookup_table_read_2D(kg, rough, mu, kernel_data.tables.ggx_E, 32, 32); + E_avg = lookup_table_read(kg, rough, kernel_data.tables.ggx_Eavg, 32); + } + else if (bsdf->type == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID) { + int ofs = kernel_data.tables.ggx_glass_E; + int avg_ofs = kernel_data.tables.ggx_glass_Eavg; + float ior = bsdf->ior; + if (ior < 1.0f) { + ior = 1.0f / ior; + ofs = kernel_data.tables.ggx_glass_inv_E; + avg_ofs = kernel_data.tables.ggx_glass_inv_Eavg; + } + /* TODO: Bias mu towards more precision for low values. */ + float z = sqrtf(fabsf((ior - 1.0f) / (ior + 1.0f))); + E = lookup_table_read_3D(kg, rough, mu, z, ofs, 16, 16, 16); + E_avg = lookup_table_read_2D(kg, rough, z, avg_ofs, 16, 16); + } + else { + kernel_assert(false); + E = 1.0f; + E_avg = 1.0f; + } + + const float missing_factor = ((1.0f - E) / E); + bsdf->energy_scale = 1.0f + missing_factor; + + /* Check if we need to account for extra darkening/saturation due to multi-bounce Fresnel. */ + if (Fss != one_spectrum()) { + /* Fms here is based on the appendix of "Revisiting Physically Based Shading at Imageworks" + * by Christopher Kulla and Alejandro Conty, + * 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. */ + const Spectrum Fms = Fss * E_avg / (one_spectrum() - Fss * (1.0f - E_avg)); + /* Since we already include the energy compensation in bsdf->energy_scale, + * this term is what's needed to make the full BSDF * weight * energy_scale + * computation work out to the correct value. */ + const Spectrum darkening = (one_spectrum() + Fms * missing_factor) / bsdf->energy_scale; + bsdf->weight *= darkening; + bsdf->sample_weight *= average(darkening); + } +} + /* This function estimates the albedo of the BSDF (NOT including the bsdf->weight) as caused by * the applied Fresnel model for the given view direction. - * The base microfacet model is assumed to have an albedo of 1, but e.g. a reflection-only - * closure with Fresnel applied can end up having a very low overall albedo. + * The base microfacet model is assumed to have an albedo of 1 (we have the energy preservation + * code for that), but e.g. a reflection-only closure with Fresnel applied can end up having + * a very low overall albedo. * This is used to adjust the sample weight, as well as for the Diff/Gloss/Trans Color pass - * and the Denoising Albedo pass. */ + * and the Denoising Albedo pass. + * + * NOTE: This code assumes the microfacet surface is fairly smooth. For very high roughness, + * the results are much more uniform across the surface. + * For better results, we'd be blending between this and Fss based on roughness, but that + * would involve storing or recomputing Fss, which is probably not worth it. */ ccl_device Spectrum bsdf_microfacet_estimate_fresnel(ccl_private const ShaderData *sd, ccl_private const MicrofacetBsdf *bsdf) { @@ -658,45 +717,105 @@ ccl_device int bsdf_microfacet_sample(ccl_private const ShaderClosure *sc, /* Fresnel term setup functions. These get called after the distribution-specific setup functions * like bsdf_microfacet_ggx_setup. */ -ccl_device void bsdf_microfacet_setup_fresnel_principledv1( - ccl_private MicrofacetBsdf *bsdf, - ccl_private const ShaderData *sd, - ccl_private FresnelPrincipledV1 *fresnel) -{ - fresnel->cspec0 = saturate(fresnel->cspec0); - - bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1; - bsdf->fresnel = fresnel; - bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf)); -} - -ccl_device void bsdf_microfacet_setup_fresnel_conductor(ccl_private MicrofacetBsdf *bsdf, +ccl_device void bsdf_microfacet_setup_fresnel_conductor(KernelGlobals kg, + ccl_private MicrofacetBsdf *bsdf, ccl_private const ShaderData *sd, - ccl_private FresnelConductor *fresnel) + ccl_private FresnelConductor *fresnel, + const bool preserve_energy) { bsdf->fresnel_type = MicrofacetFresnel::CONDUCTOR; bsdf->fresnel = fresnel; bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf)); + + if (preserve_energy) { + /* In order to estimate Fss of the conductor, we fit the F82-tint model to it based on the + * value at 0° and ~82° and then use the analytic expression for its Fss. */ + Spectrum F0 = fresnel_conductor(1.0f, fresnel->n, fresnel->k); + Spectrum F82 = fresnel_conductor(1.0f / 7.0f, fresnel->n, fresnel->k); + /* 0.46266436f is (1 - 1/7)^5, 17.651384f is 1/(1/7 * (1 - 1/7)^6) */ + Spectrum B = (mix(F0, one_spectrum(), 0.46266436f) - F82) * 17.651384f; + Spectrum Fss = saturate(mix(F0, one_spectrum(), 1.0f / 21.0f) - B * (1.0f / 126.0f)); + microfacet_ggx_preserve_energy(kg, bsdf, sd, Fss); + } } ccl_device void bsdf_microfacet_setup_fresnel_dielectric_tint( + KernelGlobals kg, ccl_private MicrofacetBsdf *bsdf, ccl_private const ShaderData *sd, - ccl_private FresnelDielectricTint *fresnel) + ccl_private FresnelDielectricTint *fresnel, + const bool preserve_energy) { bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC_TINT; bsdf->fresnel = fresnel; bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf)); + + if (preserve_energy) { + /* Assume that the transmissive tint makes up most of the overall color. */ + microfacet_ggx_preserve_energy(kg, bsdf, sd, fresnel->transmission_tint); + } } ccl_device void bsdf_microfacet_setup_fresnel_generalized_schlick( + KernelGlobals kg, ccl_private MicrofacetBsdf *bsdf, ccl_private const ShaderData *sd, - ccl_private FresnelGeneralizedSchlick *fresnel) + ccl_private FresnelGeneralizedSchlick *fresnel, + const bool preserve_energy) { bsdf->fresnel_type = MicrofacetFresnel::GENERALIZED_SCHLICK; bsdf->fresnel = fresnel; bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf)); + + if (preserve_energy) { + Spectrum Fss = one_spectrum(); + /* Multi-bounce Fresnel is only supported for reflective lobes here. */ + if (is_zero(fresnel->transmission_tint)) { + float s; + if (fresnel->exponent < 0.0f) { + const float eta = bsdf->ior; + const float real_F0 = F0_from_ior(bsdf->ior); + + /* Numerical fit for the integral of 2*cosI * F(cosI, eta) over 0...1 with F being + * the real dielectric Fresnel. From "Revisiting Physically Based Shading at Imageworks" + * by Christopher Kulla and Alejandro Conty. */ + float real_Fss; + if (eta < 1.0f) { + real_Fss = 0.997118f + eta * (0.1014f - eta * (0.965241f + eta * 0.130607f)); + } + else { + real_Fss = (eta - 1.0f) / (4.08567f + 1.00071f * eta); + } + s = saturatef(inverse_lerp(real_F0, 1.0f, real_Fss)); + } + else { + /* Integral of 2*cosI * (1 - cosI)^exponent over 0...1*/ + s = 2.0f / ((fresnel->exponent + 3.0f) * fresnel->exponent + 2.0f); + } + /* Due to the linearity of the generalized model, this ends up working. */ + Fss = fresnel->reflection_tint * mix(fresnel->f0, fresnel->f90, s); + } + else { + /* For transmissive BSDFs, assume that the transmissive tint makes up most of the overall + * color. */ + Fss = fresnel->transmission_tint; + } + + microfacet_ggx_preserve_energy(kg, bsdf, sd, Fss); + } +} + +ccl_device void bsdf_microfacet_setup_fresnel_constant(KernelGlobals kg, + ccl_private MicrofacetBsdf *bsdf, + ccl_private const ShaderData *sd, + const Spectrum color) +{ + /* Constant Fresnel is a special case - the color is already baked into the closure's + * weight, so we just need to perform the energy preservation. */ + kernel_assert(bsdf->fresnel_type == MicrofacetFresnel::NONE || + bsdf->fresnel_type == MicrofacetFresnel::DIELECTRIC); + + microfacet_ggx_preserve_energy(kg, bsdf, sd, color); } /* GGX microfacet with Smith shadow-masking from: @@ -718,6 +837,7 @@ ccl_device int bsdf_microfacet_ggx_setup(ccl_private MicrofacetBsdf *bsdf) bsdf->alpha_y = saturatef(bsdf->alpha_y); bsdf->fresnel_type = MicrofacetFresnel::NONE; + bsdf->energy_scale = 1.0f; bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_ID; return SD_BSDF | SD_BSDF_HAS_EVAL; @@ -730,6 +850,7 @@ ccl_device int bsdf_microfacet_ggx_clearcoat_setup(ccl_private MicrofacetBsdf *b bsdf->alpha_y = bsdf->alpha_x; bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC; + bsdf->energy_scale = 1.0f; bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID; bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(sd, bsdf)); @@ -742,6 +863,7 @@ ccl_device int bsdf_microfacet_ggx_refraction_setup(ccl_private MicrofacetBsdf * bsdf->alpha_y = bsdf->alpha_x; bsdf->fresnel_type = MicrofacetFresnel::NONE; + bsdf->energy_scale = 1.0f; bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_HAS_TRANSMISSION; @@ -753,6 +875,7 @@ ccl_device int bsdf_microfacet_ggx_glass_setup(ccl_private MicrofacetBsdf *bsdf) bsdf->alpha_y = bsdf->alpha_x; bsdf->fresnel_type = MicrofacetFresnel::DIELECTRIC; + bsdf->energy_scale = 1.0f; bsdf->type = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID; return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_HAS_TRANSMISSION; @@ -772,7 +895,8 @@ ccl_device Spectrum bsdf_microfacet_ggx_eval(ccl_private const ShaderClosure *sc const float3 wo, ccl_private float *pdf) { - return bsdf_microfacet_eval(sc, Ng, wi, wo, pdf); + ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; + return bsdf->energy_scale * bsdf_microfacet_eval(sc, Ng, wi, wo, pdf); } ccl_device int bsdf_microfacet_ggx_sample(ccl_private const ShaderClosure *sc, @@ -786,8 +910,11 @@ ccl_device int bsdf_microfacet_ggx_sample(ccl_private const ShaderClosure *sc, ccl_private float2 *sampled_roughness, ccl_private float *eta) { - return bsdf_microfacet_sample( + + int label = bsdf_microfacet_sample( sc, path_flag, Ng, wi, rand, eval, wo, pdf, sampled_roughness, eta); + *eval *= ((ccl_private const MicrofacetBsdf *)sc)->energy_scale; + return label; } /* Beckmann microfacet with Smith shadow-masking from: 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 6da5acbfbf3..00000000000 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h +++ /dev/null @@ -1,759 +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 = sin_from_cos(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); - - 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); - - ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel; - fresnel->color = saturate(fresnel->color); - - bsdf->fresnel_type = MicrofacetFresnel::CONSTANT; - 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); - - ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel; - fresnel->color = saturate(fresnel->color); - fresnel->cspec0 = saturate(fresnel->cspec0); - - bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1; - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; - bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(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; - - ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel; - fresnel->color = saturate(fresnel->color); - - bsdf->fresnel_type = MicrofacetFresnel::CONSTANT; - 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 Ng, - const float3 wi, - const float3 wo, - ccl_private float *pdf, - ccl_private uint *lcg_state) -{ - ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc; - const float cosNgO = dot(Ng, wo); - - if ((cosNgO < 0.0f) || 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, wi) <= 0.0f || dot(Z, wo) <= 0.0f) { - *pdf = 0.0f; - return zero_spectrum(); - } - - Spectrum color, cspec0; - bool use_fresnel; - if (bsdf->fresnel_type == MicrofacetFresnel::PRINCIPLED_V1) { - ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel; - use_fresnel = true; - color = fresnel->color; - cspec0 = fresnel->cspec0; - } - else { - kernel_assert(bsdf->fresnel_type == MicrofacetFresnel::CONSTANT); - ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel; - use_fresnel = false; - color = fresnel->color; - cspec0 = zero_spectrum(); - } - - 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 local_I = make_float3(dot(wi, X), dot(wi, Y), dot(wi, Z)); - float3 local_O = make_float3(dot(wo, X), dot(wo, Y), dot(wo, Z)); - - if (is_aniso) - *pdf = mf_ggx_aniso_pdf(local_I, local_O, make_float2(bsdf->alpha_x, bsdf->alpha_y)); - else - *pdf = mf_ggx_pdf(local_I, local_O, bsdf->alpha_x); - - if (*pdf <= 0.f) { - *pdf = 0.f; - return make_float3(0.f, 0.f, 0.f); - } - - return mf_eval_glossy(local_I, - local_O, - true, - color, - bsdf->alpha_x, - bsdf->alpha_y, - lcg_state, - bsdf->ior, - use_fresnel, - cspec0); -} - -ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals kg, - ccl_private const ShaderClosure *sc, - float3 Ng, - float3 wi, - float randu, - float randv, - ccl_private Spectrum *eval, - ccl_private float3 *wo, - 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, wi) <= 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) { - *wo = 2 * dot(Z, wi) * Z - wi; - if (dot(Ng, *wo) <= 0.0f) { - *pdf = 0.0f; - return LABEL_NONE; - } - *pdf = 1e6f; - *eval = make_spectrum(1e6f); - return LABEL_REFLECT | LABEL_SINGULAR; - } - - Spectrum color, cspec0; - bool use_fresnel; - if (bsdf->fresnel_type == MicrofacetFresnel::PRINCIPLED_V1) { - ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel; - use_fresnel = true; - color = fresnel->color; - cspec0 = fresnel->cspec0; - } - else { - kernel_assert(bsdf->fresnel_type == MicrofacetFresnel::CONSTANT); - ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel; - use_fresnel = false; - color = fresnel->color; - cspec0 = zero_spectrum(); - } - - *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 local_I = make_float3(dot(wi, X), dot(wi, Y), dot(wi, Z)); - float3 local_O; - - *eval = mf_sample_glossy(local_I, - &local_O, - color, - bsdf->alpha_x, - bsdf->alpha_y, - lcg_state, - bsdf->ior, - use_fresnel, - cspec0); - *wo = X * local_O.x + Y * local_O.y + Z * local_O.z; - - /* Ensure that the light direction is on the outside w.r.t. the geometry normal. */ - if (dot(Ng, *wo) <= 0.0f) { - *pdf = 0.0f; - return LABEL_NONE; - } - - if (is_aniso) - *pdf = mf_ggx_aniso_pdf(local_I, local_O, make_float2(bsdf->alpha_x, bsdf->alpha_y)); - else - *pdf = mf_ggx_pdf(local_I, local_O, 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); - - ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel; - fresnel->color = saturate(fresnel->color); - - bsdf->fresnel_type = MicrofacetFresnel::CONSTANT; - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; - - return SD_BSDF | SD_BSDF_HAS_EVAL | SD_BSDF_NEEDS_LCG | SD_BSDF_HAS_TRANSMISSION; -} - -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); - - ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel; - fresnel->color = saturate(fresnel->color); - fresnel->cspec0 = saturate(fresnel->cspec0); - - bsdf->fresnel_type = MicrofacetFresnel::PRINCIPLED_V1; - bsdf->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; - bsdf->sample_weight *= average(bsdf_microfacet_estimate_fresnel(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 wi, - const float3 wo, - 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 local_I = make_float3(dot(wi, X), dot(wi, Y), dot(wi, Z)); - float3 local_O = make_float3(dot(wo, X), dot(wo, Y), dot(wo, Z)); - - const bool is_transmission = local_O.z < 0.0f; - - Spectrum color, cspec0; - bool use_fresnel; - if (bsdf->fresnel_type == MicrofacetFresnel::PRINCIPLED_V1) { - ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel; - use_fresnel = true; - color = fresnel->color; - cspec0 = is_transmission ? fresnel->color : fresnel->cspec0; - } - else { - kernel_assert(bsdf->fresnel_type == MicrofacetFresnel::CONSTANT); - ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel; - use_fresnel = false; - color = fresnel->color; - cspec0 = zero_spectrum(); - } - - *pdf = mf_glass_pdf(local_I, local_O, bsdf->alpha_x, bsdf->ior); - kernel_assert(*pdf >= 0.f); - return mf_eval_glass(local_I, - local_O, - !is_transmission, - color, - bsdf->alpha_x, - bsdf->alpha_y, - lcg_state, - bsdf->ior, - !is_transmission && use_fresnel, - cspec0); -} - -ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals kg, - ccl_private const ShaderClosure *sc, - float3 Ng, - float3 wi, - float randu, - float randv, - ccl_private Spectrum *eval, - ccl_private float3 *wo, - 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 T; - bool inside; - float fresnel = fresnel_dielectric(bsdf->ior, Z, wi, &T, &inside); - - *pdf = 1e6f; - *eval = make_spectrum(1e6f); - if (randu < fresnel) { - *wo = 2 * dot(Z, wi) * Z - wi; - return LABEL_REFLECT | LABEL_SINGULAR; - } - else { - *wo = T; - return LABEL_TRANSMIT | LABEL_SINGULAR; - } - } - - Spectrum color, cspec0; - bool use_fresnel; - if (bsdf->fresnel_type == MicrofacetFresnel::PRINCIPLED_V1) { - ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *)bsdf->fresnel; - use_fresnel = true; - color = fresnel->color; - cspec0 = fresnel->cspec0; - } - else { - kernel_assert(bsdf->fresnel_type == MicrofacetFresnel::CONSTANT); - ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)bsdf->fresnel; - use_fresnel = false; - color = fresnel->color; - cspec0 = zero_spectrum(); - } - - make_orthonormals(Z, &X, &Y); - - float3 local_I = make_float3(dot(wi, X), dot(wi, Y), dot(wi, Z)); - float3 local_O; - - *eval = mf_sample_glass(local_I, - &local_O, - color, - bsdf->alpha_x, - bsdf->alpha_y, - lcg_state, - bsdf->ior, - use_fresnel, - cspec0); - *pdf = mf_glass_pdf(local_I, local_O, bsdf->alpha_x, bsdf->ior); - kernel_assert(*pdf >= 0.f); - *eval *= *pdf; - - *wo = X * local_O.x + Y * local_O.y + Z * local_O.z; - if (local_O.z * local_I.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 af1a821b361..00000000000 --- a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h +++ /dev/null @@ -1,250 +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 - - if (use_fresnel) { - throughput = interpolate_fresnel_color(wi, wh, eta, 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, cspec0); - } -#else /* MF_MULTI_GLOSSY */ - if (use_fresnel && order > 0) { - throughput *= interpolate_fresnel_color(-wr, wm, eta, 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; - - 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 { - throughput *= interpolate_fresnel_color(wi_prev, wm, eta, cspec0); - } - } -#else /* MF_MULTI_GLOSSY */ - if (use_fresnel) { - throughput *= interpolate_fresnel_color(-wr, wm, eta, cspec0); - } - 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_util.h b/intern/cycles/kernel/closure/bsdf_util.h index de59556bb08..4e62820619e 100644 --- a/intern/cycles/kernel/closure/bsdf_util.h +++ b/intern/cycles/kernel/closure/bsdf_util.h @@ -75,12 +75,17 @@ ccl_device Spectrum fresnel_conductor(float cosi, const Spectrum eta, const Spec return (Rparl2 + Rperp2) * 0.5f; } -ccl_device float ior_from_F0(Spectrum f0) +ccl_device float ior_from_F0(float f0) { - const float sqrt_f0 = sqrtf(clamp(average(f0), 0.0f, 0.99f)); + const float sqrt_f0 = sqrtf(clamp(f0, 0.0f, 0.99f)); return (1.0f + sqrt_f0) / (1.0f - sqrt_f0); } +ccl_device float F0_from_ior(float ior) +{ + return sqr((ior - 1.0f) / (ior + 1.0f)); +} + ccl_device float schlick_fresnel(float u) { float m = clamp(1.0f - u, 0.0f, 1.0f); diff --git a/intern/cycles/kernel/osl/closures_setup.h b/intern/cycles/kernel/osl/closures_setup.h index 549ab3b6b21..041d02e8f85 100644 --- a/intern/cycles/kernel/osl/closures_setup.h +++ b/intern/cycles/kernel/osl/closures_setup.h @@ -14,7 +14,6 @@ #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_oren_nayar.h" #include "kernel/closure/bsdf_transparent.h" #include "kernel/closure/bsdf_ashikhmin_shirley.h" @@ -209,27 +208,12 @@ ccl_device void osl_closure_dielectric_bsdf_setup(KernelGlobals kg, bsdf->alpha_x = closure->alpha_x; bsdf->alpha_y = closure->alpha_y; bsdf->ior = closure->ior; - if (sd->flag & SD_BACKFACING) { - bsdf->ior = 1.0f / bsdf->ior; - } bsdf->T = closure->T; - /* GGX */ - if (closure->distribution == make_string("ggx", 11253504724482777663ull) || - closure->distribution == make_string("default", 4430693559278735917ull)) - { - if (has_reflection && has_transmission) { - sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf); - } - else if (has_transmission) { - sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf); - } - else { - sd->flag |= bsdf_microfacet_ggx_setup(bsdf); - } - } + bool preserve_energy = false; + /* Beckmann */ - else { + if (closure->distribution == make_string("beckmann", 14712237670914973463ull)) { if (has_reflection && has_transmission) { sd->flag |= bsdf_microfacet_beckmann_glass_setup(bsdf); } @@ -240,10 +224,24 @@ ccl_device void osl_closure_dielectric_bsdf_setup(KernelGlobals kg, sd->flag |= bsdf_microfacet_beckmann_setup(bsdf); } } + /* GGX (either single- or multiscattering) */ + else { + if (has_reflection && has_transmission) { + sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf); + } + else if (has_transmission) { + sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf); + } + else { + sd->flag |= bsdf_microfacet_ggx_setup(bsdf); + } + + preserve_energy = (closure->distribution == make_string("multi_ggx", 16842698693386468366ull)); + } fresnel->reflection_tint = rgb_to_spectrum(closure->reflection_tint); fresnel->transmission_tint = rgb_to_spectrum(closure->transmission_tint); - bsdf_microfacet_setup_fresnel_dielectric_tint(bsdf, sd, fresnel); + bsdf_microfacet_setup_fresnel_dielectric_tint(kg, bsdf, sd, fresnel, preserve_energy); } ccl_device void osl_closure_conductor_bsdf_setup(KernelGlobals kg, @@ -274,20 +272,21 @@ ccl_device void osl_closure_conductor_bsdf_setup(KernelGlobals kg, bsdf->ior = 0.0f; bsdf->T = closure->T; - /* GGX */ - if (closure->distribution == make_string("ggx", 11253504724482777663ull) || - closure->distribution == make_string("default", 4430693559278735917ull)) - { - sd->flag |= bsdf_microfacet_ggx_setup(bsdf); - } + bool preserve_energy = false; + /* Beckmann */ - else { + if (closure->distribution == make_string("beckmann", 14712237670914973463ull)) { sd->flag |= bsdf_microfacet_beckmann_setup(bsdf); } + /* GGX (either single- or multiscattering) */ + else { + sd->flag |= bsdf_microfacet_ggx_setup(bsdf); + preserve_energy = (closure->distribution == make_string("multi_ggx", 16842698693386468366ull)); + } fresnel->n = rgb_to_spectrum(closure->ior); fresnel->k = rgb_to_spectrum(closure->extinction); - bsdf_microfacet_setup_fresnel_conductor(bsdf, sd, fresnel); + bsdf_microfacet_setup_fresnel_conductor(kg, bsdf, sd, fresnel, preserve_energy); } ccl_device void osl_closure_generalized_schlick_bsdf_setup( @@ -319,28 +318,16 @@ ccl_device void osl_closure_generalized_schlick_bsdf_setup( bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); bsdf->alpha_x = closure->alpha_x; bsdf->alpha_y = closure->alpha_y; - bsdf->ior = ior_from_F0(closure->f0); + bsdf->ior = ior_from_F0(average(closure->f0)); if (sd->flag & SD_BACKFACING) { bsdf->ior = 1.0f / bsdf->ior; } bsdf->T = closure->T; - /* GGX */ - if (closure->distribution == make_string("ggx", 11253504724482777663ull) || - closure->distribution == make_string("default", 4430693559278735917ull)) - { - if (has_reflection && has_transmission) { - sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf); - } - else if (has_transmission) { - sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf); - } - else { - sd->flag |= bsdf_microfacet_ggx_setup(bsdf); - } - } + bool preserve_energy = false; + /* Beckmann */ - else { + if (closure->distribution == make_string("beckmann", 14712237670914973463ull)) { if (has_reflection && has_transmission) { sd->flag |= bsdf_microfacet_beckmann_glass_setup(bsdf); } @@ -351,13 +338,27 @@ ccl_device void osl_closure_generalized_schlick_bsdf_setup( sd->flag |= bsdf_microfacet_beckmann_setup(bsdf); } } + /* GGX (either single- or multiscattering) */ + else { + if (has_reflection && has_transmission) { + sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf); + } + else if (has_transmission) { + sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf); + } + else { + sd->flag |= bsdf_microfacet_ggx_setup(bsdf); + } + + preserve_energy = (closure->distribution == make_string("multi_ggx", 16842698693386468366ull)); + } fresnel->reflection_tint = rgb_to_spectrum(closure->reflection_tint); fresnel->transmission_tint = rgb_to_spectrum(closure->transmission_tint); fresnel->f0 = rgb_to_spectrum(closure->f0); fresnel->f90 = rgb_to_spectrum(closure->f90); fresnel->exponent = closure->exponent; - bsdf_microfacet_setup_fresnel_generalized_schlick(bsdf, sd, fresnel); + bsdf_microfacet_setup_fresnel_generalized_schlick(kg, bsdf, sd, fresnel, preserve_energy); } /* Standard microfacet closures */ @@ -413,7 +414,7 @@ ccl_device void osl_closure_microfacet_setup(KernelGlobals kg, else if (closure->distribution == make_string("ashikhmin_shirley", 11318482998918370922ull)) { sd->flag |= bsdf_ashikhmin_shirley_setup(bsdf); } - /* GGX */ + /* GGX (either single- or multiscattering) */ else { if (closure->refract == 1) { sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf); @@ -424,195 +425,15 @@ ccl_device void osl_closure_microfacet_setup(KernelGlobals kg, else { sd->flag |= bsdf_microfacet_ggx_setup(bsdf); } + + if (closure->distribution == make_string("multi_ggx", 16842698693386468366ull)) { + /* Since there's no dedicated color input, the weight is the best we got. */ + bsdf_microfacet_setup_fresnel_constant(kg, bsdf, sd, rgb_to_spectrum(weight)); + } } } -ccl_device void osl_closure_microfacet_ggx_setup( - KernelGlobals kg, - ccl_private ShaderData *sd, - uint32_t path_flag, - float3 weight, - ccl_private const MicrofacetGGXIsotropicClosure *closure) -{ - if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { - return; - } - - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight)); - if (!bsdf) { - return; - } - - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); - bsdf->alpha_x = bsdf->alpha_y = closure->alpha_x; - - sd->flag |= bsdf_microfacet_ggx_setup(bsdf); -} - -ccl_device void osl_closure_microfacet_ggx_aniso_setup( - KernelGlobals kg, - ccl_private ShaderData *sd, - uint32_t path_flag, - float3 weight, - ccl_private const MicrofacetGGXClosure *closure) -{ - if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { - return; - } - - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight)); - if (!bsdf) { - return; - } - - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); - bsdf->alpha_x = closure->alpha_x; - bsdf->alpha_y = closure->alpha_y; - bsdf->T = closure->T; - - sd->flag |= bsdf_microfacet_ggx_setup(bsdf); -} - -ccl_device void osl_closure_microfacet_ggx_refraction_setup( - KernelGlobals kg, - ccl_private ShaderData *sd, - uint32_t path_flag, - float3 weight, - ccl_private const MicrofacetGGXRefractionClosure *closure) -{ - if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_TRANSMIT)) { - return; - } - - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight)); - if (!bsdf) { - return; - } - - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); - bsdf->alpha_x = closure->alpha_x; - bsdf->ior = closure->ior; - - sd->flag |= bsdf_microfacet_ggx_refraction_setup(bsdf); -} - -/* GGX closures with Fresnel */ - -ccl_device void osl_closure_microfacet_ggx_fresnel_setup( - KernelGlobals kg, - ccl_private ShaderData *sd, - uint32_t path_flag, - float3 weight, - ccl_private const MicrofacetGGXFresnelClosure *closure) -{ - if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { - return; - } - - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight)); - if (!bsdf) { - return; - } - - ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *) - closure_alloc_extra(sd, sizeof(FresnelPrincipledV1)); - if (!fresnel) { - return; - } - - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); - bsdf->alpha_x = closure->alpha_x; - bsdf->alpha_y = bsdf->alpha_x; - bsdf->ior = closure->ior; - bsdf->T = zero_float3(); - - sd->flag |= bsdf_microfacet_ggx_setup(bsdf); - - fresnel->color = rgb_to_spectrum(closure->color); - fresnel->cspec0 = rgb_to_spectrum(closure->cspec0); - bsdf_microfacet_setup_fresnel_principledv1(bsdf, sd, fresnel); -} - -ccl_device void osl_closure_microfacet_ggx_aniso_fresnel_setup( - KernelGlobals kg, - ccl_private ShaderData *sd, - uint32_t path_flag, - float3 weight, - ccl_private const MicrofacetGGXAnisoFresnelClosure *closure) -{ - if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { - return; - } - - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight)); - if (!bsdf) { - return; - } - - ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *) - closure_alloc_extra(sd, sizeof(FresnelPrincipledV1)); - if (!fresnel) { - return; - } - - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); - bsdf->alpha_x = closure->alpha_x; - bsdf->alpha_y = closure->alpha_y; - bsdf->ior = closure->ior; - bsdf->T = closure->T; - - sd->flag |= bsdf_microfacet_ggx_setup(bsdf); - - fresnel->color = rgb_to_spectrum(closure->color); - fresnel->cspec0 = rgb_to_spectrum(closure->cspec0); - bsdf_microfacet_setup_fresnel_principledv1(bsdf, sd, fresnel); -} - -/* Multi-scattering GGX closures */ - -ccl_device void osl_closure_microfacet_multi_ggx_setup( - KernelGlobals kg, - ccl_private ShaderData *sd, - uint32_t path_flag, - float3 weight, - ccl_private const MicrofacetMultiGGXClosure *closure) -{ - /* Technically, the MultiGGX closure may also transmit. However, - * since this is set statically and only used for caustic flags, this - * is probably as good as it gets. */ - if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { - return; - } - - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight)); - if (!bsdf) { - return; - } - - ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)closure_alloc_extra( - sd, sizeof(FresnelConstant)); - if (!fresnel) { - return; - } - - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); - bsdf->alpha_x = closure->alpha_x; - bsdf->alpha_y = bsdf->alpha_x; - bsdf->ior = 1.0f; - - bsdf->fresnel = fresnel; - fresnel->color = rgb_to_spectrum(closure->color); - - bsdf->T = zero_float3(); - - sd->flag |= bsdf_microfacet_multi_ggx_setup(bsdf); -} +/* Special-purpose Microfacet closures */ ccl_device void osl_closure_microfacet_multi_ggx_glass_setup( KernelGlobals kg, @@ -634,23 +455,15 @@ ccl_device void osl_closure_microfacet_multi_ggx_glass_setup( return; } - ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)closure_alloc_extra( - sd, sizeof(FresnelConstant)); - if (!fresnel) { - return; - } - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); bsdf->alpha_x = closure->alpha_x; bsdf->alpha_y = bsdf->alpha_x; bsdf->ior = closure->ior; - bsdf->fresnel = fresnel; - fresnel->color = rgb_to_spectrum(closure->color); - bsdf->T = zero_float3(); - sd->flag |= bsdf_microfacet_multi_ggx_glass_setup(bsdf); + sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf); + bsdf_microfacet_setup_fresnel_constant(kg, bsdf, sd, rgb_to_spectrum(closure->color)); } ccl_device void osl_closure_microfacet_multi_ggx_aniso_setup( @@ -658,11 +471,8 @@ ccl_device void osl_closure_microfacet_multi_ggx_aniso_setup( ccl_private ShaderData *sd, uint32_t path_flag, float3 weight, - ccl_private const MicrofacetMultiGGXAnisoClosure *closure) + ccl_private const MicrofacetMultiGGXClosure *closure) { - /* Technically, the MultiGGX closure may also transmit. However, - * since this is set statically and only used for caustic flags, this - * is probably as good as it gets. */ if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { return; } @@ -673,37 +483,24 @@ ccl_device void osl_closure_microfacet_multi_ggx_aniso_setup( return; } - ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)closure_alloc_extra( - sd, sizeof(FresnelConstant)); - if (!fresnel) { - return; - } - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); bsdf->alpha_x = closure->alpha_x; bsdf->alpha_y = closure->alpha_y; bsdf->ior = 1.0f; - bsdf->fresnel = fresnel; - fresnel->color = rgb_to_spectrum(closure->color); - bsdf->T = closure->T; - sd->flag |= bsdf_microfacet_multi_ggx_setup(bsdf); + sd->flag |= bsdf_microfacet_ggx_setup(bsdf); + bsdf_microfacet_setup_fresnel_constant(kg, bsdf, sd, rgb_to_spectrum(closure->color)); } -/* Multi-scattering GGX closures with Fresnel */ - -ccl_device void osl_closure_microfacet_multi_ggx_fresnel_setup( +ccl_device void osl_closure_microfacet_aniso_fresnel_setup( KernelGlobals kg, ccl_private ShaderData *sd, uint32_t path_flag, float3 weight, - ccl_private const MicrofacetMultiGGXFresnelClosure *closure) + ccl_private const MicrofacetAnisoFresnelClosure *closure) { - /* Technically, the MultiGGX closure may also transmit. However, - * since this is set statically and only used for caustic flags, this - * is probably as good as it gets. */ if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { return; } @@ -714,88 +511,8 @@ ccl_device void osl_closure_microfacet_multi_ggx_fresnel_setup( return; } - ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *) - closure_alloc_extra(sd, sizeof(FresnelPrincipledV1)); - if (!fresnel) { - return; - } - - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); - bsdf->alpha_x = closure->alpha_x; - bsdf->alpha_y = bsdf->alpha_x; - bsdf->ior = closure->ior; - - bsdf->fresnel = fresnel; - fresnel->color = rgb_to_spectrum(closure->color); - fresnel->cspec0 = rgb_to_spectrum(closure->cspec0); - - bsdf->T = zero_float3(); - - sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd); -} - -ccl_device void osl_closure_microfacet_multi_ggx_glass_fresnel_setup( - KernelGlobals kg, - ccl_private ShaderData *sd, - uint32_t path_flag, - float3 weight, - ccl_private const MicrofacetMultiGGXGlassFresnelClosure *closure) -{ - /* Technically, the MultiGGX closure may also transmit. However, - * since this is set statically and only used for caustic flags, this - * is probably as good as it gets. */ - if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { - return; - } - - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight)); - if (!bsdf) { - return; - } - - ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *) - closure_alloc_extra(sd, sizeof(FresnelPrincipledV1)); - if (!fresnel) { - return; - } - - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); - bsdf->alpha_x = closure->alpha_x; - bsdf->alpha_y = bsdf->alpha_x; - bsdf->ior = closure->ior; - - bsdf->fresnel = fresnel; - fresnel->color = rgb_to_spectrum(closure->color); - fresnel->cspec0 = rgb_to_spectrum(closure->cspec0); - - bsdf->T = zero_float3(); - - sd->flag |= bsdf_microfacet_multi_ggx_glass_fresnel_setup(bsdf, sd); -} - -ccl_device void osl_closure_microfacet_multi_ggx_aniso_fresnel_setup( - KernelGlobals kg, - ccl_private ShaderData *sd, - uint32_t path_flag, - float3 weight, - ccl_private const MicrofacetMultiGGXAnisoFresnelClosure *closure) -{ - /* Technically, the MultiGGX closure may also transmit. However, - * since this is set statically and only used for caustic flags, this - * is probably as good as it gets. */ - if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { - return; - } - - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight)); - if (!bsdf) { - return; - } - - ccl_private FresnelPrincipledV1 *fresnel = (ccl_private FresnelPrincipledV1 *) - closure_alloc_extra(sd, sizeof(FresnelPrincipledV1)); + ccl_private FresnelGeneralizedSchlick *fresnel = (ccl_private FresnelGeneralizedSchlick *) + closure_alloc_extra(sd, sizeof(FresnelGeneralizedSchlick)); if (!fresnel) { return; } @@ -804,91 +521,23 @@ ccl_device void osl_closure_microfacet_multi_ggx_aniso_fresnel_setup( bsdf->alpha_x = closure->alpha_x; bsdf->alpha_y = closure->alpha_y; bsdf->ior = closure->ior; - - bsdf->fresnel = fresnel; - fresnel->color = rgb_to_spectrum(closure->color); - fresnel->cspec0 = rgb_to_spectrum(closure->cspec0); - bsdf->T = closure->T; - sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd); + /* Only GGX (either single- or multiscattering) supported here */ + sd->flag |= bsdf_microfacet_ggx_setup(bsdf); + + const bool preserve_energy = (closure->distribution == + make_string("multi_ggx", 16842698693386468366ull)); + + fresnel->reflection_tint = one_spectrum(); + fresnel->transmission_tint = zero_spectrum(); + fresnel->f0 = rgb_to_spectrum(closure->f0); + fresnel->f90 = rgb_to_spectrum(closure->f90); + fresnel->exponent = -1.0f; + bsdf_microfacet_setup_fresnel_generalized_schlick(kg, bsdf, sd, fresnel, preserve_energy); } -/* Beckmann closures */ - -ccl_device void osl_closure_microfacet_beckmann_setup( - KernelGlobals kg, - ccl_private ShaderData *sd, - uint32_t path_flag, - float3 weight, - ccl_private const MicrofacetBeckmannIsotropicClosure *closure) -{ - if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { - return; - } - - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight)); - if (!bsdf) { - return; - } - - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); - bsdf->alpha_x = bsdf->alpha_y = closure->alpha_x; - - sd->flag |= bsdf_microfacet_beckmann_setup(bsdf); -} - -ccl_device void osl_closure_microfacet_beckmann_aniso_setup( - KernelGlobals kg, - ccl_private ShaderData *sd, - uint32_t path_flag, - float3 weight, - ccl_private const MicrofacetBeckmannClosure *closure) -{ - if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { - return; - } - - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight)); - if (!bsdf) { - return; - } - - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); - bsdf->alpha_x = closure->alpha_x; - bsdf->alpha_y = closure->alpha_y; - bsdf->T = closure->T; - - sd->flag |= bsdf_microfacet_beckmann_setup(bsdf); -} - -ccl_device void osl_closure_microfacet_beckmann_refraction_setup( - KernelGlobals kg, - ccl_private ShaderData *sd, - uint32_t path_flag, - float3 weight, - ccl_private const MicrofacetBeckmannRefractionClosure *closure) -{ - if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_TRANSMIT)) { - return; - } - - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight)); - if (!bsdf) { - return; - } - - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); - bsdf->alpha_x = closure->alpha_x; - bsdf->ior = closure->ior; - - sd->flag |= bsdf_microfacet_beckmann_refraction_setup(bsdf); -} - -/* Ashikhmin closures */ +/* Ashikhmin Velvet */ ccl_device void osl_closure_ashikhmin_velvet_setup( KernelGlobals kg, @@ -913,31 +562,6 @@ ccl_device void osl_closure_ashikhmin_velvet_setup( sd->flag |= bsdf_ashikhmin_velvet_setup(bsdf); } -ccl_device void osl_closure_ashikhmin_shirley_setup( - KernelGlobals kg, - ccl_private ShaderData *sd, - uint32_t path_flag, - float3 weight, - ccl_private const AshikhminShirleyClosure *closure) -{ - if (osl_closure_skip(kg, sd, path_flag, LABEL_GLOSSY | LABEL_REFLECT)) { - return; - } - - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), rgb_to_spectrum(weight)); - if (!bsdf) { - return; - } - - bsdf->N = ensure_valid_specular_reflection(sd->Ng, sd->wi, closure->N); - bsdf->alpha_x = closure->alpha_x; - bsdf->alpha_y = closure->alpha_y; - bsdf->T = closure->T; - - sd->flag |= bsdf_ashikhmin_shirley_setup(bsdf); -} - ccl_device void osl_closure_diffuse_toon_setup(KernelGlobals kg, ccl_private ShaderData *sd, uint32_t path_flag, diff --git a/intern/cycles/kernel/osl/closures_template.h b/intern/cycles/kernel/osl/closures_template.h index e1ecd7f9d06..e7b93e48769 100644 --- a/intern/cycles/kernel/osl/closures_template.h +++ b/intern/cycles/kernel/osl/closures_template.h @@ -83,30 +83,6 @@ OSL_CLOSURE_STRUCT_BEGIN(Microfacet, microfacet) OSL_CLOSURE_STRUCT_MEMBER(Microfacet, INT, int, refract, NULL) OSL_CLOSURE_STRUCT_END(Microfacet, microfacet) -OSL_CLOSURE_STRUCT_BEGIN(MicrofacetGGXIsotropic, microfacet_ggx) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXIsotropic, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXIsotropic, FLOAT, float, alpha_x, NULL) -OSL_CLOSURE_STRUCT_END(MicrofacetGGXIsotropic, microfacet_ggx) - -OSL_CLOSURE_STRUCT_BEGIN(MicrofacetGGX, microfacet_ggx_aniso) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGX, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGX, VECTOR, packed_float3, T, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGX, FLOAT, float, alpha_x, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGX, FLOAT, float, alpha_y, NULL) -OSL_CLOSURE_STRUCT_END(MicrofacetGGX, microfacet_ggx_aniso) - -OSL_CLOSURE_STRUCT_BEGIN(MicrofacetGGXRefraction, microfacet_ggx_refraction) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXRefraction, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXRefraction, FLOAT, float, alpha_x, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXRefraction, FLOAT, float, ior, NULL) -OSL_CLOSURE_STRUCT_END(MicrofacetGGXRefraction, microfacet_ggx_refraction) - -OSL_CLOSURE_STRUCT_BEGIN(MicrofacetMultiGGX, microfacet_multi_ggx) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGX, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGX, FLOAT, float, alpha_x, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGX, VECTOR, packed_float3, color, NULL) -OSL_CLOSURE_STRUCT_END(MicrofacetMultiGGX, microfacet_multi_ggx) - OSL_CLOSURE_STRUCT_BEGIN(MicrofacetMultiGGXGlass, microfacet_multi_ggx_glass) OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXGlass, VECTOR, packed_float3, N, NULL) OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXGlass, FLOAT, float, alpha_x, NULL) @@ -114,82 +90,24 @@ OSL_CLOSURE_STRUCT_BEGIN(MicrofacetMultiGGXGlass, microfacet_multi_ggx_glass) OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXGlass, VECTOR, packed_float3, color, NULL) OSL_CLOSURE_STRUCT_END(MicrofacetMultiGGXGlass, microfacet_multi_ggx_glass) -OSL_CLOSURE_STRUCT_BEGIN(MicrofacetMultiGGXAniso, microfacet_multi_ggx_aniso) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXAniso, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXAniso, VECTOR, packed_float3, T, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXAniso, FLOAT, float, alpha_x, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXAniso, FLOAT, float, alpha_y, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXAniso, VECTOR, packed_float3, color, NULL) -OSL_CLOSURE_STRUCT_END(MicrofacetMultiGGXAniso, microfacet_multi_ggx_aniso) +OSL_CLOSURE_STRUCT_BEGIN(MicrofacetMultiGGX, microfacet_multi_ggx_aniso) + OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGX, VECTOR, packed_float3, N, NULL) + OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGX, VECTOR, packed_float3, T, NULL) + OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGX, FLOAT, float, alpha_x, NULL) + OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGX, FLOAT, float, alpha_y, NULL) + OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGX, VECTOR, packed_float3, color, NULL) +OSL_CLOSURE_STRUCT_END(MicrofacetMultiGGX, microfacet_multi_ggx_aniso) -OSL_CLOSURE_STRUCT_BEGIN(MicrofacetGGXFresnel, microfacet_ggx_fresnel) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXFresnel, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXFresnel, FLOAT, float, alpha_x, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXFresnel, FLOAT, float, ior, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXFresnel, VECTOR, packed_float3, color, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXFresnel, VECTOR, packed_float3, cspec0, NULL) -OSL_CLOSURE_STRUCT_END(MicrofacetGGXFresnel, microfacet_ggx_fresnel) - -OSL_CLOSURE_STRUCT_BEGIN(MicrofacetGGXAnisoFresnel, microfacet_ggx_aniso_fresnel) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXAnisoFresnel, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXAnisoFresnel, VECTOR, packed_float3, T, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXAnisoFresnel, FLOAT, float, alpha_x, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXAnisoFresnel, FLOAT, float, alpha_y, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXAnisoFresnel, FLOAT, float, ior, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXAnisoFresnel, VECTOR, packed_float3, color, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetGGXAnisoFresnel, VECTOR, packed_float3, cspec0, NULL) -OSL_CLOSURE_STRUCT_END(MicrofacetGGXAnisoFresnel, microfacet_ggx_aniso_fresnel) - -OSL_CLOSURE_STRUCT_BEGIN(MicrofacetMultiGGXFresnel, microfacet_multi_ggx_fresnel) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXFresnel, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXFresnel, FLOAT, float, alpha_x, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXFresnel, FLOAT, float, ior, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXFresnel, VECTOR, packed_float3, color, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXFresnel, VECTOR, packed_float3, cspec0, NULL) -OSL_CLOSURE_STRUCT_END(MicrofacetMultiGGXFresnel, microfacet_multi_ggx_fresnel) - -OSL_CLOSURE_STRUCT_BEGIN(MicrofacetMultiGGXGlassFresnel, microfacet_multi_ggx_glass_fresnel) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXGlassFresnel, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXGlassFresnel, FLOAT, float, alpha_x, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXGlassFresnel, FLOAT, float, ior, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXGlassFresnel, VECTOR, packed_float3, color, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXGlassFresnel, VECTOR, packed_float3, cspec0, NULL) -OSL_CLOSURE_STRUCT_END(MicrofacetMultiGGXGlassFresnel, microfacet_multi_ggx_glass_fresnel) - -OSL_CLOSURE_STRUCT_BEGIN(MicrofacetMultiGGXAnisoFresnel, microfacet_multi_ggx_aniso_fresnel) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXAnisoFresnel, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXAnisoFresnel, VECTOR, packed_float3, T, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXAnisoFresnel, FLOAT, float, alpha_x, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXAnisoFresnel, FLOAT, float, alpha_y, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXAnisoFresnel, FLOAT, float, ior, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXAnisoFresnel, VECTOR, packed_float3, color, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetMultiGGXAnisoFresnel, VECTOR, packed_float3, cspec0, NULL) -OSL_CLOSURE_STRUCT_END(MicrofacetMultiGGXAnisoFresnel, microfacet_multi_ggx_aniso_fresnel) - -OSL_CLOSURE_STRUCT_BEGIN(MicrofacetBeckmannIsotropic, microfacet_beckmann) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetBeckmannIsotropic, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetBeckmannIsotropic, FLOAT, float, alpha_x, NULL) -OSL_CLOSURE_STRUCT_END(MicrofacetBeckmannIsotropic, microfacet_beckmann) - -OSL_CLOSURE_STRUCT_BEGIN(MicrofacetBeckmann, microfacet_beckmann_aniso) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetBeckmann, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetBeckmann, VECTOR, packed_float3, T, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetBeckmann, FLOAT, float, alpha_x, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetBeckmann, FLOAT, float, alpha_y, NULL) -OSL_CLOSURE_STRUCT_END(MicrofacetBeckmann, microfacet_beckmann_aniso) - -OSL_CLOSURE_STRUCT_BEGIN(MicrofacetBeckmannRefraction, microfacet_beckmann_refraction) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetBeckmannRefraction, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetBeckmannRefraction, FLOAT, float, alpha_x, NULL) - OSL_CLOSURE_STRUCT_MEMBER(MicrofacetBeckmannRefraction, FLOAT, float, ior, NULL) -OSL_CLOSURE_STRUCT_END(MicrofacetBeckmannRefraction, microfacet_beckmann_refraction) - -OSL_CLOSURE_STRUCT_BEGIN(AshikhminShirley, ashikhmin_shirley) - OSL_CLOSURE_STRUCT_MEMBER(AshikhminShirley, VECTOR, packed_float3, N, NULL) - OSL_CLOSURE_STRUCT_MEMBER(AshikhminShirley, VECTOR, packed_float3, T, NULL) - OSL_CLOSURE_STRUCT_MEMBER(AshikhminShirley, FLOAT, float, alpha_x, NULL) - OSL_CLOSURE_STRUCT_MEMBER(AshikhminShirley, FLOAT, float, alpha_y, NULL) -OSL_CLOSURE_STRUCT_END(AshikhminShirley, ashikhmin_shirley) +OSL_CLOSURE_STRUCT_BEGIN(MicrofacetAnisoFresnel, microfacet_aniso_fresnel) + OSL_CLOSURE_STRUCT_MEMBER(MicrofacetAnisoFresnel, VECTOR, packed_float3, N, NULL) + OSL_CLOSURE_STRUCT_MEMBER(MicrofacetAnisoFresnel, VECTOR, packed_float3, T, NULL) + OSL_CLOSURE_STRUCT_MEMBER(MicrofacetAnisoFresnel, FLOAT, float, alpha_x, NULL) + OSL_CLOSURE_STRUCT_MEMBER(MicrofacetAnisoFresnel, FLOAT, float, alpha_y, NULL) + OSL_CLOSURE_STRUCT_MEMBER(MicrofacetAnisoFresnel, VECTOR, packed_float3, f0, NULL) + OSL_CLOSURE_STRUCT_MEMBER(MicrofacetAnisoFresnel, VECTOR, packed_float3, f90, NULL) + OSL_CLOSURE_STRUCT_MEMBER(MicrofacetAnisoFresnel, FLOAT, float, ior, NULL) + OSL_CLOSURE_STRUCT_MEMBER(MicrofacetAnisoFresnel, STRING, DeviceString, distribution, NULL) +OSL_CLOSURE_STRUCT_END(MicrofacetAnisoFresnel, microfacet_aniso_fresnel) OSL_CLOSURE_STRUCT_BEGIN(AshikhminVelvet, ashikhmin_velvet) OSL_CLOSURE_STRUCT_MEMBER(AshikhminVelvet, VECTOR, packed_float3, N, NULL) diff --git a/intern/cycles/kernel/osl/shaders/node_fresnel.h b/intern/cycles/kernel/osl/shaders/node_fresnel.h index 42b6ad42b05..cb047fbef92 100644 --- a/intern/cycles/kernel/osl/shaders/node_fresnel.h +++ b/intern/cycles/kernel/osl/shaders/node_fresnel.h @@ -36,3 +36,9 @@ color fresnel_conductor(float cosi, color eta, color k) color Rperp2 = (tmp_f - (2.0 * eta * cosi) + cosi2) / (tmp_f + (2.0 * eta * cosi) + cosi2); return (Rparl2 + Rperp2) * 0.5; } + +float F0_from_ior(float eta) +{ + float f0 = (eta - 1.0) / (eta + 1.0); + return f0 * f0; +} diff --git a/intern/cycles/kernel/osl/shaders/node_glossy_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_glossy_bsdf.osl index 6bf5962e69d..074143e1d18 100644 --- a/intern/cycles/kernel/osl/shaders/node_glossy_bsdf.osl +++ b/intern/cycles/kernel/osl/shaders/node_glossy_bsdf.osl @@ -40,7 +40,7 @@ shader node_glossy_bsdf(color Color = 0.8, } if (distribution == "Multiscatter GGX") - BSDF = Color * microfacet_multi_ggx(Normal, roughness, Color); + BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, roughness_u, roughness_v, Color); else BSDF = Color * microfacet(distribution, Normal, T, roughness_u, roughness_v, 0.0, 0); } diff --git a/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl b/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl index 2499f90bc03..03ffc1ef6a4 100644 --- a/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl +++ b/intern/cycles/kernel/osl/shaders/node_principled_bsdf.osl @@ -4,7 +4,7 @@ #include "node_fresnel.h" #include "stdcycles.h" -shader node_principled_bsdf(string distribution = "Multiscatter GGX", +shader node_principled_bsdf(string distribution = "multi_ggx", string subsurface_method = "random_walk", color BaseColor = color(0.8, 0.8, 0.8), float Subsurface = 0.0, @@ -34,6 +34,7 @@ shader node_principled_bsdf(string distribution = "Multiscatter GGX", float diffuse_weight = (1.0 - clamp(Metallic, 0.0, 1.0)) * (1.0 - clamp(Transmission, 0.0, 1.0)); float final_transmission = clamp(Transmission, 0.0, 1.0) * (1.0 - clamp(Metallic, 0.0, 1.0)); float specular_weight = (1.0 - final_transmission); + float r2 = Roughness * Roughness; vector T = Tangent; @@ -65,52 +66,35 @@ shader node_principled_bsdf(string distribution = "Multiscatter GGX", } if (Sheen > 1e-5) { - color sheen_color = color(1.0, 1.0, 1.0) * (1.0 - SheenTint) + m_ctint * SheenTint; + color sheen_color = mix(color(1.0), m_ctint, SheenTint); - BSDF = BSDF + sheen_color * Sheen * principled_sheen(Normal); + BSDF += sheen_color * Sheen * principled_sheen(Normal); } - BSDF = BSDF * diffuse_weight; + BSDF *= diffuse_weight; } if (specular_weight > 1e-5) { float aspect = sqrt(1.0 - Anisotropic * 0.9); - float r2 = Roughness * Roughness; - float alpha_x = r2 / aspect; float alpha_y = r2 * aspect; - color tmp_col = color(1.0, 1.0, 1.0) * (1.0 - SpecularTint) + m_ctint * SpecularTint; + color tmp_col = mix(color(1.0), m_ctint, SpecularTint); color Cspec0 = (Specular * 0.08 * tmp_col) * (1.0 - Metallic) + BaseColor * Metallic; - if (distribution == "GGX" || Roughness <= 0.075) { - BSDF = BSDF + specular_weight * - microfacet_ggx_aniso_fresnel(Normal, - T, - alpha_x, - alpha_y, - (2.0 / (1.0 - sqrt(0.08 * Specular))) - 1.0, - BaseColor, - Cspec0); - } - else { - BSDF = BSDF + specular_weight * microfacet_multi_ggx_aniso_fresnel( - Normal, - T, - alpha_x, - alpha_y, - (2.0 / (1.0 - sqrt(0.08 * Specular))) - 1.0, - BaseColor, - Cspec0); - } + float eta = (2.0 / (1.0 - sqrt(0.08 * Specular))) - 1.0; + + string spec_dist = (Roughness <= 0.075) ? "ggx" : distribution; + BSDF += specular_weight * microfacet_aniso_fresnel( + Normal, T, alpha_x, alpha_y, Cspec0, color(1.0), eta, spec_dist); } if (final_transmission > 1e-5) { - color Cspec0 = BaseColor * SpecularTint + color(1.0, 1.0, 1.0) * (1.0 - SpecularTint); + color Cspec0 = mix(color(1.0), BaseColor, SpecularTint); float eta = backfacing() ? 1.0 / f : f; - if (distribution == "GGX" || Roughness <= 5e-2) { + if (distribution == "ggx" || Roughness <= 5e-2) { float cosNI = dot(Normal, I); float Fr = fresnel_dielectric_cos(cosNI, eta); @@ -119,26 +103,23 @@ shader node_principled_bsdf(string distribution = "Multiscatter GGX", refl_roughness = 0.0; float transmission_roughness = refl_roughness; - if (distribution == "GGX") + if (distribution == "ggx") transmission_roughness = 1.0 - (1.0 - refl_roughness) * (1.0 - TransmissionRoughness); - BSDF = BSDF + - final_transmission * - (Fr * microfacet_ggx_fresnel( - Normal, refl_roughness * refl_roughness, eta, BaseColor, Cspec0) + - (1.0 - Fr) * BaseColor * - microfacet_ggx_refraction( - Normal, transmission_roughness * transmission_roughness, eta)); + closure color refraction = microfacet( + "ggx", Normal, transmission_roughness * transmission_roughness, eta, 1); + closure color reflection = microfacet_aniso_fresnel( + Normal, T, r2, r2, Cspec0, color(1.0), eta, "ggx"); + BSDF += final_transmission * mix(BaseColor * refraction, reflection, Fr); } else { - BSDF = BSDF + - final_transmission * microfacet_multi_ggx_glass_fresnel( - Normal, Roughness * Roughness, eta, BaseColor, Cspec0); + BSDF += final_transmission * + dielectric_bsdf(Normal, vector(0.0), Cspec0, BaseColor, r2, r2, eta, "multi_ggx"); } } if (Clearcoat > 1e-5) { - BSDF = BSDF + principled_clearcoat( - ClearcoatNormal, Clearcoat, ClearcoatRoughness * ClearcoatRoughness); + BSDF += principled_clearcoat( + ClearcoatNormal, Clearcoat, ClearcoatRoughness * ClearcoatRoughness); } } diff --git a/intern/cycles/kernel/osl/shaders/stdcycles.h b/intern/cycles/kernel/osl/shaders/stdcycles.h index 6fe0e5987fa..4ecee50548e 100644 --- a/intern/cycles/kernel/osl/shaders/stdcycles.h +++ b/intern/cycles/kernel/osl/shaders/stdcycles.h @@ -20,31 +20,21 @@ closure color diffuse_ramp(normal N, color colors[8]) BUILTIN; closure color phong_ramp(normal N, float exponent, color colors[8]) BUILTIN; closure color diffuse_toon(normal N, float size, float smooth) BUILTIN; closure color glossy_toon(normal N, float size, float smooth) BUILTIN; -closure color microfacet_ggx(normal N, float ag) BUILTIN; -closure color microfacet_ggx_aniso(normal N, vector T, float ax, float ay) BUILTIN; -closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN; -closure color microfacet_multi_ggx(normal N, float ag, color C) BUILTIN; -closure color microfacet_multi_ggx_aniso(normal N, vector T, float ax, float ay, color C) BUILTIN; -closure color microfacet_multi_ggx_glass(normal N, float ag, float eta, color C) BUILTIN; -closure color microfacet_ggx_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN; -closure color microfacet_ggx_aniso_fresnel( - normal N, vector T, float ax, float ay, float eta, color C, color Cspec0) BUILTIN; -closure color -microfacet_multi_ggx_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN; -closure color microfacet_multi_ggx_aniso_fresnel( - normal N, vector T, float ax, float ay, float eta, color C, color Cspec0) BUILTIN; -closure color -microfacet_multi_ggx_glass_fresnel(normal N, float ag, float eta, color C, color Cspec0) BUILTIN; -closure color microfacet_beckmann(normal N, float ab) BUILTIN; -closure color microfacet_beckmann_aniso(normal N, vector T, float ax, float ay) BUILTIN; -closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN; -closure color ashikhmin_shirley(normal N, vector T, float ax, float ay) BUILTIN; closure color ashikhmin_velvet(normal N, float sigma) BUILTIN; closure color ambient_occlusion() BUILTIN; closure color principled_diffuse(normal N, float roughness) BUILTIN; closure color principled_sheen(normal N) BUILTIN; closure color principled_clearcoat(normal N, float clearcoat, float clearcoat_roughness) BUILTIN; +/* Needed to pass along the color for multiscattering saturation adjustment, + * otherwise could be replaced by microfacet() */ +closure color microfacet_multi_ggx_glass(normal N, float ag, float eta, color C) BUILTIN; +closure color microfacet_multi_ggx_aniso(normal N, vector T, float ax, float ay, color C) BUILTIN; +/* Needed to pass along the IOR for the Principled V1 Fresnel calculation, + * otherwise could be replaced by generalized_schlick_bsdf() */ +closure color microfacet_aniso_fresnel( + normal N, vector T, float ax, float ay, color f0, color f90, float eta, string dist) BUILTIN; + // BSSRDF closure color bssrdf(string method, normal N, vector radius, color albedo) BUILTIN; diff --git a/intern/cycles/kernel/svm/closure.h b/intern/cycles/kernel/svm/closure.h index 10e88f126a1..9b9c22acced 100644 --- a/intern/cycles/kernel/svm/closure.h +++ b/intern/cycles/kernel/svm/closure.h @@ -261,9 +261,9 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( sd, sizeof(MicrofacetBsdf), spec_weight); - ccl_private FresnelPrincipledV1 *fresnel = - (bsdf != NULL) ? (ccl_private FresnelPrincipledV1 *)closure_alloc_extra( - sd, sizeof(FresnelPrincipledV1)) : + ccl_private FresnelGeneralizedSchlick *fresnel = + (bsdf != NULL) ? (ccl_private FresnelGeneralizedSchlick *)closure_alloc_extra( + sd, sizeof(FresnelGeneralizedSchlick)) : NULL; if (bsdf && fresnel) { @@ -283,22 +283,17 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, one_float3(); // normalize lum. to isolate hue+sat float3 tmp_col = make_float3(1.0f - specular_tint) + m_ctint * specular_tint; - fresnel->cspec0 = rgb_to_spectrum((specular * 0.08f * tmp_col) * (1.0f - metallic) + - base_color * metallic); - fresnel->color = rgb_to_spectrum(base_color); + fresnel->f0 = rgb_to_spectrum((specular * 0.08f * tmp_col) * (1.0f - metallic) + + base_color * metallic); + fresnel->f90 = one_spectrum(); + fresnel->exponent = -1.0f; + fresnel->reflection_tint = one_spectrum(); + fresnel->transmission_tint = zero_spectrum(); /* setup bsdf */ - - /* Use single-scatter GGX. */ - if (distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID || roughness <= 0.075f) { - sd->flag |= bsdf_microfacet_ggx_setup(bsdf); - bsdf_microfacet_setup_fresnel_principledv1(bsdf, sd, fresnel); - } /* Use multi-scatter GGX. */ - else { - - bsdf->fresnel = fresnel; - sd->flag |= bsdf_microfacet_multi_ggx_fresnel_setup(bsdf, sd); - } + sd->flag |= bsdf_microfacet_ggx_setup(bsdf); + const bool is_multiggx = (distribution == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); + bsdf_microfacet_setup_fresnel_generalized_schlick(kg, bsdf, sd, fresnel, is_multiggx); } } #ifdef __CAUSTICS_TRICKS__ @@ -313,7 +308,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, #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); + Spectrum cspec0 = base_color * specular_tint + make_float3(1.0f - specular_tint); /* Use single-scatter GGX. */ if (roughness <= 5e-2f || distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID) { @@ -327,15 +322,14 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, { ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( sd, sizeof(MicrofacetBsdf), glass_weight * fresnel); - ccl_private FresnelPrincipledV1 *fresnel = - (bsdf != NULL) ? (ccl_private FresnelPrincipledV1 *)closure_alloc_extra( - sd, sizeof(FresnelPrincipledV1)) : + ccl_private FresnelGeneralizedSchlick *fresnel = + (bsdf != NULL) ? (ccl_private FresnelGeneralizedSchlick *)closure_alloc_extra( + sd, sizeof(FresnelGeneralizedSchlick)) : NULL; if (bsdf && fresnel) { bsdf->N = valid_reflection_N; bsdf->T = zero_float3(); - bsdf->fresnel = fresnel; bsdf->alpha_x = refl_roughness * refl_roughness; bsdf->alpha_y = refl_roughness * refl_roughness; @@ -344,9 +338,13 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, /* setup bsdf */ sd->flag |= bsdf_microfacet_ggx_setup(bsdf); - fresnel->color = rgb_to_spectrum(base_color); - fresnel->cspec0 = rgb_to_spectrum(cspec0); - bsdf_microfacet_setup_fresnel_principledv1(bsdf, sd, fresnel); + fresnel->f0 = cspec0; + fresnel->f90 = one_spectrum(); + fresnel->exponent = -1.0f; + fresnel->reflection_tint = one_spectrum(); + fresnel->transmission_tint = zero_spectrum(); + + bsdf_microfacet_setup_fresnel_generalized_schlick(kg, bsdf, sd, fresnel, false); } } @@ -364,7 +362,6 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, if (bsdf) { bsdf->N = valid_reflection_N; bsdf->T = zero_float3(); - bsdf->fresnel = NULL; if (distribution == CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID) transmission_roughness = 1.0f - (1.0f - refl_roughness) * @@ -384,25 +381,28 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, else { ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( sd, sizeof(MicrofacetBsdf), glass_weight); - ccl_private FresnelPrincipledV1 *fresnel = - (bsdf != NULL) ? (ccl_private FresnelPrincipledV1 *)closure_alloc_extra( - sd, sizeof(FresnelPrincipledV1)) : + ccl_private FresnelGeneralizedSchlick *fresnel = + (bsdf != NULL) ? (ccl_private FresnelGeneralizedSchlick *)closure_alloc_extra( + sd, sizeof(FresnelGeneralizedSchlick)) : NULL; if (bsdf && fresnel) { bsdf->N = valid_reflection_N; - bsdf->fresnel = fresnel; bsdf->T = zero_float3(); bsdf->alpha_x = roughness * roughness; bsdf->alpha_y = roughness * roughness; bsdf->ior = ior; - fresnel->color = rgb_to_spectrum(base_color); - fresnel->cspec0 = rgb_to_spectrum(cspec0); + fresnel->f0 = make_spectrum(F0_from_ior(ior)); + fresnel->f90 = one_spectrum(); + fresnel->exponent = -1.0f; + fresnel->reflection_tint = cspec0; + fresnel->transmission_tint = base_color; /* setup bsdf */ - sd->flag |= bsdf_microfacet_multi_ggx_glass_fresnel_setup(bsdf, sd); + sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf); + bsdf_microfacet_setup_fresnel_generalized_schlick(kg, bsdf, sd, fresnel, true); } } } @@ -492,7 +492,6 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, bsdf->N = maybe_ensure_valid_specular_reflection(sd, N); bsdf->ior = 1.0f; - bsdf->fresnel = NULL; /* compute roughness */ float anisotropy = clamp(param2, -0.99f, 0.99f); @@ -525,20 +524,16 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, sd->flag |= bsdf_reflection_setup(bsdf); else if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID) sd->flag |= bsdf_microfacet_beckmann_setup(bsdf); - else if (type == CLOSURE_BSDF_MICROFACET_GGX_ID) - sd->flag |= bsdf_microfacet_ggx_setup(bsdf); - else if (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) { - kernel_assert(stack_valid(data_node.w)); - ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)closure_alloc_extra( - sd, sizeof(FresnelConstant)); - if (fresnel) { - bsdf->fresnel = fresnel; - fresnel->color = rgb_to_spectrum(stack_load_float3(stack, data_node.w)); - sd->flag |= bsdf_microfacet_multi_ggx_setup(bsdf); - } + else if (type == CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID) { + sd->flag |= bsdf_ashikhmin_shirley_setup(bsdf); } else { - sd->flag |= bsdf_ashikhmin_shirley_setup(bsdf); + sd->flag |= bsdf_microfacet_ggx_setup(bsdf); + if (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) { + kernel_assert(stack_valid(data_node.w)); + const Spectrum color = rgb_to_spectrum(stack_load_float3(stack, data_node.w)); + bsdf_microfacet_setup_fresnel_constant(kg, bsdf, sd, color); + } } break; @@ -557,7 +552,6 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, if (bsdf) { bsdf->N = maybe_ensure_valid_specular_reflection(sd, N); bsdf->T = zero_float3(); - bsdf->fresnel = NULL; float eta = fmaxf(param2, 1e-5f); eta = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta; @@ -587,7 +581,8 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, } case CLOSURE_BSDF_SHARP_GLASS_ID: case CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID: - case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: { + case CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: { #ifdef __CAUSTICS_TRICKS__ if (!kernel_data.integrator.caustics_reflective && !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) @@ -621,49 +616,19 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, if (type == CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID) sd->flag |= bsdf_microfacet_beckmann_glass_setup(bsdf); - else + else { sd->flag |= bsdf_microfacet_ggx_glass_setup(bsdf); + if (type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) { + kernel_assert(stack_valid(data_node.z)); + const Spectrum color = rgb_to_spectrum(stack_load_float3(stack, data_node.z)); + bsdf_microfacet_setup_fresnel_constant(kg, bsdf, sd, color); + } + } } } break; } - case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: { -#ifdef __CAUSTICS_TRICKS__ - if (!kernel_data.integrator.caustics_reflective && - !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) - break; -#endif - Spectrum weight = sd->svm_closure_weight * mix_weight; - ccl_private MicrofacetBsdf *bsdf = (ccl_private MicrofacetBsdf *)bsdf_alloc( - sd, sizeof(MicrofacetBsdf), weight); - if (!bsdf) { - break; - } - - ccl_private FresnelConstant *fresnel = (ccl_private FresnelConstant *)closure_alloc_extra( - sd, sizeof(FresnelConstant)); - if (!fresnel) { - break; - } - - bsdf->N = maybe_ensure_valid_specular_reflection(sd, N); - bsdf->fresnel = fresnel; - bsdf->T = zero_float3(); - - float roughness = sqr(param1); - bsdf->alpha_x = roughness; - bsdf->alpha_y = roughness; - float eta = fmaxf(param2, 1e-5f); - bsdf->ior = (sd->flag & SD_BACKFACING) ? 1.0f / eta : eta; - - kernel_assert(stack_valid(data_node.z)); - fresnel->color = rgb_to_spectrum(stack_load_float3(stack, data_node.z)); - - /* setup bsdf */ - sd->flag |= bsdf_microfacet_multi_ggx_glass_setup(bsdf); - break; - } case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: { Spectrum weight = sd->svm_closure_weight * mix_weight; ccl_private VelvetBsdf *bsdf = (ccl_private VelvetBsdf *)bsdf_alloc( diff --git a/intern/cycles/kernel/svm/types.h b/intern/cycles/kernel/svm/types.h index b106cfed891..5cfd237ae23 100644 --- a/intern/cycles/kernel/svm/types.h +++ b/intern/cycles/kernel/svm/types.h @@ -423,7 +423,7 @@ typedef enum ClosureType { CLOSURE_BSDF_MICROFACET_GGX_ID, CLOSURE_BSDF_MICROFACET_GGX_CLEARCOAT_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_ID, - CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID, /* virtual closure */ CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID, CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, CLOSURE_BSDF_PHONG_RAMP_ID, @@ -437,7 +437,7 @@ typedef enum ClosureType { CLOSURE_BSDF_SHARP_GLASS_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID, - CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, /* virtual closure */ CLOSURE_BSDF_HAIR_PRINCIPLED_ID, CLOSURE_BSDF_HAIR_TRANSMISSION_ID, diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 14951e933fb..96185284198 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -1224,7 +1224,13 @@ typedef enum KernelBVHLayout { typedef struct KernelTables { int filter_table_offset; - int pad1, pad2, pad3; + int ggx_E; + int ggx_Eavg; + int ggx_glass_E; + int ggx_glass_Eavg; + int ggx_glass_inv_E; + int ggx_glass_inv_Eavg; + int pad1; } 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..aee0729c841 100644 --- a/intern/cycles/kernel/util/lookup_table.h +++ b/intern/cycles/kernel/util/lookup_table.h @@ -40,4 +40,21 @@ ccl_device float lookup_table_read_2D( return (1.0f - t) * data0 + t * data1; } +ccl_device float lookup_table_read_3D( + KernelGlobals kg, float x, float y, float z, int offset, int xsize, int ysize, int zsize) +{ + z = saturatef(z) * (zsize - 1); + + 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 (1.0f - t) * data0 + t * data1; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/scene/shader.cpp b/intern/cycles/scene/shader.cpp index 1a37d87513c..f9b7a6dff7c 100644 --- a/intern/cycles/scene/shader.cpp +++ b/intern/cycles/scene/shader.cpp @@ -29,6 +29,8 @@ namespace OCIO = OCIO_NAMESPACE; #endif +#include "scene/shader.tables" + CCL_NAMESPACE_BEGIN thread_mutex ShaderManager::lookup_table_mutex; @@ -564,6 +566,15 @@ void ShaderManager::device_update_common(Device * /*device*/, dscene->shaders.copy_to_device(); + /* lookup tables */ + KernelTables *ktables = &dscene->data.tables; + ktables->ggx_E = ensure_bsdf_table(dscene, scene, table_ggx_E); + ktables->ggx_Eavg = ensure_bsdf_table(dscene, scene, table_ggx_Eavg); + ktables->ggx_glass_E = ensure_bsdf_table(dscene, scene, table_ggx_glass_E); + ktables->ggx_glass_Eavg = ensure_bsdf_table(dscene, scene, table_ggx_glass_Eavg); + ktables->ggx_glass_inv_E = ensure_bsdf_table(dscene, scene, table_ggx_glass_inv_E); + ktables->ggx_glass_inv_Eavg = ensure_bsdf_table(dscene, scene, table_ggx_glass_inv_Eavg); + /* integrator */ KernelIntegrator *kintegrator = &dscene->data.integrator; kintegrator->use_volumes = has_volumes; @@ -583,8 +594,13 @@ void ShaderManager::device_update_common(Device * /*device*/, kfilm->is_rec709 = is_rec709; } -void ShaderManager::device_free_common(Device * /*device*/, DeviceScene *dscene, Scene * /*scene*/) +void ShaderManager::device_free_common(Device * /*device*/, DeviceScene *dscene, Scene *scene) { + for (auto &entry : bsdf_tables) { + scene->lookup_tables->remove_table(&entry.second); + } + bsdf_tables.clear(); + dscene->shaders.free(); } @@ -889,4 +905,17 @@ void ShaderManager::init_xyz_transforms() #endif } +size_t ShaderManager::ensure_bsdf_table_impl(DeviceScene *dscene, + Scene *scene, + const float *table, + size_t n) +{ + /* Since the BSDF tables are static arrays, we can use their address to identify them. */ + if (!(bsdf_tables.count(table))) { + vector entries(table, table + n); + bsdf_tables[table] = scene->lookup_tables->add_table(dscene, entries); + } + return bsdf_tables[table]; +} + CCL_NAMESPACE_END diff --git a/intern/cycles/scene/shader.h b/intern/cycles/scene/shader.h index fab09fcd9d3..d3dd53e736f 100644 --- a/intern/cycles/scene/shader.h +++ b/intern/cycles/scene/shader.h @@ -233,6 +233,15 @@ class ShaderManager { static thread_mutex lookup_table_mutex; + unordered_map bsdf_tables; + + template + size_t ensure_bsdf_table(DeviceScene *dscene, Scene *scene, const float (&table)[n]) + { + return ensure_bsdf_table_impl(dscene, scene, table, n); + } + size_t ensure_bsdf_table_impl(DeviceScene *dscene, Scene *scene, const float *table, size_t n); + uint get_graph_kernel_features(ShaderGraph *graph); thread_spin_lock attribute_lock_; diff --git a/intern/cycles/scene/shader.tables b/intern/cycles/scene/shader.tables new file mode 100644 index 00000000000..bbd4c5cae42 --- /dev/null +++ b/intern/cycles/scene/shader.tables @@ -0,0 +1,635 @@ +/* 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. */ + +CCL_NAMESPACE_BEGIN + +/* Precomputed BSDF albedo tables for various microfacet distributions. */ + +static const float table_ggx_E[1024] = { + 1.000000f, 0.980405f, 0.994967f, 0.997749f, 0.998725f, 0.999173f, 0.999411f, 0.999550f, 0.999634f, 0.999686f, 0.999716f, 0.999732f, 0.999738f, 0.999735f, 0.999726f, 0.999712f, 0.999693f, 0.999671f, 0.999645f, 0.999615f, 0.999583f, 0.999548f, 0.999511f, 0.999471f, 0.999429f, 0.999385f, 0.999338f, 0.999290f, 0.999240f, 0.999188f, 0.999134f, 0.999079f, + 1.000000f, 0.999451f, 0.990086f, 0.954714f, 0.911203f, 0.891678f, 0.893893f, 0.905010f, 0.917411f, 0.928221f, 0.936755f, 0.943104f, 0.947567f, 0.950455f, 0.952036f, 0.952526f, 0.952096f, 0.950879f, 0.948983f, 0.946495f, 0.943484f, 0.940010f, 0.936122f, 0.931864f, 0.927272f, 0.922380f, 0.917217f, 0.911810f, 0.906184f, 0.900361f, 0.894361f, 0.888202f, + 1.000000f, 0.999866f, 0.997676f, 0.987331f, 0.962386f, 0.929174f, 0.902886f, 0.890270f, 0.888687f, 0.893114f, 0.899716f, 0.906297f, 0.911810f, 0.915853f, 0.918345f, 0.919348f, 0.918982f, 0.917380f, 0.914671f, 0.910973f, 0.906393f, 0.901026f, 0.894957f, 0.888261f, 0.881006f, 0.873254f, 0.865061f, 0.856478f, 0.847553f, 0.838329f, 0.828845f, 0.819138f, + 1.000000f, 0.999941f, 0.998997f, 0.994519f, 0.982075f, 0.959460f, 0.931758f, 0.907714f, 0.892271f, 0.885248f, 0.884058f, 0.885962f, 0.888923f, 0.891666f, 0.893488f, 0.894054f, 0.893246f, 0.891062f, 0.887565f, 0.882845f, 0.877003f, 0.870143f, 0.862365f, 0.853766f, 0.844436f, 0.834459f, 0.823915f, 0.812876f, 0.801410f, 0.789581f, 0.777445f, 0.765057f, + 1.000000f, 0.999967f, 0.999442f, 0.996987f, 0.989925f, 0.975437f, 0.953654f, 0.929078f, 0.907414f, 0.891877f, 0.882635f, 0.878166f, 0.876572f, 0.876236f, 0.876004f, 0.875144f, 0.873238f, 0.870080f, 0.865601f, 0.859812f, 0.852774f, 0.844571f, 0.835302f, 0.825069f, 0.813976f, 0.802123f, 0.789609f, 0.776523f, 0.762954f, 0.748982f, 0.734682f, 0.720122f, + 1.000000f, 0.999979f, 0.999644f, 0.998096f, 0.993618f, 0.983950f, 0.967765f, 0.946488f, 0.923989f, 0.904160f, 0.889039f, 0.878704f, 0.872099f, 0.867839f, 0.864665f, 0.861611f, 0.858015f, 0.853468f, 0.847745f, 0.840752f, 0.832480f, 0.822973f, 0.812312f, 0.800592f, 0.787922f, 0.774411f, 0.760171f, 0.745308f, 0.729926f, 0.714121f, 0.697985f, 0.681600f, + 1.000000f, 0.999985f, 0.999752f, 0.998684f, 0.995603f, 0.988803f, 0.976727f, 0.959272f, 0.938451f, 0.917446f, 0.898932f, 0.884154f, 0.873043f, 0.864773f, 0.858278f, 0.852565f, 0.846845f, 0.840555f, 0.833331f, 0.824969f, 0.815378f, 0.804550f, 0.792533f, 0.779405f, 0.765271f, 0.750246f, 0.734447f, 0.717996f, 0.701008f, 0.683595f, 0.665862f, 0.647905f, + 1.000000f, 0.999989f, 0.999816f, 0.999032f, 0.996781f, 0.991766f, 0.982561f, 0.968421f, 0.950089f, 0.929705f, 0.909775f, 0.892112f, 0.877428f, 0.865535f, 0.855737f, 0.847185f, 0.839084f, 0.830796f, 0.821858f, 0.811969f, 0.800961f, 0.788766f, 0.775391f, 0.760894f, 0.745367f, 0.728923f, 0.711685f, 0.693783f, 0.675344f, 0.656491f, 0.637343f, 0.618009f, + 1.000000f, 0.999991f, 0.999858f, 0.999255f, 0.997533f, 0.993686f, 0.986490f, 0.974988f, 0.959173f, 0.940264f, 0.920251f, 0.901030f, 0.883794f, 0.868900f, 0.856078f, 0.844728f, 0.834154f, 0.823720f, 0.812914f, 0.801368f, 0.788846f, 0.775227f, 0.760476f, 0.744623f, 0.727744f, 0.709946f, 0.691355f, 0.672105f, 0.652332f, 0.632172f, 0.611753f, 0.591195f, + 1.000000f, 0.999993f, 0.999886f, 0.999406f, 0.998040f, 0.994992f, 0.989227f, 0.979769f, 0.966203f, 0.949069f, 0.929766f, 0.909990f, 0.891126f, 0.873921f, 0.858498f, 0.844545f, 0.831539f, 0.818909f, 0.806146f, 0.792847f, 0.778733f, 0.763633f, 0.747476f, 0.730264f, 0.712056f, 0.692949f, 0.673066f, 0.652547f, 0.631533f, 0.610170f, 0.588596f, 0.566939f, + 1.000000f, 0.999995f, 0.999906f, 0.999513f, 0.998399f, 0.995917f, 0.991195f, 0.983312f, 0.971656f, 0.956303f, 0.938125f, 0.918488f, 0.898757f, 0.879901f, 0.862353f, 0.846089f, 0.830787f, 0.815992f, 0.801242f, 0.786135f, 0.770368f, 0.753741f, 0.736147f, 0.717566f, 0.698037f, 0.677649f, 0.656520f, 0.634791f, 0.612611f, 0.590130f, 0.567495f, 0.544843f, + 1.000000f, 0.999996f, 0.999921f, 0.999591f, 0.998661f, 0.996594f, 0.992650f, 0.985988f, 0.975917f, 0.962217f, 0.945336f, 0.926280f, 0.906266f, 0.886338f, 0.867144f, 0.848905f, 0.831508f, 0.814643f, 0.797929f, 0.780995f, 0.763540f, 0.745347f, 0.726289f, 0.706324f, 0.685477f, 0.663824f, 0.641483f, 0.618591f, 0.595303f, 0.571774f, 0.548156f, 0.524596f, + 1.000000f, 0.999996f, 0.999933f, 0.999651f, 0.998859f, 0.997104f, 0.993752f, 0.988046f, 0.979280f, 0.967055f, 0.951498f, 0.933282f, 0.913407f, 0.892888f, 0.872490f, 0.852624f, 0.833371f, 0.814578f, 0.795964f, 0.777219f, 0.758062f, 0.738279f, 0.717734f, 0.696371f, 0.674202f, 0.651296f, 0.627765f, 0.603747f, 0.579398f, 0.554878f, 0.530346f, 0.505951f, + 1.000000f, 0.999997f, 0.999941f, 0.999696f, 0.999012f, 0.997497f, 0.994604f, 0.989656f, 0.981964f, 0.971026f, 0.956742f, 0.939495f, 0.920052f, 0.899322f, 0.878109f, 0.856955f, 0.836102f, 0.815549f, 0.795133f, 0.774620f, 0.753771f, 0.732389f, 0.710341f, 0.687567f, 0.664071f, 0.639918f, 0.615213f, 0.590097f, 0.564725f, 0.539263f, 0.513871f, 0.488706f, + 1.000000f, 0.999997f, 0.999949f, 0.999733f, 0.999132f, 0.997806f, 0.995276f, 0.990935f, 0.984129f, 0.974304f, 0.961200f, 0.944967f, 0.926144f, 0.905496f, 0.883799f, 0.861667f, 0.839472f, 0.817348f, 0.795251f, 0.773035f, 0.750522f, 0.727545f, 0.703988f, 0.679793f, 0.654965f, 0.629565f, 0.603699f, 0.577506f, 0.551143f, 0.524778f, 0.498576f, 0.472695f, + 1.000000f, 0.999997f, 0.999954f, 0.999762f, 0.999228f, 0.998053f, 0.995814f, 0.991966f, 0.985893f, 0.977026f, 0.964995f, 0.949768f, 0.931677f, 0.911324f, 0.889415f, 0.866586f, 0.843295f, 0.819794f, 0.796153f, 0.772321f, 0.748187f, 0.723632f, 0.698566f, 0.672945f, 0.646780f, 0.620134f, 0.593114f, 0.565860f, 0.538532f, 0.511298f, 0.484328f, 0.457779f, + 1.000000f, 0.999998f, 0.999959f, 0.999786f, 0.999307f, 0.998254f, 0.996252f, 0.992808f, 0.987348f, 0.979302f, 0.968235f, 0.953973f, 0.936669f, 0.916763f, 0.894859f, 0.871576f, 0.847421f, 0.822737f, 0.797698f, 0.772347f, 0.746651f, 0.720547f, 0.693982f, 0.666934f, 0.639428f, 0.611535f, 0.583366f, 0.555065f, 0.526792f, 0.498719f, 0.471015f, 0.443841f, + 1.000000f, 0.999998f, 0.999962f, 0.999805f, 0.999371f, 0.998420f, 0.996612f, 0.993502f, 0.988557f, 0.981218f, 0.971011f, 0.957656f, 0.941156f, 0.921798f, 0.900070f, 0.876539f, 0.851730f, 0.826051f, 0.799763f, 0.773002f, 0.745814f, 0.718199f, 0.690150f, 0.661679f, 0.632832f, 0.603691f, 0.574377f, 0.545037f, 0.515837f, 0.486949f, 0.458544f, 0.430781f, + 1.000000f, 0.999998f, 0.999966f, 0.999822f, 0.999425f, 0.998558f, 0.996912f, 0.994082f, 0.989572f, 0.982843f, 0.973398f, 0.960884f, 0.945180f, 0.926433f, 0.905008f, 0.881402f, 0.856128f, 0.829631f, 0.802244f, 0.774186f, 0.745583f, 0.716504f, 0.686997f, 0.657112f, 0.626924f, 0.596535f, 0.566077f, 0.535706f, 0.505592f, 0.475910f, 0.446831f, 0.418514f, + 1.000000f, 0.999998f, 0.999968f, 0.999836f, 0.999471f, 0.998674f, 0.997165f, 0.994570f, 0.990430f, 0.984229f, 0.975460f, 0.963718f, 0.948785f, 0.930682f, 0.909656f, 0.886116f, 0.860541f, 0.833390f, 0.805050f, 0.775811f, 0.745878f, 0.715390f, 0.684454f, 0.653169f, 0.621644f, 0.590007f, 0.558407f, 0.527011f, 0.495995f, 0.465536f, 0.435808f, 0.406965f, + 1.000000f, 0.999999f, 0.999970f, 0.999848f, 0.999509f, 0.998773f, 0.997379f, 0.994985f, 0.991163f, 0.985419f, 0.977249f, 0.966213f, 0.952014f, 0.934568f, 0.914006f, 0.890646f, 0.864912f, 0.837258f, 0.808105f, 0.777803f, 0.746627f, 0.714789f, 0.682460f, 0.649794f, 0.616939f, 0.584055f, 0.551314f, 0.518896f, 0.486987f, 0.455768f, 0.425410f, 0.396069f, + 1.000000f, 0.999999f, 0.999973f, 0.999858f, 0.999542f, 0.998857f, 0.997562f, 0.995341f, 0.991792f, 0.986447f, 0.978809f, 0.968414f, 0.954908f, 0.938115f, 0.918063f, 0.894970f, 0.869199f, 0.841178f, 0.811344f, 0.780093f, 0.747765f, 0.714642f, 0.680962f, 0.646935f, 0.612760f, 0.578633f, 0.544751f, 0.511315f, 0.478520f, 0.446553f, 0.415586f, 0.385770f, + 1.000000f, 0.999999f, 0.999974f, 0.999867f, 0.999571f, 0.998930f, 0.997720f, 0.995648f, 0.992336f, 0.987340f, 0.980174f, 0.970361f, 0.957504f, 0.941351f, 0.921833f, 0.899078f, 0.873371f, 0.845104f, 0.814712f, 0.782625f, 0.749237f, 0.714896f, 0.679909f, 0.644547f, 0.609064f, 0.573697f, 0.538677f, 0.504225f, 0.470550f, 0.437846f, 0.406286f, 0.376017f, + 1.000000f, 0.999999f, 0.999976f, 0.999874f, 0.999596f, 0.998993f, 0.997858f, 0.995914f, 0.992810f, 0.988121f, 0.981374f, 0.972090f, 0.959837f, 0.944301f, 0.925331f, 0.902963f, 0.877406f, 0.848999f, 0.818163f, 0.785347f, 0.750991f, 0.715502f, 0.679256f, 0.642589f, 0.605812f, 0.569211f, 0.533054f, 0.497587f, 0.463038f, 0.429607f, 0.397469f, 0.366766f, + 1.000000f, 0.999999f, 0.999977f, 0.999881f, 0.999618f, 0.999049f, 0.997978f, 0.996147f, 0.993224f, 0.988806f, 0.982434f, 0.973628f, 0.961935f, 0.946991f, 0.928572f, 0.906628f, 0.881288f, 0.852834f, 0.821659f, 0.788217f, 0.752981f, 0.716417f, 0.678962f, 0.641022f, 0.602968f, 0.565141f, 0.527849f, 0.491370f, 0.455949f, 0.421800f, 0.389096f, 0.357977f, + 1.000000f, 0.999999f, 0.999978f, 0.999887f, 0.999637f, 0.999097f, 0.998083f, 0.996352f, 0.993588f, 0.989410f, 0.983373f, 0.975002f, 0.963827f, 0.949446f, 0.931571f, 0.910076f, 0.885009f, 0.856589f, 0.825169f, 0.791196f, 0.755170f, 0.717601f, 0.678991f, 0.639812f, 0.600501f, 0.561455f, 0.523031f, 0.485541f, 0.449253f, 0.414392f, 0.381135f, 0.349616f, + 1.000000f, 0.999999f, 0.999979f, 0.999892f, 0.999655f, 0.999141f, 0.998177f, 0.996533f, 0.993910f, 0.989945f, 0.984209f, 0.976232f, 0.965536f, 0.951688f, 0.934346f, 0.913314f, 0.888564f, 0.860245f, 0.828665f, 0.794253f, 0.757521f, 0.719020f, 0.679309f, 0.638927f, 0.598380f, 0.558126f, 0.518574f, 0.480074f, 0.442922f, 0.407354f, 0.373554f, 0.341651f, + 1.000000f, 0.999999f, 0.999980f, 0.999897f, 0.999669f, 0.999179f, 0.998260f, 0.996693f, 0.994197f, 0.990422f, 0.984956f, 0.977337f, 0.967083f, 0.953737f, 0.936913f, 0.916351f, 0.891951f, 0.863792f, 0.832128f, 0.797360f, 0.760004f, 0.720642f, 0.679885f, 0.638338f, 0.596578f, 0.555128f, 0.514452f, 0.474944f, 0.436929f, 0.400661f, 0.366328f, 0.334053f, + 1.000000f, 0.999999f, 0.999981f, 0.999901f, 0.999683f, 0.999213f, 0.998334f, 0.996836f, 0.994452f, 0.990848f, 0.985625f, 0.978332f, 0.968486f, 0.955612f, 0.939288f, 0.919197f, 0.895172f, 0.867221f, 0.835539f, 0.800494f, 0.762592f, 0.722438f, 0.680691f, 0.638020f, 0.595071f, 0.552438f, 0.510643f, 0.470129f, 0.431253f, 0.394289f, 0.359430f, 0.326796f, + 1.000000f, 0.999999f, 0.999982f, 0.999905f, 0.999695f, 0.999244f, 0.998400f, 0.996965f, 0.994681f, 0.991230f, 0.986227f, 0.979231f, 0.969761f, 0.957330f, 0.941486f, 0.921863f, 0.898229f, 0.870526f, 0.838887f, 0.803634f, 0.765260f, 0.724383f, 0.681702f, 0.637948f, 0.593837f, 0.550034f, 0.507126f, 0.465607f, 0.425873f, 0.388216f, 0.352839f, 0.319858f, + 1.000000f, 0.999999f, 0.999982f, 0.999908f, 0.999706f, 0.999271f, 0.998459f, 0.997080f, 0.994886f, 0.991574f, 0.986770f, 0.980045f, 0.970922f, 0.958906f, 0.943521f, 0.924358f, 0.901128f, 0.873705f, 0.842159f, 0.806765f, 0.767988f, 0.726453f, 0.682895f, 0.638100f, 0.592854f, 0.547896f, 0.503881f, 0.461361f, 0.420769f, 0.382424f, 0.346535f, 0.313216f, + 1.000000f, 0.999999f, 0.999983f, 0.999911f, 0.999716f, 0.999296f, 0.998513f, 0.997184f, 0.995072f, 0.991884f, 0.987261f, 0.980785f, 0.971982f, 0.960355f, 0.945407f, 0.926694f, 0.903873f, 0.876756f, 0.845349f, 0.809871f, 0.770757f, 0.728630f, 0.684249f, 0.638454f, 0.592102f, 0.546006f, 0.500893f, 0.457373f, 0.415925f, 0.376893f, 0.340499f, 0.306853f +}; + +static const float table_ggx_Eavg[32] = { + 1.000000f, 0.999992f, 0.999897f, 0.999548f, 0.998729f, 0.997199f, 0.994703f, 0.990986f, 0.985805f, 0.978930f, 0.970160f, 0.959321f, 0.946279f, 0.930937f, 0.913247f, 0.893209f, 0.870874f, 0.846345f, 0.819774f, 0.791360f, 0.761345f, 0.730001f, 0.697631f, 0.664547f, 0.631068f, 0.597509f, 0.564165f, 0.531311f, 0.499191f, 0.468013f, 0.437950f, 0.409137f +}; + +static const float table_ggx_glass_E[4096] = { + 0.999985f, 1.000000f, 0.999989f, 0.999990f, 1.000000f, 0.999999f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + + 1.000000f, 0.995405f, 0.998159f, 0.997352f, 0.995556f, 0.993264f, 0.990673f, 0.987859f, 0.984857f, 0.981686f, 0.978366f, 0.974910f, 0.971336f, 0.967655f, 0.963881f, 0.960025f, + 1.000000f, 0.999037f, 0.984373f, 0.951223f, 0.908812f, 0.850714f, 0.787824f, 0.732387f, 0.688038f, 0.653736f, 0.627288f, 0.606724f, 0.590534f, 0.577604f, 0.567136f, 0.558556f, + 1.000000f, 0.999790f, 0.996491f, 0.983048f, 0.954803f, 0.911598f, 0.857483f, 0.801146f, 0.750002f, 0.707130f, 0.672506f, 0.644881f, 0.622845f, 0.605146f, 0.590797f, 0.579049f, + 1.000000f, 0.999901f, 0.998395f, 0.991953f, 0.976043f, 0.947847f, 0.907820f, 0.860180f, 0.811070f, 0.765424f, 0.725673f, 0.692262f, 0.664642f, 0.641911f, 0.623184f, 0.607670f, + 1.000000f, 0.999943f, 0.999081f, 0.995375f, 0.985803f, 0.967476f, 0.939094f, 0.901894f, 0.859442f, 0.816061f, 0.775183f, 0.738672f, 0.707095f, 0.680251f, 0.657599f, 0.638515f, + 1.000000f, 0.999964f, 0.999418f, 0.997064f, 0.990881f, 0.978596f, 0.958507f, 0.930339f, 0.895632f, 0.857261f, 0.818368f, 0.781421f, 0.747848f, 0.718200f, 0.692449f, 0.670282f, + 1.000000f, 0.999976f, 0.999609f, 0.998028f, 0.993836f, 0.985334f, 0.970961f, 0.949851f, 0.922317f, 0.889899f, 0.854891f, 0.819635f, 0.785941f, 0.754930f, 0.727098f, 0.702515f, + 1.000000f, 0.999983f, 0.999729f, 0.998628f, 0.995695f, 0.989681f, 0.979281f, 0.963516f, 0.942069f, 0.915536f, 0.885302f, 0.853191f, 0.820962f, 0.790000f, 0.761205f, 0.735019f, + 1.000000f, 0.999988f, 0.999807f, 0.999027f, 0.996943f, 0.992630f, 0.985061f, 0.973329f, 0.956860f, 0.935671f, 0.910431f, 0.882327f, 0.852785f, 0.823168f, 0.794564f, 0.767691f, + 1.000000f, 0.999992f, 0.999862f, 0.999306f, 0.997815f, 0.994714f, 0.989218f, 0.980549f, 0.968095f, 0.951578f, 0.931158f, 0.907462f, 0.881472f, 0.854302f, 0.827016f, 0.800477f, + 1.000000f, 0.999994f, 0.999903f, 0.999508f, 0.998451f, 0.996240f, 0.992293f, 0.985990f, 0.976770f, 0.964243f, 0.948276f, 0.929081f, 0.907187f, 0.883360f, 0.858467f, 0.833340f, + 1.000000f, 0.999996f, 0.999933f, 0.999659f, 0.998925f, 0.997388f, 0.994627f, 0.990177f, 0.983575f, 0.974422f, 0.962463f, 0.947642f, 0.930135f, 0.910340f, 0.888830f, 0.866259f, + 1.000000f, 0.999997f, 0.999956f, 0.999775f, 0.999292f, 0.998273f, 0.996437f, 0.993456f, 0.988984f, 0.982691f, 0.974287f, 0.963598f, 0.950566f, 0.935300f, 0.918059f, 0.899216f, + 1.000000f, 0.999998f, 0.999974f, 0.999866f, 0.999577f, 0.998969f, 0.997868f, 0.996070f, 0.993349f, 0.989468f, 0.984197f, 0.977335f, 0.968739f, 0.958323f, 0.946109f, 0.932199f, + 1.000000f, 0.999999f, 0.999988f, 0.999938f, 0.999806f, 0.999525f, 0.999015f, 0.998179f, 0.996906f, 0.995072f, 0.992543f, 0.989188f, 0.984877f, 0.979492f, 0.972944f, 0.965165f, + 1.000000f, 1.000000f, 0.999999f, 0.999995f, 0.999985f, 0.999964f, 0.999925f, 0.999860f, 0.999762f, 0.999618f, 0.999419f, 0.999153f, 0.998802f, 0.998352f, 0.997801f, 0.997112f, + + 1.000000f, 0.995388f, 0.998717f, 0.998982f, 0.998625f, 0.997974f, 0.997140f, 0.996182f, 0.995130f, 0.993999f, 0.992798f, 0.991533f, 0.990206f, 0.988822f, 0.987383f, 0.985894f, + 1.000000f, 0.998651f, 0.978192f, 0.943710f, 0.926163f, 0.904416f, 0.868343f, 0.824688f, 0.781400f, 0.742589f, 0.709377f, 0.681460f, 0.658110f, 0.638518f, 0.622000f, 0.607981f, + 1.000000f, 0.999773f, 0.995969f, 0.981116f, 0.957538f, 0.930096f, 0.894925f, 0.851684f, 0.805599f, 0.761916f, 0.723411f, 0.690729f, 0.663465f, 0.640826f, 0.622007f, 0.606292f, + 1.000000f, 0.999911f, 0.998475f, 0.992107f, 0.977460f, 0.954862f, 0.924548f, 0.886566f, 0.843561f, 0.799865f, 0.759023f, 0.722868f, 0.691844f, 0.665632f, 0.643614f, 0.625119f, + 1.000000f, 0.999950f, 0.999175f, 0.995723f, 0.986844f, 0.970734f, 0.946942f, 0.915586f, 0.878129f, 0.837559f, 0.797224f, 0.759605f, 0.726013f, 0.696786f, 0.671701f, 0.650322f, + 1.000000f, 0.999968f, 0.999475f, 0.997315f, 0.991570f, 0.980337f, 0.962445f, 0.937545f, 0.906282f, 0.870486f, 0.832776f, 0.795698f, 0.761069f, 0.729848f, 0.702311f, 0.678351f, + 1.000000f, 0.999979f, 0.999643f, 0.998177f, 0.994255f, 0.986313f, 0.973041f, 0.953715f, 0.928347f, 0.897880f, 0.864109f, 0.829178f, 0.795033f, 0.763020f, 0.733880f, 0.707879f, + 1.000000f, 0.999985f, 0.999746f, 0.998712f, 0.995937f, 0.990229f, 0.980411f, 0.965602f, 0.945430f, 0.920208f, 0.890979f, 0.859337f, 0.826964f, 0.795377f, 0.765624f, 0.738299f, + 1.000000f, 0.999989f, 0.999817f, 0.999073f, 0.997075f, 0.992926f, 0.985659f, 0.974419f, 0.958652f, 0.938260f, 0.913723f, 0.886014f, 0.856456f, 0.826428f, 0.797093f, 0.769282f, + 1.000000f, 0.999991f, 0.999868f, 0.999329f, 0.997882f, 0.994860f, 0.989503f, 0.981072f, 0.968962f, 0.952856f, 0.932834f, 0.909386f, 0.883374f, 0.855884f, 0.828001f, 0.800646f, + 1.000000f, 0.999994f, 0.999905f, 0.999517f, 0.998476f, 0.996291f, 0.992395f, 0.986168f, 0.977075f, 0.964700f, 0.948872f, 0.929742f, 0.907742f, 0.883594f, 0.858150f, 0.832280f, + 1.000000f, 0.999996f, 0.999933f, 0.999660f, 0.998926f, 0.997385f, 0.994618f, 0.990151f, 0.983532f, 0.974353f, 0.962345f, 0.947409f, 0.929670f, 0.909496f, 0.887408f, 0.864093f, + 1.000000f, 0.999997f, 0.999955f, 0.999771f, 0.999277f, 0.998237f, 0.996357f, 0.993308f, 0.988723f, 0.982284f, 0.973688f, 0.962731f, 0.949336f, 0.933578f, 0.915681f, 0.896025f, + 1.000000f, 0.999998f, 0.999973f, 0.999859f, 0.999554f, 0.998910f, 0.997742f, 0.995841f, 0.992953f, 0.988845f, 0.983268f, 0.976012f, 0.966908f, 0.955859f, 0.942858f, 0.927996f, + 1.000000f, 0.999999f, 0.999986f, 0.999929f, 0.999774f, 0.999452f, 0.998859f, 0.997892f, 0.996414f, 0.994288f, 0.991361f, 0.987491f, 0.982523f, 0.976329f, 0.968792f, 0.959831f, + 1.000000f, 1.000000f, 0.999997f, 0.999982f, 0.999942f, 0.999857f, 0.999704f, 0.999448f, 0.999060f, 0.998493f, 0.997714f, 0.996670f, 0.995320f, 0.993613f, 0.991499f, 0.988921f, + + 1.000000f, 0.995365f, 0.998801f, 0.999276f, 0.999227f, 0.998963f, 0.998568f, 0.998082f, 0.997529f, 0.996923f, 0.996273f, 0.995583f, 0.994856f, 0.994093f, 0.993298f, 0.992470f, + 1.000000f, 0.998400f, 0.974244f, 0.935839f, 0.925457f, 0.920630f, 0.903983f, 0.875865f, 0.841964f, 0.807196f, 0.774375f, 0.744706f, 0.718426f, 0.695348f, 0.675129f, 0.657387f, + 1.000000f, 0.999729f, 0.995093f, 0.977435f, 0.953654f, 0.934130f, 0.912830f, 0.883507f, 0.847141f, 0.808095f, 0.770242f, 0.735737f, 0.705344f, 0.679048f, 0.656456f, 0.637080f, + 1.000000f, 0.999904f, 0.998303f, 0.991076f, 0.975623f, 0.955620f, 0.932714f, 0.904383f, 0.869703f, 0.831042f, 0.791868f, 0.754930f, 0.721663f, 0.692511f, 0.667329f, 0.645711f, + 1.000000f, 0.999950f, 0.999166f, 0.995545f, 0.986347f, 0.971067f, 0.950765f, 0.925206f, 0.893847f, 0.857809f, 0.819700f, 0.782222f, 0.747305f, 0.715920f, 0.688322f, 0.664353f, + 1.000000f, 0.999970f, 0.999497f, 0.997349f, 0.991580f, 0.980677f, 0.964385f, 0.942677f, 0.915420f, 0.883167f, 0.847684f, 0.811270f, 0.776018f, 0.743303f, 0.713816f, 0.687720f, + 1.000000f, 0.999979f, 0.999662f, 0.998244f, 0.994377f, 0.986622f, 0.974078f, 0.956417f, 0.933464f, 0.905495f, 0.873578f, 0.839486f, 0.805137f, 0.772120f, 0.741468f, 0.713698f, + 1.000000f, 0.999985f, 0.999760f, 0.998765f, 0.996051f, 0.990449f, 0.980961f, 0.966960f, 0.948125f, 0.924486f, 0.896610f, 0.865696f, 0.833324f, 0.801053f, 0.770094f, 0.741288f, + 1.000000f, 0.999989f, 0.999825f, 0.999106f, 0.997145f, 0.993050f, 0.985914f, 0.975021f, 0.959903f, 0.940392f, 0.916674f, 0.889467f, 0.859911f, 0.829349f, 0.799017f, 0.769914f, + 1.000000f, 0.999992f, 0.999871f, 0.999343f, 0.997913f, 0.994898f, 0.989563f, 0.981215f, 0.969336f, 0.953599f, 0.933946f, 0.910703f, 0.884586f, 0.856581f, 0.827793f, 0.799252f, + 1.000000f, 0.999994f, 0.999905f, 0.999520f, 0.998473f, 0.996269f, 0.992322f, 0.986046f, 0.976919f, 0.964556f, 0.948744f, 0.929525f, 0.907225f, 0.882483f, 0.856137f, 0.829089f, + 1.000000f, 0.999996f, 0.999932f, 0.999655f, 0.998905f, 0.997315f, 0.994456f, 0.989845f, 0.983045f, 0.973644f, 0.961379f, 0.946083f, 0.927839f, 0.906910f, 0.883827f, 0.859263f, + 1.000000f, 0.999997f, 0.999953f, 0.999760f, 0.999238f, 0.998136f, 0.996141f, 0.992892f, 0.988035f, 0.981227f, 0.972155f, 0.960609f, 0.946489f, 0.929771f, 0.910717f, 0.889658f, + 1.000000f, 0.999998f, 0.999970f, 0.999844f, 0.999505f, 0.998789f, 0.997485f, 0.995350f, 0.992123f, 0.987537f, 0.981342f, 0.973304f, 0.963244f, 0.951027f, 0.936610f, 0.920084f, + 1.000000f, 0.999999f, 0.999983f, 0.999911f, 0.999717f, 0.999310f, 0.998567f, 0.997335f, 0.995468f, 0.992786f, 0.989111f, 0.984278f, 0.978116f, 0.970461f, 0.961172f, 0.950156f, + 1.000000f, 1.000000f, 0.999992f, 0.999961f, 0.999873f, 0.999687f, 0.999348f, 0.998783f, 0.997916f, 0.996657f, 0.994936f, 0.992649f, 0.989728f, 0.986067f, 0.981571f, 0.976141f, + + 1.000000f, 0.995351f, 0.998825f, 0.999374f, 0.999438f, 0.999320f, 0.999098f, 0.998806f, 0.998460f, 0.998073f, 0.997651f, 0.997201f, 0.996723f, 0.996222f, 0.995696f, 0.995148f, + 1.000000f, 0.998247f, 0.971853f, 0.930499f, 0.922466f, 0.925445f, 0.919781f, 0.902821f, 0.877948f, 0.849240f, 0.819764f, 0.791363f, 0.764922f, 0.740764f, 0.718887f, 0.699161f, + 1.000000f, 0.999691f, 0.994374f, 0.974344f, 0.949194f, 0.933147f, 0.920047f, 0.900903f, 0.873664f, 0.840927f, 0.806286f, 0.772525f, 0.741186f, 0.712937f, 0.687847f, 0.665746f, + 1.000000f, 0.999891f, 0.998077f, 0.989841f, 0.972944f, 0.953646f, 0.935232f, 0.914098f, 0.886967f, 0.854149f, 0.818325f, 0.782378f, 0.748372f, 0.717379f, 0.689780f, 0.665505f, + 1.000000f, 0.999948f, 0.999095f, 0.995105f, 0.985120f, 0.969684f, 0.951429f, 0.930275f, 0.904363f, 0.873183f, 0.838235f, 0.801991f, 0.766711f, 0.733862f, 0.704162f, 0.677798f, + 1.000000f, 0.999969f, 0.999481f, 0.997211f, 0.991093f, 0.979948f, 0.964446f, 0.945167f, 0.921457f, 0.892837f, 0.860035f, 0.824915f, 0.789586f, 0.755768f, 0.724509f, 0.696306f, + 1.000000f, 0.999980f, 0.999662f, 0.998216f, 0.994213f, 0.986278f, 0.973997f, 0.957520f, 0.936668f, 0.911128f, 0.881257f, 0.848288f, 0.814019f, 0.780159f, 0.748034f, 0.718404f, + 1.000000f, 0.999986f, 0.999763f, 0.998768f, 0.996003f, 0.990290f, 0.980821f, 0.967303f, 0.949566f, 0.927380f, 0.900854f, 0.870765f, 0.838439f, 0.805471f, 0.773240f, 0.742756f, + 1.000000f, 0.999990f, 0.999828f, 0.999112f, 0.997132f, 0.992951f, 0.985733f, 0.974930f, 0.960250f, 0.941434f, 0.918449f, 0.891675f, 0.862029f, 0.830797f, 0.799266f, 0.768611f, + 1.000000f, 0.999992f, 0.999874f, 0.999345f, 0.997890f, 0.994798f, 0.989332f, 0.980869f, 0.969008f, 0.953434f, 0.933980f, 0.910769f, 0.884320f, 0.855554f, 0.825575f, 0.795502f, + 1.000000f, 0.999994f, 0.999906f, 0.999513f, 0.998440f, 0.996149f, 0.992040f, 0.985528f, 0.976163f, 0.963589f, 0.947551f, 0.927984f, 0.905085f, 0.879413f, 0.851774f, 0.823130f, + 1.000000f, 0.999996f, 0.999930f, 0.999641f, 0.998853f, 0.997173f, 0.994130f, 0.989225f, 0.982030f, 0.972164f, 0.959346f, 0.943372f, 0.924226f, 0.902133f, 0.877591f, 0.851276f, + 1.000000f, 0.999997f, 0.999949f, 0.999742f, 0.999176f, 0.997970f, 0.995769f, 0.992189f, 0.986844f, 0.979388f, 0.969535f, 0.957031f, 0.941711f, 0.923565f, 0.902781f, 0.879717f, + 1.000000f, 0.999998f, 0.999966f, 0.999823f, 0.999435f, 0.998604f, 0.997084f, 0.994588f, 0.990810f, 0.985469f, 0.978302f, 0.969050f, 0.957516f, 0.943553f, 0.927085f, 0.908201f, + 1.000000f, 0.999999f, 0.999977f, 0.999887f, 0.999639f, 0.999111f, 0.998133f, 0.996516f, 0.994047f, 0.990516f, 0.985714f, 0.979460f, 0.971538f, 0.961773f, 0.950012f, 0.936120f, + 1.000000f, 0.999999f, 0.999987f, 0.999932f, 0.999781f, 0.999458f, 0.998865f, 0.997872f, 0.996341f, 0.994130f, 0.991100f, 0.987136f, 0.982102f, 0.975874f, 0.968306f, 0.959261f, + + 1.000000f, 0.995343f, 0.998834f, 0.999417f, 0.999534f, 0.999486f, 0.999351f, 0.999156f, 0.998917f, 0.998643f, 0.998341f, 0.998014f, 0.997667f, 0.997300f, 0.996916f, 0.996514f, + 1.000000f, 0.998152f, 0.970350f, 0.926992f, 0.919810f, 0.926744f, 0.927339f, 0.917618f, 0.899592f, 0.876390f, 0.850767f, 0.824690f, 0.799364f, 0.775412f, 0.753093f, 0.732480f, + 1.000000f, 0.999662f, 0.993854f, 0.972077f, 0.945526f, 0.931029f, 0.922665f, 0.910276f, 0.890044f, 0.863129f, 0.832392f, 0.800590f, 0.769662f, 0.740698f, 0.714184f, 0.690214f, + 1.000000f, 0.999881f, 0.997877f, 0.988770f, 0.970473f, 0.951066f, 0.935189f, 0.918918f, 0.897606f, 0.870055f, 0.837934f, 0.803874f, 0.770140f, 0.738260f, 0.709006f, 0.682637f, + 1.000000f, 0.999944f, 0.999017f, 0.994627f, 0.983760f, 0.967743f, 0.950500f, 0.932327f, 0.910645f, 0.883712f, 0.852009f, 0.817534f, 0.782559f, 0.748862f, 0.717541f, 0.689106f, + 1.000000f, 0.999967f, 0.999451f, 0.997009f, 0.990405f, 0.978715f, 0.963443f, 0.945744f, 0.924775f, 0.899237f, 0.869030f, 0.835420f, 0.800394f, 0.765814f, 0.733053f, 0.702884f, + 1.000000f, 0.999979f, 0.999652f, 0.998128f, 0.993877f, 0.985555f, 0.973154f, 0.957354f, 0.938058f, 0.914542f, 0.886497f, 0.854660f, 0.820578f, 0.786015f, 0.752477f, 0.720993f, + 1.000000f, 0.999985f, 0.999760f, 0.998732f, 0.995835f, 0.989850f, 0.980146f, 0.966771f, 0.949739f, 0.928657f, 0.903252f, 0.873820f, 0.841491f, 0.807763f, 0.774164f, 0.741895f, + 1.000000f, 0.999990f, 0.999826f, 0.999093f, 0.997027f, 0.992657f, 0.985168f, 0.974212f, 0.959656f, 0.941256f, 0.918706f, 0.892130f, 0.862190f, 0.830060f, 0.797147f, 0.764696f, + 1.000000f, 0.999992f, 0.999870f, 0.999328f, 0.997815f, 0.994567f, 0.988825f, 0.980053f, 0.967938f, 0.952246f, 0.932681f, 0.909189f, 0.882118f, 0.852259f, 0.820769f, 0.788851f, + 1.000000f, 0.999994f, 0.999903f, 0.999496f, 0.998369f, 0.995932f, 0.991547f, 0.984629f, 0.974796f, 0.961723f, 0.945138f, 0.924851f, 0.900967f, 0.873946f, 0.844593f, 0.813961f, + 1.000000f, 0.999995f, 0.999928f, 0.999621f, 0.998775f, 0.996954f, 0.993626f, 0.988273f, 0.980454f, 0.969838f, 0.956104f, 0.939056f, 0.918565f, 0.894820f, 0.868295f, 0.839747f, + 1.000000f, 0.999997f, 0.999945f, 0.999718f, 0.999092f, 0.997740f, 0.995253f, 0.991184f, 0.985131f, 0.976743f, 0.965717f, 0.951804f, 0.934809f, 0.914653f, 0.891571f, 0.865936f, + 1.000000f, 0.999997f, 0.999960f, 0.999794f, 0.999339f, 0.998357f, 0.996540f, 0.993539f, 0.988990f, 0.982587f, 0.974059f, 0.963136f, 0.949594f, 0.933262f, 0.914088f, 0.892194f, + 1.000000f, 0.999998f, 0.999971f, 0.999855f, 0.999537f, 0.998843f, 0.997560f, 0.995425f, 0.992140f, 0.987444f, 0.981109f, 0.972937f, 0.962686f, 0.950191f, 0.935263f, 0.917776f, + 1.000000f, 0.999999f, 0.999980f, 0.999897f, 0.999669f, 0.999176f, 0.998257f, 0.996711f, 0.994312f, 0.990857f, 0.986147f, 0.980028f, 0.972349f, 0.962984f, 0.951747f, 0.938446f, + + 1.000000f, 0.995338f, 0.998838f, 0.999440f, 0.999586f, 0.999577f, 0.999490f, 0.999351f, 0.999175f, 0.998968f, 0.998736f, 0.998484f, 0.998214f, 0.997928f, 0.997626f, 0.997311f, + 1.000000f, 0.998092f, 0.969422f, 0.924749f, 0.917886f, 0.926986f, 0.931290f, 0.926250f, 0.913085f, 0.894264f, 0.872124f, 0.848514f, 0.824720f, 0.801539f, 0.779408f, 0.758534f, + 1.000000f, 0.999643f, 0.993497f, 0.970499f, 0.942854f, 0.929021f, 0.923442f, 0.915421f, 0.900249f, 0.878008f, 0.850911f, 0.821420f, 0.791524f, 0.762584f, 0.735343f, 0.710141f, + 1.000000f, 0.999872f, 0.997720f, 0.987944f, 0.968504f, 0.948723f, 0.934249f, 0.921133f, 0.903975f, 0.880621f, 0.851861f, 0.819891f, 0.786954f, 0.754774f, 0.724418f, 0.696424f, + 1.000000f, 0.999941f, 0.998942f, 0.994201f, 0.982545f, 0.965851f, 0.949003f, 0.932731f, 0.914054f, 0.890431f, 0.861560f, 0.828880f, 0.794502f, 0.760357f, 0.727794f, 0.697582f, + 1.000000f, 0.999966f, 0.999415f, 0.996792f, 0.989702f, 0.977385f, 0.961984f, 0.945192f, 0.926129f, 0.902953f, 0.874868f, 0.842631f, 0.807991f, 0.772842f, 0.738772f, 0.706761f, + 1.000000f, 0.999978f, 0.999635f, 0.998018f, 0.993472f, 0.984659f, 0.971907f, 0.956353f, 0.938049f, 0.915975f, 0.889331f, 0.858374f, 0.824386f, 0.789120f, 0.754188f, 0.720854f, + 1.000000f, 0.999985f, 0.999751f, 0.998669f, 0.995592f, 0.989245f, 0.979123f, 0.965596f, 0.948856f, 0.928433f, 0.903711f, 0.874633f, 0.842050f, 0.807429f, 0.772336f, 0.738157f, + 1.000000f, 0.999990f, 0.999820f, 0.999051f, 0.996866f, 0.992215f, 0.984304f, 0.972966f, 0.958226f, 0.939838f, 0.917349f, 0.890568f, 0.859995f, 0.826715f, 0.792153f, 0.757701f, + 1.000000f, 0.999992f, 0.999867f, 0.999298f, 0.997691f, 0.994215f, 0.988063f, 0.978772f, 0.966154f, 0.949994f, 0.929930f, 0.905745f, 0.877620f, 0.846305f, 0.812937f, 0.778847f, + 1.000000f, 0.999994f, 0.999899f, 0.999469f, 0.998258f, 0.995624f, 0.990838f, 0.983336f, 0.972760f, 0.958874f, 0.941336f, 0.919894f, 0.894559f, 0.865712f, 0.834213f, 0.801176f, + 1.000000f, 0.999995f, 0.999922f, 0.999592f, 0.998670f, 0.996654f, 0.992943f, 0.986954f, 0.978268f, 0.966560f, 0.951539f, 0.932919f, 0.910556f, 0.884624f, 0.855596f, 0.824331f, + 1.000000f, 0.999997f, 0.999939f, 0.999685f, 0.998980f, 0.997439f, 0.994566f, 0.989850f, 0.982832f, 0.973172f, 0.960564f, 0.944737f, 0.925481f, 0.902756f, 0.876764f, 0.848011f, + 1.000000f, 0.999997f, 0.999953f, 0.999760f, 0.999222f, 0.998042f, 0.995847f, 0.992171f, 0.986606f, 0.978789f, 0.968444f, 0.955311f, 0.939175f, 0.919856f, 0.897362f, 0.871839f, + 1.000000f, 0.999998f, 0.999965f, 0.999817f, 0.999412f, 0.998518f, 0.996844f, 0.994017f, 0.989671f, 0.983465f, 0.975149f, 0.964496f, 0.951323f, 0.935445f, 0.916701f, 0.895043f, + 1.000000f, 0.999998f, 0.999973f, 0.999857f, 0.999535f, 0.998835f, 0.997511f, 0.995268f, 0.991772f, 0.986725f, 0.979890f, 0.971099f, 0.960227f, 0.947129f, 0.931637f, 0.913594f, + + 1.000000f, 0.995335f, 0.998841f, 0.999454f, 0.999617f, 0.999633f, 0.999575f, 0.999472f, 0.999335f, 0.999171f, 0.998985f, 0.998781f, 0.998561f, 0.998327f, 0.998080f, 0.997821f, + 1.000000f, 0.998057f, 0.968893f, 0.923459f, 0.916722f, 0.927045f, 0.933608f, 0.931619f, 0.921879f, 0.906373f, 0.887096f, 0.865718f, 0.843494f, 0.821270f, 0.799603f, 0.778777f, + 1.000000f, 0.999630f, 0.993270f, 0.969511f, 0.941118f, 0.927569f, 0.923625f, 0.918415f, 0.906730f, 0.888060f, 0.863984f, 0.836655f, 0.807988f, 0.779413f, 0.751852f, 0.725815f, + 1.000000f, 0.999866f, 0.997609f, 0.987360f, 0.967111f, 0.946922f, 0.933184f, 0.922045f, 0.907742f, 0.887488f, 0.861456f, 0.831398f, 0.799368f, 0.767173f, 0.736051f, 0.706747f, + 1.000000f, 0.999936f, 0.998884f, 0.993871f, 0.981590f, 0.964266f, 0.947497f, 0.932325f, 0.915646f, 0.894410f, 0.867724f, 0.836543f, 0.802774f, 0.768338f, 0.734726f, 0.702937f, + 1.000000f, 0.999964f, 0.999381f, 0.996594f, 0.989068f, 0.976145f, 0.960438f, 0.944059f, 0.926151f, 0.904562f, 0.877990f, 0.846777f, 0.812393f, 0.776702f, 0.741371f, 0.707616f, + 1.000000f, 0.999977f, 0.999616f, 0.997896f, 0.993058f, 0.983726f, 0.970492f, 0.954856f, 0.937005f, 0.915755f, 0.889934f, 0.859457f, 0.825319f, 0.789215f, 0.752845f, 0.717588f, + 1.000000f, 0.999984f, 0.999738f, 0.998590f, 0.995306f, 0.988536f, 0.977873f, 0.963933f, 0.947112f, 0.926849f, 0.902275f, 0.873099f, 0.839926f, 0.804143f, 0.767380f, 0.731136f, + 1.000000f, 0.999989f, 0.999812f, 0.998996f, 0.996656f, 0.991651f, 0.983203f, 0.971253f, 0.956000f, 0.937219f, 0.914295f, 0.886837f, 0.855208f, 0.820400f, 0.783895f, 0.747196f, + 1.000000f, 0.999992f, 0.999859f, 0.999254f, 0.997520f, 0.993744f, 0.987064f, 0.977043f, 0.963617f, 0.946599f, 0.925582f, 0.900200f, 0.870532f, 0.837295f, 0.801669f, 0.765094f, + 1.000000f, 0.999994f, 0.999891f, 0.999426f, 0.998108f, 0.995200f, 0.989896f, 0.981609f, 0.970024f, 0.954912f, 0.935970f, 0.912863f, 0.885512f, 0.854314f, 0.820197f, 0.784360f, + 1.000000f, 0.999995f, 0.999914f, 0.999553f, 0.998523f, 0.996252f, 0.992040f, 0.985224f, 0.975379f, 0.962194f, 0.945386f, 0.924662f, 0.899836f, 0.871115f, 0.839063f, 0.804620f, + 1.000000f, 0.999997f, 0.999931f, 0.999645f, 0.998833f, 0.997041f, 0.993672f, 0.988105f, 0.979841f, 0.968489f, 0.953793f, 0.935483f, 0.913352f, 0.887395f, 0.857937f, 0.825571f, + 1.000000f, 0.999996f, 0.999946f, 0.999716f, 0.999075f, 0.997647f, 0.994947f, 0.990417f, 0.983533f, 0.973887f, 0.961201f, 0.945264f, 0.925853f, 0.902884f, 0.876431f, 0.846788f, + 1.000000f, 0.999997f, 0.999957f, 0.999772f, 0.999256f, 0.998115f, 0.995939f, 0.992236f, 0.986522f, 0.978386f, 0.967529f, 0.953795f, 0.937007f, 0.917074f, 0.893916f, 0.867565f, + 1.000000f, 0.999998f, 0.999963f, 0.999808f, 0.999376f, 0.998420f, 0.996599f, 0.993479f, 0.988597f, 0.981542f, 0.972038f, 0.959955f, 0.945226f, 0.927773f, 0.907511f, 0.884305f, + + 1.000000f, 0.995335f, 0.998844f, 0.999465f, 0.999639f, 0.999669f, 0.999632f, 0.999552f, 0.999442f, 0.999308f, 0.999153f, 0.998983f, 0.998797f, 0.998600f, 0.998390f, 0.998171f, + 1.000000f, 0.998044f, 0.968696f, 0.922973f, 0.916296f, 0.927294f, 0.935224f, 0.935229f, 0.927867f, 0.914821f, 0.897813f, 0.878318f, 0.857513f, 0.836257f, 0.815119f, 0.794485f, + 1.000000f, 0.999624f, 0.993156f, 0.969020f, 0.940235f, 0.926824f, 0.923789f, 0.920324f, 0.911013f, 0.894903f, 0.873185f, 0.847683f, 0.820176f, 0.792074f, 0.764380f, 0.737725f, + 1.000000f, 0.999862f, 0.997543f, 0.987009f, 0.966250f, 0.945776f, 0.932390f, 0.922391f, 0.909912f, 0.891815f, 0.867819f, 0.839273f, 0.808062f, 0.775915f, 0.744179f, 0.713729f, + 1.000000f, 0.999934f, 0.998840f, 0.993630f, 0.980895f, 0.963078f, 0.946202f, 0.931596f, 0.916075f, 0.896373f, 0.871175f, 0.841070f, 0.807718f, 0.772954f, 0.738364f, 0.705076f, + 1.000000f, 0.999963f, 0.999351f, 0.996429f, 0.988543f, 0.975067f, 0.958965f, 0.942618f, 0.925261f, 0.904521f, 0.878830f, 0.848156f, 0.813742f, 0.777356f, 0.740733f, 0.705209f, + 1.000000f, 0.999976f, 0.999593f, 0.997779f, 0.992648f, 0.982804f, 0.969002f, 0.953011f, 0.935135f, 0.914113f, 0.888522f, 0.857980f, 0.823355f, 0.786161f, 0.748188f, 0.710935f, + 1.000000f, 0.999983f, 0.999725f, 0.998500f, 0.994983f, 0.987753f, 0.976443f, 0.961866f, 0.944536f, 0.923912f, 0.898955f, 0.869139f, 0.834944f, 0.797666f, 0.758979f, 0.720489f, + 1.000000f, 0.999988f, 0.999800f, 0.998925f, 0.996398f, 0.990976f, 0.981847f, 0.969068f, 0.952950f, 0.933279f, 0.909384f, 0.880743f, 0.847536f, 0.810789f, 0.772008f, 0.732801f, + 1.000000f, 0.999991f, 0.999848f, 0.999191f, 0.997295f, 0.993140f, 0.985784f, 0.974812f, 0.960228f, 0.941901f, 0.919390f, 0.892251f, 0.860487f, 0.824834f, 0.786546f, 0.747163f, + 1.000000f, 0.999993f, 0.999881f, 0.999369f, 0.997902f, 0.994643f, 0.988678f, 0.979359f, 0.966399f, 0.949633f, 0.928731f, 0.903335f, 0.873372f, 0.839281f, 0.802053f, 0.763068f, + 1.000000f, 0.999994f, 0.999905f, 0.999496f, 0.998329f, 0.995725f, 0.990852f, 0.982969f, 0.971599f, 0.956461f, 0.937293f, 0.913808f, 0.885894f, 0.853766f, 0.818146f, 0.780156f, + 1.000000f, 0.999996f, 0.999921f, 0.999590f, 0.998646f, 0.996528f, 0.992521f, 0.985848f, 0.975946f, 0.962425f, 0.945039f, 0.923544f, 0.897845f, 0.868008f, 0.834488f, 0.798085f, + 1.000000f, 0.999996f, 0.999934f, 0.999659f, 0.998882f, 0.997141f, 0.993801f, 0.988155f, 0.979569f, 0.967566f, 0.951911f, 0.932421f, 0.909015f, 0.881690f, 0.850699f, 0.816519f, + 1.000000f, 0.999996f, 0.999945f, 0.999714f, 0.999066f, 0.997605f, 0.994799f, 0.989987f, 0.982516f, 0.971896f, 0.957849f, 0.940259f, 0.919094f, 0.894392f, 0.866221f, 0.834798f, + 1.000000f, 0.999997f, 0.999952f, 0.999750f, 0.999181f, 0.997914f, 0.995465f, 0.991237f, 0.984588f, 0.974987f, 0.962151f, 0.946012f, 0.926653f, 0.904147f, 0.878556f, 0.849884f, + + 1.000000f, 0.995337f, 0.998849f, 0.999474f, 0.999655f, 0.999697f, 0.999673f, 0.999609f, 0.999518f, 0.999405f, 0.999274f, 0.999128f, 0.998968f, 0.998797f, 0.998615f, 0.998423f, + 1.000000f, 0.998052f, 0.968822f, 0.923265f, 0.916662f, 0.927944f, 0.936637f, 0.937891f, 0.932151f, 0.920891f, 0.905625f, 0.887660f, 0.868061f, 0.847666f, 0.827052f, 0.806635f, + 1.000000f, 0.999623f, 0.993153f, 0.969006f, 0.940211f, 0.926863f, 0.924254f, 0.921762f, 0.913922f, 0.899581f, 0.879602f, 0.855532f, 0.828968f, 0.801287f, 0.773504f, 0.746324f, + 1.000000f, 0.999860f, 0.997516f, 0.986877f, 0.965924f, 0.945296f, 0.932018f, 0.922554f, 0.911097f, 0.894339f, 0.871706f, 0.844219f, 0.813562f, 0.781384f, 0.749046f, 0.717517f, + 1.000000f, 0.999932f, 0.998811f, 0.993481f, 0.980459f, 0.962295f, 0.945210f, 0.930718f, 0.915703f, 0.896784f, 0.872406f, 0.842881f, 0.809626f, 0.774388f, 0.738759f, 0.703967f, + 1.000000f, 0.999962f, 0.999327f, 0.996291f, 0.988107f, 0.974159f, 0.957580f, 0.940962f, 0.923592f, 0.903062f, 0.877585f, 0.846930f, 0.812107f, 0.774804f, 0.736746f, 0.699373f, + 1.000000f, 0.999975f, 0.999571f, 0.997657f, 0.992255f, 0.981883f, 0.967421f, 0.950799f, 0.932444f, 0.911052f, 0.885074f, 0.853957f, 0.818370f, 0.779796f, 0.740007f, 0.700593f, + 1.000000f, 0.999982f, 0.999706f, 0.998397f, 0.994632f, 0.986872f, 0.974779f, 0.959300f, 0.941070f, 0.919535f, 0.893583f, 0.862567f, 0.826849f, 0.787697f, 0.746802f, 0.705863f, + 1.000000f, 0.999987f, 0.999782f, 0.998834f, 0.996072f, 0.990154f, 0.980185f, 0.966294f, 0.948893f, 0.927835f, 0.902369f, 0.871911f, 0.836607f, 0.797476f, 0.756062f, 0.714084f, + 1.000000f, 0.999990f, 0.999833f, 0.999109f, 0.997003f, 0.992369f, 0.984152f, 0.971915f, 0.955755f, 0.935592f, 0.910961f, 0.881426f, 0.846974f, 0.808391f, 0.767037f, 0.724539f, + 1.000000f, 0.999992f, 0.999867f, 0.999292f, 0.997631f, 0.993915f, 0.987083f, 0.976413f, 0.961637f, 0.942644f, 0.919132f, 0.890789f, 0.857552f, 0.819982f, 0.779213f, 0.736731f, + 1.000000f, 0.999994f, 0.999891f, 0.999423f, 0.998071f, 0.995029f, 0.989302f, 0.980012f, 0.966642f, 0.948946f, 0.926737f, 0.899769f, 0.868025f, 0.831862f, 0.792195f, 0.750277f, + 1.000000f, 0.999995f, 0.999908f, 0.999518f, 0.998395f, 0.995854f, 0.990995f, 0.982894f, 0.970873f, 0.954534f, 0.933692f, 0.908243f, 0.878166f, 0.843771f, 0.805670f, 0.764892f, + 1.000000f, 0.999996f, 0.999922f, 0.999589f, 0.998635f, 0.996480f, 0.992312f, 0.985223f, 0.974419f, 0.959410f, 0.939975f, 0.916084f, 0.887813f, 0.855398f, 0.819314f, 0.780252f, + 1.000000f, 0.999996f, 0.999932f, 0.999642f, 0.998819f, 0.996953f, 0.993329f, 0.987079f, 0.977358f, 0.963575f, 0.945473f, 0.923115f, 0.896667f, 0.866416f, 0.832654f, 0.795872f, + 1.000000f, 0.999996f, 0.999938f, 0.999679f, 0.998940f, 0.997276f, 0.994034f, 0.988387f, 0.979485f, 0.966655f, 0.949608f, 0.928453f, 0.903518f, 0.875176f, 0.843709f, 0.809330f, + + 1.000000f, 0.995343f, 0.998855f, 0.999483f, 0.999669f, 0.999718f, 0.999704f, 0.999652f, 0.999575f, 0.999478f, 0.999364f, 0.999236f, 0.999096f, 0.998945f, 0.998784f, 0.998615f, + 1.000000f, 0.998083f, 0.969303f, 0.924430f, 0.917931f, 0.929179f, 0.938138f, 0.940083f, 0.935376f, 0.925368f, 0.911393f, 0.894614f, 0.875999f, 0.856324f, 0.836157f, 0.815926f, + 1.000000f, 0.999629f, 0.993257f, 0.969480f, 0.941061f, 0.927776f, 0.925202f, 0.923072f, 0.915997f, 0.902730f, 0.883901f, 0.860843f, 0.834978f, 0.807577f, 0.779658f, 0.751951f, + 1.000000f, 0.999861f, 0.997527f, 0.986952f, 0.966093f, 0.945483f, 0.932121f, 0.922708f, 0.911589f, 0.895462f, 0.873549f, 0.846656f, 0.816239f, 0.783848f, 0.750829f, 0.718183f, + 1.000000f, 0.999931f, 0.998797f, 0.993409f, 0.980244f, 0.961841f, 0.944467f, 0.929718f, 0.914624f, 0.895827f, 0.871621f, 0.842148f, 0.808628f, 0.772679f, 0.735883f, 0.699500f, + 1.000000f, 0.999960f, 0.999304f, 0.996172f, 0.987729f, 0.973327f, 0.956177f, 0.938978f, 0.921091f, 0.900152f, 0.874277f, 0.843070f, 0.807425f, 0.768903f, 0.729218f, 0.689856f, + 1.000000f, 0.999973f, 0.999548f, 0.997531f, 0.991825f, 0.980882f, 0.965598f, 0.948047f, 0.928751f, 0.906409f, 0.879409f, 0.847132f, 0.810118f, 0.769800f, 0.727940f, 0.686197f, + 1.000000f, 0.999981f, 0.999682f, 0.998272f, 0.994204f, 0.985815f, 0.972740f, 0.956015f, 0.936399f, 0.913386f, 0.885808f, 0.852995f, 0.815241f, 0.773789f, 0.730378f, 0.686765f, + 1.000000f, 0.999986f, 0.999761f, 0.998716f, 0.995668f, 0.989101f, 0.978044f, 0.962666f, 0.943491f, 0.920413f, 0.892719f, 0.859812f, 0.821845f, 0.779846f, 0.735462f, 0.690470f, + 1.000000f, 0.999989f, 0.999813f, 0.998997f, 0.996616f, 0.991347f, 0.981992f, 0.968097f, 0.949806f, 0.927145f, 0.899708f, 0.867065f, 0.829307f, 0.787277f, 0.742452f, 0.696583f, + 1.000000f, 0.999991f, 0.999849f, 0.999187f, 0.997264f, 0.992935f, 0.984960f, 0.972503f, 0.955315f, 0.933385f, 0.906506f, 0.874432f, 0.837230f, 0.795607f, 0.750846f, 0.704615f, + 1.000000f, 0.999993f, 0.999872f, 0.999321f, 0.997721f, 0.994091f, 0.987221f, 0.976077f, 0.960090f, 0.939078f, 0.912949f, 0.881662f, 0.845301f, 0.804470f, 0.760276f, 0.714188f, + 1.000000f, 0.999994f, 0.999890f, 0.999419f, 0.998059f, 0.994951f, 0.988977f, 0.978987f, 0.964177f, 0.944209f, 0.918995f, 0.888621f, 0.853316f, 0.813628f, 0.770455f, 0.725040f, + 1.000000f, 0.999994f, 0.999903f, 0.999492f, 0.998310f, 0.995607f, 0.990346f, 0.981362f, 0.967689f, 0.948783f, 0.924566f, 0.895218f, 0.861122f, 0.822828f, 0.781114f, 0.736951f, + 1.000000f, 0.999995f, 0.999914f, 0.999549f, 0.998501f, 0.996109f, 0.991426f, 0.983297f, 0.970650f, 0.952799f, 0.929588f, 0.901313f, 0.868512f, 0.831837f, 0.791942f, 0.749584f, + 1.000000f, 0.999995f, 0.999921f, 0.999587f, 0.998635f, 0.996461f, 0.992195f, 0.984724f, 0.972915f, 0.955941f, 0.933578f, 0.906196f, 0.874554f, 0.839421f, 0.801478f, 0.761256f, + + 1.000000f, 0.995353f, 0.998865f, 0.999494f, 0.999683f, 0.999736f, 0.999729f, 0.999686f, 0.999620f, 0.999535f, 0.999435f, 0.999322f, 0.999197f, 0.999062f, 0.998918f, 0.998766f, + 1.000000f, 0.998142f, 0.970240f, 0.926708f, 0.920346f, 0.931220f, 0.939975f, 0.942092f, 0.937929f, 0.928707f, 0.915627f, 0.899725f, 0.881865f, 0.862749f, 0.842926f, 0.822811f, + 1.000000f, 0.999640f, 0.993481f, 0.970495f, 0.942871f, 0.929672f, 0.926767f, 0.924403f, 0.917472f, 0.904673f, 0.886466f, 0.863995f, 0.838527f, 0.811225f, 0.783058f, 0.754755f, + 1.000000f, 0.999864f, 0.997569f, 0.987205f, 0.966716f, 0.946238f, 0.932608f, 0.922795f, 0.911423f, 0.895275f, 0.873498f, 0.846701f, 0.816172f, 0.783347f, 0.749489f, 0.715648f, + 1.000000f, 0.999930f, 0.998788f, 0.993377f, 0.980152f, 0.961536f, 0.943727f, 0.928369f, 0.912666f, 0.893344f, 0.868722f, 0.838781f, 0.804584f, 0.767636f, 0.729484f, 0.691397f, + 1.000000f, 0.999959f, 0.999279f, 0.996040f, 0.987304f, 0.972370f, 0.954439f, 0.936304f, 0.917405f, 0.895435f, 0.868538f, 0.836248f, 0.799330f, 0.759260f, 0.717727f, 0.676233f, + 1.000000f, 0.999971f, 0.999519f, 0.997370f, 0.991285f, 0.979590f, 0.963201f, 0.944311f, 0.923528f, 0.899607f, 0.870990f, 0.836968f, 0.798051f, 0.755634f, 0.711449f, 0.667187f, + 1.000000f, 0.999979f, 0.999652f, 0.998105f, 0.993635f, 0.984397f, 0.969980f, 0.951526f, 0.929938f, 0.904772f, 0.874915f, 0.839670f, 0.799368f, 0.755217f, 0.709017f, 0.662536f, + 1.000000f, 0.999984f, 0.999732f, 0.998553f, 0.995112f, 0.987668f, 0.975125f, 0.957697f, 0.936069f, 0.910260f, 0.879610f, 0.843577f, 0.802361f, 0.757048f, 0.709369f, 0.661181f, + 1.000000f, 0.999987f, 0.999785f, 0.998842f, 0.996080f, 0.989949f, 0.979048f, 0.962879f, 0.941712f, 0.915732f, 0.884654f, 0.848162f, 0.806442f, 0.760467f, 0.711831f, 0.662405f, + 1.000000f, 0.999989f, 0.999821f, 0.999038f, 0.996754f, 0.991590f, 0.982053f, 0.967179f, 0.946783f, 0.920992f, 0.889804f, 0.853131f, 0.811229f, 0.764994f, 0.715888f, 0.665713f, + 1.000000f, 0.999991f, 0.999847f, 0.999181f, 0.997236f, 0.992805f, 0.984396f, 0.970756f, 0.951286f, 0.925956f, 0.894889f, 0.858256f, 0.816447f, 0.770312f, 0.721200f, 0.670770f, + 1.000000f, 0.999992f, 0.999864f, 0.999283f, 0.997594f, 0.993722f, 0.986241f, 0.973735f, 0.955274f, 0.930582f, 0.899822f, 0.863404f, 0.821902f, 0.776188f, 0.727504f, 0.677325f, + 1.000000f, 0.999993f, 0.999880f, 0.999363f, 0.997868f, 0.994431f, 0.987713f, 0.976227f, 0.958784f, 0.934853f, 0.904567f, 0.868500f, 0.827467f, 0.782451f, 0.734612f, 0.685220f, + 1.000000f, 0.999994f, 0.999891f, 0.999425f, 0.998078f, 0.994987f, 0.988897f, 0.978306f, 0.961859f, 0.938761f, 0.909049f, 0.873455f, 0.833026f, 0.788954f, 0.742359f, 0.694317f, + 1.000000f, 0.999994f, 0.999899f, 0.999469f, 0.998230f, 0.995395f, 0.989794f, 0.979946f, 0.964372f, 0.942073f, 0.912956f, 0.877817f, 0.838022f, 0.794995f, 0.749934f, 0.703736f, + + 1.000000f, 0.995372f, 0.998882f, 0.999509f, 0.999698f, 0.999754f, 0.999751f, 0.999715f, 0.999657f, 0.999581f, 0.999491f, 0.999390f, 0.999278f, 0.999156f, 0.999026f, 0.998888f, + 1.000000f, 0.998242f, 0.971833f, 0.930547f, 0.924331f, 0.934324f, 0.942304f, 0.944064f, 0.939950f, 0.931093f, 0.918552f, 0.903232f, 0.885894f, 0.867167f, 0.847559f, 0.827465f, + 1.000000f, 0.999659f, 0.993827f, 0.972071f, 0.945685f, 0.932510f, 0.928824f, 0.925669f, 0.918261f, 0.905332f, 0.887252f, 0.864969f, 0.839592f, 0.812164f, 0.783606f, 0.754618f, + 1.000000f, 0.999867f, 0.997633f, 0.987557f, 0.967567f, 0.947227f, 0.933086f, 0.922399f, 0.910177f, 0.893396f, 0.871192f, 0.844036f, 0.813046f, 0.779516f, 0.744671f, 0.709514f, + 1.000000f, 0.999930f, 0.998771f, 0.993300f, 0.979919f, 0.960922f, 0.942369f, 0.925957f, 0.909076f, 0.888654f, 0.863025f, 0.832120f, 0.796861f, 0.758657f, 0.718960f, 0.679045f, + 1.000000f, 0.999956f, 0.999239f, 0.995830f, 0.986625f, 0.970820f, 0.951661f, 0.932046f, 0.911534f, 0.887936f, 0.859439f, 0.825540f, 0.786932f, 0.745027f, 0.701449f, 0.657704f, + 1.000000f, 0.999969f, 0.999473f, 0.997118f, 0.990453f, 0.977609f, 0.959545f, 0.938648f, 0.915693f, 0.889524f, 0.858630f, 0.822317f, 0.781060f, 0.736208f, 0.689492f, 0.642615f, + 1.000000f, 0.999976f, 0.999606f, 0.997854f, 0.992781f, 0.982286f, 0.965882f, 0.944911f, 0.920520f, 0.892413f, 0.859550f, 0.821273f, 0.777916f, 0.730738f, 0.681511f, 0.632081f, + 1.000000f, 0.999981f, 0.999687f, 0.998312f, 0.994284f, 0.985568f, 0.970883f, 0.950549f, 0.925506f, 0.896024f, 0.861574f, 0.821689f, 0.776670f, 0.727675f, 0.676486f, 0.625008f, + 1.000000f, 0.999985f, 0.999743f, 0.998616f, 0.995303f, 0.987934f, 0.974828f, 0.955478f, 0.930373f, 0.899997f, 0.864294f, 0.823096f, 0.776766f, 0.726395f, 0.673719f, 0.620682f, + 1.000000f, 0.999987f, 0.999781f, 0.998827f, 0.996025f, 0.989682f, 0.977961f, 0.959749f, 0.934996f, 0.904136f, 0.867474f, 0.825208f, 0.777828f, 0.726456f, 0.672745f, 0.618613f, + 1.000000f, 0.999988f, 0.999810f, 0.998982f, 0.996552f, 0.991001f, 0.980464f, 0.963424f, 0.939294f, 0.908297f, 0.870947f, 0.827811f, 0.779621f, 0.727558f, 0.673225f, 0.618454f, + 1.000000f, 0.999990f, 0.999830f, 0.999096f, 0.996952f, 0.992022f, 0.982488f, 0.966579f, 0.943252f, 0.912412f, 0.874629f, 0.830792f, 0.781979f, 0.729501f, 0.674937f, 0.619990f, + 1.000000f, 0.999991f, 0.999846f, 0.999185f, 0.997261f, 0.992825f, 0.984141f, 0.969298f, 0.946884f, 0.916421f, 0.878440f, 0.834092f, 0.784810f, 0.732168f, 0.677746f, 0.623118f, + 1.000000f, 0.999992f, 0.999858f, 0.999254f, 0.997503f, 0.993468f, 0.985501f, 0.971650f, 0.950197f, 0.920309f, 0.882351f, 0.837660f, 0.788084f, 0.735510f, 0.681629f, 0.627864f, + 1.000000f, 0.999992f, 0.999868f, 0.999309f, 0.997692f, 0.993974f, 0.986604f, 0.973631f, 0.953141f, 0.923966f, 0.886221f, 0.841379f, 0.791669f, 0.739403f, 0.686462f, 0.634174f, + + 1.000000f, 0.995413f, 0.998913f, 0.999532f, 0.999717f, 0.999772f, 0.999771f, 0.999739f, 0.999687f, 0.999618f, 0.999537f, 0.999445f, 0.999344f, 0.999233f, 0.999114f, 0.998988f, + 1.000000f, 0.998400f, 0.974429f, 0.936758f, 0.930501f, 0.938746f, 0.945098f, 0.945820f, 0.941234f, 0.932309f, 0.919951f, 0.904932f, 0.887890f, 0.869377f, 0.849842f, 0.829658f, + 1.000000f, 0.999681f, 0.994258f, 0.974035f, 0.949106f, 0.935700f, 0.930671f, 0.926035f, 0.917515f, 0.903922f, 0.885496f, 0.863037f, 0.837465f, 0.809716f, 0.780605f, 0.750826f, + 1.000000f, 0.999867f, 0.997657f, 0.987721f, 0.967895f, 0.947244f, 0.932082f, 0.919954f, 0.906332f, 0.888399f, 0.865291f, 0.837388f, 0.805642f, 0.771219f, 0.735246f, 0.698702f, + 1.000000f, 0.999925f, 0.998707f, 0.992961f, 0.978875f, 0.958705f, 0.938638f, 0.920490f, 0.901846f, 0.879769f, 0.852684f, 0.820426f, 0.783826f, 0.744171f, 0.702835f, 0.661064f, + 1.000000f, 0.999951f, 0.999157f, 0.995375f, 0.985160f, 0.967563f, 0.946128f, 0.924097f, 0.901206f, 0.875334f, 0.844707f, 0.808799f, 0.768233f, 0.724320f, 0.678633f, 0.632651f, + 1.000000f, 0.999965f, 0.999391f, 0.996667f, 0.988943f, 0.974050f, 0.953115f, 0.929017f, 0.902852f, 0.873624f, 0.839810f, 0.800723f, 0.756819f, 0.709381f, 0.660104f, 0.610670f, + 1.000000f, 0.999972f, 0.999530f, 0.997437f, 0.991362f, 0.978783f, 0.959185f, 0.934340f, 0.905871f, 0.873756f, 0.837055f, 0.795148f, 0.748369f, 0.697964f, 0.645713f, 0.593434f, + 1.000000f, 0.999977f, 0.999618f, 0.997931f, 0.992983f, 0.982271f, 0.964282f, 0.939592f, 0.909677f, 0.875207f, 0.835895f, 0.791409f, 0.742095f, 0.689182f, 0.634462f, 0.579861f, + 1.000000f, 0.999981f, 0.999679f, 0.998269f, 0.994120f, 0.984880f, 0.968507f, 0.944532f, 0.913892f, 0.877580f, 0.835951f, 0.789083f, 0.737498f, 0.682417f, 0.625664f, 0.569212f, + 1.000000f, 0.999983f, 0.999722f, 0.998511f, 0.994947f, 0.986867f, 0.971985f, 0.949030f, 0.918252f, 0.880613f, 0.836955f, 0.787880f, 0.734206f, 0.677265f, 0.618859f, 0.560978f, + 1.000000f, 0.999985f, 0.999755f, 0.998689f, 0.995564f, 0.988405f, 0.974849f, 0.953070f, 0.922585f, 0.884086f, 0.838719f, 0.787615f, 0.732013f, 0.673422f, 0.613712f, 0.554814f, + 1.000000f, 0.999987f, 0.999780f, 0.998827f, 0.996034f, 0.989616f, 0.977223f, 0.956653f, 0.926786f, 0.887858f, 0.841111f, 0.788160f, 0.730739f, 0.670705f, 0.610002f, 0.550491f, + 1.000000f, 0.999988f, 0.999799f, 0.998932f, 0.996407f, 0.990586f, 0.979197f, 0.959827f, 0.930789f, 0.891800f, 0.844011f, 0.789411f, 0.730324f, 0.669025f, 0.607615f, 0.547908f, + 1.000000f, 0.999989f, 0.999814f, 0.999017f, 0.996706f, 0.991378f, 0.980863f, 0.962638f, 0.934581f, 0.895866f, 0.847385f, 0.791390f, 0.730794f, 0.668422f, 0.606630f, 0.547188f, + 1.000000f, 0.999989f, 0.999827f, 0.999089f, 0.996952f, 0.992038f, 0.982292f, 0.965160f, 0.938212f, 0.900086f, 0.851302f, 0.794258f, 0.732412f, 0.669246f, 0.607505f, 0.548948f, + + 1.000000f, 0.995527f, 0.998988f, 0.999578f, 0.999746f, 0.999792f, 0.999788f, 0.999757f, 0.999709f, 0.999646f, 0.999572f, 0.999487f, 0.999393f, 0.999292f, 0.999182f, 0.999065f, + 1.000000f, 0.998630f, 0.978259f, 0.945594f, 0.938363f, 0.943208f, 0.946704f, 0.945624f, 0.940084f, 0.930762f, 0.918345f, 0.903424f, 0.886518f, 0.868076f, 0.848494f, 0.828108f, + 1.000000f, 0.999686f, 0.994379f, 0.974597f, 0.949667f, 0.934937f, 0.927853f, 0.921320f, 0.911428f, 0.896989f, 0.878093f, 0.855342f, 0.829503f, 0.801381f, 0.771709f, 0.741121f, + 1.000000f, 0.999854f, 0.997413f, 0.986433f, 0.964455f, 0.941275f, 0.923775f, 0.909649f, 0.894422f, 0.875277f, 0.851284f, 0.822663f, 0.790233f, 0.755013f, 0.718042f, 0.680244f, + 1.000000f, 0.999911f, 0.998460f, 0.991601f, 0.974763f, 0.950692f, 0.926863f, 0.905686f, 0.884687f, 0.860771f, 0.832199f, 0.798686f, 0.760917f, 0.720034f, 0.677317f, 0.633973f, + 1.000000f, 0.999939f, 0.998951f, 0.994222f, 0.981435f, 0.959489f, 0.933079f, 0.906577f, 0.880075f, 0.851316f, 0.818348f, 0.780447f, 0.738092f, 0.692475f, 0.645047f, 0.597247f, + 1.000000f, 0.999955f, 0.999220f, 0.995720f, 0.985790f, 0.966702f, 0.940181f, 0.910358f, 0.879136f, 0.845680f, 0.808362f, 0.766337f, 0.719885f, 0.670150f, 0.618757f, 0.567295f, + 1.000000f, 0.999964f, 0.999386f, 0.996651f, 0.988710f, 0.972315f, 0.947035f, 0.915627f, 0.880780f, 0.842993f, 0.801433f, 0.755396f, 0.705118f, 0.651733f, 0.596910f, 0.542404f, + 1.000000f, 0.999970f, 0.999497f, 0.997273f, 0.990734f, 0.976637f, 0.953160f, 0.921481f, 0.884126f, 0.842575f, 0.796931f, 0.746983f, 0.693063f, 0.636338f, 0.578514f, 0.521455f, + 1.000000f, 0.999975f, 0.999573f, 0.997701f, 0.992188f, 0.979945f, 0.958416f, 0.927337f, 0.888509f, 0.843869f, 0.794433f, 0.740656f, 0.683196f, 0.623342f, 0.562868f, 0.503667f, + 1.000000f, 0.999978f, 0.999630f, 0.998013f, 0.993256f, 0.982510f, 0.962846f, 0.932888f, 0.893436f, 0.846421f, 0.793557f, 0.736072f, 0.675142f, 0.612325f, 0.549463f, 0.488487f, + 1.000000f, 0.999980f, 0.999672f, 0.998245f, 0.994061f, 0.984514f, 0.966548f, 0.937969f, 0.898572f, 0.849868f, 0.794002f, 0.732975f, 0.668639f, 0.602965f, 0.537948f, 0.475509f, + 1.000000f, 0.999982f, 0.999704f, 0.998422f, 0.994681f, 0.986106f, 0.969639f, 0.942542f, 0.903685f, 0.853930f, 0.795521f, 0.731167f, 0.663513f, 0.595046f, 0.528062f, 0.464468f, + 1.000000f, 0.999983f, 0.999729f, 0.998565f, 0.995174f, 0.987383f, 0.972219f, 0.946621f, 0.908635f, 0.858379f, 0.797926f, 0.730503f, 0.659617f, 0.588452f, 0.519655f, 0.455184f, + 1.000000f, 0.999985f, 0.999750f, 0.998678f, 0.995570f, 0.988433f, 0.974409f, 0.950253f, 0.913383f, 0.863096f, 0.801085f, 0.730928f, 0.656937f, 0.583162f, 0.512731f, 0.447692f, + 1.000000f, 0.999986f, 0.999768f, 0.998774f, 0.995908f, 0.989329f, 0.976331f, 0.953588f, 0.918034f, 0.868186f, 0.805172f, 0.732710f, 0.655891f, 0.579707f, 0.507923f, 0.442761f, + + 1.000000f, 0.996312f, 0.999240f, 0.999651f, 0.999760f, 0.999787f, 0.999779f, 0.999749f, 0.999703f, 0.999645f, 0.999575f, 0.999495f, 0.999407f, 0.999309f, 0.999204f, 0.999092f, + 1.000000f, 0.998301f, 0.972928f, 0.931704f, 0.920748f, 0.925333f, 0.930051f, 0.930602f, 0.926625f, 0.918661f, 0.907363f, 0.893324f, 0.877064f, 0.859040f, 0.839650f, 0.819231f, + 1.000000f, 0.999525f, 0.991428f, 0.961144f, 0.923725f, 0.903320f, 0.896105f, 0.891629f, 0.884225f, 0.872051f, 0.855024f, 0.833730f, 0.808951f, 0.781485f, 0.752085f, 0.721414f, + 1.000000f, 0.999774f, 0.995997f, 0.978904f, 0.944981f, 0.910598f, 0.887366f, 0.871985f, 0.857707f, 0.840241f, 0.817970f, 0.790838f, 0.759542f, 0.725052f, 0.688400f, 0.650532f, + 1.000000f, 0.999866f, 0.997668f, 0.987231f, 0.961720f, 0.926013f, 0.892610f, 0.866048f, 0.842981f, 0.818867f, 0.790927f, 0.758281f, 0.721314f, 0.681005f, 0.638561f, 0.595155f, + 1.000000f, 0.999910f, 0.998450f, 0.991465f, 0.972609f, 0.940671f, 0.903484f, 0.868578f, 0.836857f, 0.805400f, 0.771279f, 0.733075f, 0.690796f, 0.645329f, 0.597985f, 0.550096f, + 1.000000f, 0.999934f, 0.998877f, 0.993833f, 0.979565f, 0.952395f, 0.915451f, 0.875635f, 0.836658f, 0.797939f, 0.757376f, 0.713464f, 0.665999f, 0.615761f, 0.564091f, 0.512452f, + 1.000000f, 0.999949f, 0.999134f, 0.995276f, 0.984114f, 0.961248f, 0.926533f, 0.884641f, 0.840287f, 0.794994f, 0.747999f, 0.698280f, 0.645647f, 0.590843f, 0.535249f, 0.480393f, + 1.000000f, 0.999958f, 0.999301f, 0.996212f, 0.987189f, 0.967857f, 0.936066f, 0.894071f, 0.846193f, 0.795328f, 0.742217f, 0.686680f, 0.628856f, 0.569615f, 0.510364f, 0.452686f, + 1.000000f, 0.999965f, 0.999416f, 0.996852f, 0.989347f, 0.972802f, 0.944007f, 0.903118f, 0.853287f, 0.797992f, 0.739251f, 0.678005f, 0.614995f, 0.551366f, 0.488656f, 0.428473f, + 1.000000f, 0.999970f, 0.999498f, 0.997309f, 0.990906f, 0.976548f, 0.950521f, 0.911388f, 0.860855f, 0.802240f, 0.738510f, 0.671750f, 0.603568f, 0.535592f, 0.469551f, 0.407102f, + 1.000000f, 0.999973f, 0.999559f, 0.997645f, 0.992065f, 0.979424f, 0.955846f, 0.918761f, 0.868427f, 0.807506f, 0.739482f, 0.667504f, 0.594210f, 0.521887f, 0.452611f, 0.388102f, + 1.000000f, 0.999976f, 0.999605f, 0.997901f, 0.992948f, 0.981668f, 0.960198f, 0.925230f, 0.875721f, 0.813375f, 0.741762f, 0.664925f, 0.586603f, 0.509959f, 0.437510f, 0.371096f, + 1.000000f, 0.999978f, 0.999641f, 0.998100f, 0.993634f, 0.983446f, 0.963777f, 0.930872f, 0.882581f, 0.819548f, 0.745028f, 0.663733f, 0.580515f, 0.499559f, 0.423985f, 0.355802f, + 1.000000f, 0.999980f, 0.999669f, 0.998256f, 0.994180f, 0.984875f, 0.966740f, 0.935768f, 0.888948f, 0.825804f, 0.749026f, 0.663698f, 0.575750f, 0.490506f, 0.411849f, 0.342017f, + 1.000000f, 0.999981f, 0.999693f, 0.998386f, 0.994628f, 0.986052f, 0.969236f, 0.940057f, 0.894841f, 0.832060f, 0.753620f, 0.664714f, 0.572245f, 0.482769f, 0.401059f, 0.329698f +}; + +static const float table_ggx_glass_Eavg[256] = { + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 0.999948f, 0.999526f, 0.998250f, 0.995368f, 0.990153f, 0.982226f, 0.971590f, 0.958500f, 0.943359f, 0.926629f, 0.908785f, 0.890266f, 0.871452f, 0.852674f, 0.834183f, + 1.000000f, 0.999940f, 0.999462f, 0.998212f, 0.995774f, 0.991512f, 0.984795f, 0.975285f, 0.963001f, 0.948259f, 0.931521f, 0.913309f, 0.894118f, 0.874394f, 0.854521f, 0.834797f, + 1.000000f, 0.999936f, 0.999404f, 0.998052f, 0.995642f, 0.991777f, 0.985879f, 0.977416f, 0.966120f, 0.952052f, 0.935530f, 0.917035f, 0.897098f, 0.876222f, 0.854858f, 0.833395f, + 1.000000f, 0.999933f, 0.999357f, 0.997885f, 0.995352f, 0.991530f, 0.985983f, 0.978146f, 0.967570f, 0.954055f, 0.937708f, 0.918892f, 0.898089f, 0.875842f, 0.852684f, 0.829081f, + 1.000000f, 0.999930f, 0.999320f, 0.997734f, 0.995026f, 0.991065f, 0.985531f, 0.977907f, 0.967633f, 0.954330f, 0.937894f, 0.918515f, 0.896607f, 0.872718f, 0.847450f, 0.821371f, + 1.000000f, 0.999928f, 0.999290f, 0.997605f, 0.994707f, 0.990512f, 0.984770f, 0.977000f, 0.966604f, 0.953075f, 0.936122f, 0.915787f, 0.892406f, 0.866527f, 0.838798f, 0.809912f, + 1.000000f, 0.999926f, 0.999266f, 0.997495f, 0.994409f, 0.989914f, 0.983790f, 0.975569f, 0.964631f, 0.950373f, 0.932381f, 0.910592f, 0.885253f, 0.856934f, 0.826371f, 0.794380f, + 1.000000f, 0.999925f, 0.999248f, 0.997401f, 0.994124f, 0.989277f, 0.982606f, 0.973644f, 0.961719f, 0.946182f, 0.926552f, 0.902670f, 0.874805f, 0.843553f, 0.809751f, 0.774356f, + 1.000000f, 0.999925f, 0.999234f, 0.997319f, 0.993845f, 0.988576f, 0.981182f, 0.971131f, 0.957731f, 0.940281f, 0.918293f, 0.891626f, 0.860559f, 0.825811f, 0.788362f, 0.749315f, + 1.000000f, 0.999924f, 0.999223f, 0.997242f, 0.993540f, 0.987743f, 0.979384f, 0.967830f, 0.952347f, 0.932247f, 0.907072f, 0.876767f, 0.841769f, 0.802929f, 0.761410f, 0.718503f, + 1.000000f, 0.999924f, 0.999213f, 0.997156f, 0.993169f, 0.986668f, 0.976990f, 0.963370f, 0.945041f, 0.921363f, 0.892008f, 0.857117f, 0.817340f, 0.773777f, 0.727800f, 0.680887f, + 1.000000f, 0.999924f, 0.999202f, 0.997042f, 0.992642f, 0.985137f, 0.973602f, 0.957122f, 0.934914f, 0.906478f, 0.871730f, 0.831125f, 0.785646f, 0.736704f, 0.685926f, 0.634955f, + 1.000000f, 0.999924f, 0.999184f, 0.996841f, 0.991769f, 0.982715f, 0.968441f, 0.947900f, 0.920380f, 0.885624f, 0.843955f, 0.796294f, 0.744081f, 0.689112f, 0.633285f, 0.578354f, + 1.000000f, 0.999923f, 0.999128f, 0.996370f, 0.990004f, 0.978288f, 0.959700f, 0.933154f, 0.898161f, 0.854912f, 0.804326f, 0.747966f, 0.687872f, 0.626278f, 0.565335f, 0.506855f, + 1.000000f, 0.999914f, 0.998848f, 0.994908f, 0.985894f, 0.969773f, 0.944970f, 0.910567f, 0.866457f, 0.813420f, 0.753069f, 0.687695f, 0.619929f, 0.552409f, 0.487430f, 0.426737f +}; + +static const float table_ggx_glass_inv_E[4096] = { + 0.999985f, 1.000000f, 0.999989f, 0.999990f, 1.000000f, 0.999999f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + + 1.000000f, 0.995082f, 0.997750f, 0.996814f, 0.994756f, 0.991983f, 0.988694f, 0.985008f, 0.980991f, 0.976680f, 0.972098f, 0.967263f, 0.962191f, 0.956897f, 0.951393f, 0.945694f, + 1.000000f, 0.997327f, 0.950645f, 0.832222f, 0.702110f, 0.601791f, 0.544343f, 0.516691f, 0.504458f, 0.499346f, 0.497379f, 0.496755f, 0.496683f, 0.496802f, 0.496978f, 0.497139f, + 1.000000f, 0.996432f, 0.971516f, 0.904908f, 0.818245f, 0.748255f, 0.698217f, 0.661132f, 0.632581f, 0.610204f, 0.592497f, 0.578360f, 0.566979f, 0.557720f, 0.550120f, 0.543824f, + 1.000000f, 0.999653f, 0.994103f, 0.970001f, 0.920214f, 0.860776f, 0.807060f, 0.761582f, 0.722953f, 0.690200f, 0.662685f, 0.639760f, 0.620730f, 0.604930f, 0.591761f, 0.580730f, + 1.000000f, 0.999842f, 0.997455f, 0.987479f, 0.964275f, 0.927927f, 0.884581f, 0.840264f, 0.798180f, 0.759801f, 0.725804f, 0.696324f, 0.671106f, 0.649700f, 0.631572f, 0.616216f, + 1.000000f, 0.999929f, 0.998864f, 0.994331f, 0.982910f, 0.962055f, 0.932008f, 0.895627f, 0.856527f, 0.817676f, 0.781038f, 0.747745f, 0.718231f, 0.692480f, 0.670225f, 0.651075f, + 1.000000f, 0.999961f, 0.999376f, 0.996863f, 0.990329f, 0.977586f, 0.957377f, 0.930096f, 0.897609f, 0.862462f, 0.826970f, 0.792904f, 0.761375f, 0.732918f, 0.707657f, 0.685460f, + 1.000000f, 0.999976f, 0.999613f, 0.998053f, 0.993938f, 0.985660f, 0.971838f, 0.951879f, 0.926313f, 0.896583f, 0.864557f, 0.832070f, 0.800565f, 0.771014f, 0.743952f, 0.719567f, + 1.000000f, 0.999984f, 0.999745f, 0.998715f, 0.995974f, 0.990366f, 0.980729f, 0.966212f, 0.946629f, 0.922522f, 0.895070f, 0.865716f, 0.835888f, 0.806747f, 0.779117f, 0.753489f, + 1.000000f, 0.999989f, 0.999826f, 0.999123f, 0.997243f, 0.993362f, 0.986560f, 0.976040f, 0.961305f, 0.942373f, 0.919782f, 0.894446f, 0.867512f, 0.840089f, 0.813118f, 0.787284f, + 1.000000f, 0.999993f, 0.999881f, 0.999395f, 0.998094f, 0.995389f, 0.990595f, 0.983039f, 0.972175f, 0.957736f, 0.939825f, 0.918897f, 0.895690f, 0.871077f, 0.845921f, 0.820980f, + 1.000000f, 0.999995f, 0.999918f, 0.999585f, 0.998693f, 0.996832f, 0.993503f, 0.988186f, 0.980393f, 0.969766f, 0.956157f, 0.939679f, 0.920694f, 0.899742f, 0.877484f, 0.854586f, + 1.000000f, 0.999997f, 0.999946f, 0.999726f, 0.999136f, 0.997899f, 0.995672f, 0.992082f, 0.986739f, 0.979309f, 0.969547f, 0.957358f, 0.942813f, 0.926153f, 0.907762f, 0.888097f, + 1.000000f, 0.999998f, 0.999967f, 0.999832f, 0.999469f, 0.998707f, 0.997331f, 0.995094f, 0.991728f, 0.986971f, 0.980592f, 0.972409f, 0.962344f, 0.950403f, 0.936705f, 0.921469f, + 1.000000f, 0.999999f, 0.999983f, 0.999915f, 0.999727f, 0.999335f, 0.998625f, 0.997464f, 0.995701f, 0.993179f, 0.989726f, 0.985207f, 0.979490f, 0.972486f, 0.964145f, 0.954484f, + 1.000000f, 1.000000f, 0.999994f, 0.999967f, 0.999894f, 0.999741f, 0.999464f, 0.999009f, 0.998309f, 0.997296f, 0.995883f, 0.993986f, 0.991504f, 0.988339f, 0.984390f, 0.979542f, + + 1.000000f, 0.995236f, 0.998550f, 0.998801f, 0.998428f, 0.997742f, 0.996831f, 0.995743f, 0.994509f, 0.993153f, 0.991690f, 0.990130f, 0.988479f, 0.986742f, 0.984923f, 0.983024f, + 1.000000f, 0.997491f, 0.958825f, 0.887405f, 0.836169f, 0.777014f, 0.700137f, 0.619723f, 0.550159f, 0.497933f, 0.462916f, 0.441865f, 0.430862f, 0.426506f, 0.426279f, 0.428417f, + 1.000000f, 0.999387f, 0.987949f, 0.938920f, 0.854742f, 0.761659f, 0.675893f, 0.609056f, 0.563787f, 0.535678f, 0.518945f, 0.509098f, 0.503253f, 0.499699f, 0.497454f, 0.495959f, + 1.000000f, 0.999697f, 0.992974f, 0.956997f, 0.880103f, 0.793559f, 0.724151f, 0.674443f, 0.639020f, 0.613009f, 0.593289f, 0.577939f, 0.565706f, 0.555794f, 0.547620f, 0.540809f, + 1.000000f, 0.998971f, 0.990531f, 0.966765f, 0.920386f, 0.858725f, 0.798945f, 0.749892f, 0.711318f, 0.680491f, 0.655226f, 0.634142f, 0.616388f, 0.601357f, 0.588586f, 0.577688f, + 1.000000f, 0.999848f, 0.997453f, 0.986597f, 0.958949f, 0.913663f, 0.861319f, 0.812788f, 0.771829f, 0.737675f, 0.708689f, 0.683692f, 0.661970f, 0.643061f, 0.626615f, 0.612317f, + 1.000000f, 0.999918f, 0.998627f, 0.992720f, 0.976730f, 0.947034f, 0.906966f, 0.864277f, 0.824492f, 0.789204f, 0.758048f, 0.730349f, 0.705627f, 0.683579f, 0.663985f, 0.646642f, + 1.000000f, 0.999947f, 0.999111f, 0.995378f, 0.985462f, 0.966521f, 0.938604f, 0.905036f, 0.869938f, 0.836001f, 0.804272f, 0.774971f, 0.748071f, 0.723512f, 0.701250f, 0.681195f, + 1.000000f, 0.999965f, 0.999442f, 0.997183f, 0.991249f, 0.979598f, 0.961119f, 0.936455f, 0.907646f, 0.877051f, 0.846437f, 0.816822f, 0.788744f, 0.762490f, 0.738197f, 0.715942f, + 1.000000f, 0.999979f, 0.999660f, 0.998288f, 0.994651f, 0.987309f, 0.975057f, 0.957452f, 0.935116f, 0.909384f, 0.881821f, 0.853716f, 0.826017f, 0.799342f, 0.774067f, 0.750429f, + 1.000000f, 0.999987f, 0.999784f, 0.998907f, 0.996567f, 0.991766f, 0.983508f, 0.971084f, 0.954354f, 0.933827f, 0.910448f, 0.885334f, 0.859505f, 0.833742f, 0.808627f, 0.784554f, + 1.000000f, 0.999992f, 0.999858f, 0.999280f, 0.997733f, 0.994535f, 0.988921f, 0.980212f, 0.967995f, 0.952272f, 0.933425f, 0.912153f, 0.889282f, 0.865590f, 0.841742f, 0.818257f, + 1.000000f, 0.999995f, 0.999906f, 0.999523f, 0.998498f, 0.996361f, 0.992567f, 0.986552f, 0.977881f, 0.966282f, 0.951793f, 0.934713f, 0.915529f, 0.894853f, 0.873307f, 0.851407f, + 1.000000f, 0.999996f, 0.999940f, 0.999690f, 0.999024f, 0.997628f, 0.995121f, 0.991104f, 0.985173f, 0.977015f, 0.966461f, 0.953524f, 0.938375f, 0.921364f, 0.902945f, 0.883553f, + 1.000000f, 0.999998f, 0.999962f, 0.999809f, 0.999389f, 0.998514f, 0.996933f, 0.994364f, 0.990509f, 0.985082f, 0.977837f, 0.968625f, 0.957380f, 0.944176f, 0.929178f, 0.912684f, + 1.000000f, 0.999999f, 0.999973f, 0.999862f, 0.999565f, 0.998939f, 0.997802f, 0.995933f, 0.993080f, 0.988962f, 0.983276f, 0.975719f, 0.965982f, 0.953785f, 0.938866f, 0.921038f, + + 1.000000f, 0.995264f, 0.998700f, 0.999181f, 0.999146f, 0.998899f, 0.998518f, 0.998034f, 0.997464f, 0.996820f, 0.996113f, 0.995349f, 0.994536f, 0.993675f, 0.992770f, 0.991822f, + 1.000000f, 0.997506f, 0.959780f, 0.895886f, 0.867758f, 0.847192f, 0.811951f, 0.761560f, 0.702769f, 0.642860f, 0.587308f, 0.539284f, 0.500040f, 0.469478f, 0.446760f, 0.430697f, + 1.000000f, 0.999403f, 0.988921f, 0.947698f, 0.887836f, 0.831693f, 0.772965f, 0.707226f, 0.641001f, 0.582776f, 0.537128f, 0.504336f, 0.482382f, 0.468571f, 0.460416f, 0.456006f, + 1.000000f, 0.999734f, 0.994985f, 0.971627f, 0.918352f, 0.846555f, 0.770872f, 0.699786f, 0.639815f, 0.593898f, 0.561036f, 0.538362f, 0.522894f, 0.512265f, 0.504808f, 0.499436f, + 1.000000f, 0.999845f, 0.996884f, 0.980556f, 0.935434f, 0.863605f, 0.786812f, 0.721647f, 0.671750f, 0.634636f, 0.606898f, 0.585793f, 0.569400f, 0.556404f, 0.545880f, 0.537246f, + 1.000000f, 0.999883f, 0.997078f, 0.981152f, 0.942190f, 0.884389f, 0.821505f, 0.765319f, 0.719739f, 0.683723f, 0.655004f, 0.631650f, 0.612346f, 0.596152f, 0.582440f, 0.570744f, + 1.000000f, 0.999708f, 0.995826f, 0.983677f, 0.958470f, 0.917402f, 0.865810f, 0.813738f, 0.767950f, 0.730061f, 0.698996f, 0.673189f, 0.651349f, 0.632596f, 0.616345f, 0.602177f, + 1.000000f, 0.999917f, 0.998624f, 0.992763f, 0.976951f, 0.946967f, 0.904504f, 0.857014f, 0.811931f, 0.772830f, 0.739955f, 0.712217f, 0.688432f, 0.667676f, 0.649364f, 0.633098f, + 1.000000f, 0.999950f, 0.999175f, 0.995639f, 0.985685f, 0.965189f, 0.932959f, 0.892918f, 0.851405f, 0.812999f, 0.779369f, 0.750289f, 0.724925f, 0.702481f, 0.682374f, 0.664235f, + 1.000000f, 0.999965f, 0.999425f, 0.996976f, 0.990134f, 0.975876f, 0.952425f, 0.921070f, 0.885697f, 0.850344f, 0.817472f, 0.787847f, 0.761314f, 0.737404f, 0.715685f, 0.695837f, + 1.000000f, 0.999974f, 0.999576f, 0.997806f, 0.992983f, 0.983078f, 0.966551f, 0.943335f, 0.915131f, 0.884541f, 0.853930f, 0.824734f, 0.797553f, 0.772445f, 0.749281f, 0.727863f, + 1.000000f, 0.999983f, 0.999708f, 0.998519f, 0.995334f, 0.988826f, 0.977711f, 0.961295f, 0.939903f, 0.914764f, 0.887583f, 0.859907f, 0.832855f, 0.807035f, 0.782699f, 0.759885f, + 1.000000f, 0.999988f, 0.999811f, 0.999042f, 0.996990f, 0.992740f, 0.985312f, 0.973911f, 0.958186f, 0.938466f, 0.915581f, 0.890711f, 0.864992f, 0.839356f, 0.814445f, 0.790603f, + 1.000000f, 0.999993f, 0.999876f, 0.999372f, 0.998020f, 0.995197f, 0.990179f, 0.982272f, 0.970926f, 0.955919f, 0.937441f, 0.916057f, 0.892562f, 0.867872f, 0.842769f, 0.817881f, + 1.000000f, 0.999995f, 0.999915f, 0.999566f, 0.998632f, 0.996669f, 0.993140f, 0.987456f, 0.979025f, 0.967403f, 0.952286f, 0.933661f, 0.911774f, 0.887060f, 0.860168f, 0.831767f, + 1.000000f, 0.999996f, 0.999937f, 0.999677f, 0.998980f, 0.997510f, 0.994842f, 0.990476f, 0.983850f, 0.974367f, 0.961453f, 0.944585f, 0.923348f, 0.897484f, 0.866932f, 0.831849f, + + 1.000000f, 0.995274f, 0.998753f, 0.999314f, 0.999400f, 0.999312f, 0.999128f, 0.998872f, 0.998561f, 0.998199f, 0.997795f, 0.997353f, 0.996877f, 0.996371f, 0.995835f, 0.995272f, + 1.000000f, 0.997511f, 0.960071f, 0.898620f, 0.878659f, 0.873821f, 0.860219f, 0.833543f, 0.796233f, 0.752198f, 0.705231f, 0.658472f, 0.614230f, 0.573972f, 0.538477f, 0.508025f, + 1.000000f, 0.999405f, 0.989130f, 0.949830f, 0.897468f, 0.858122f, 0.823932f, 0.782744f, 0.732512f, 0.677594f, 0.623754f, 0.575427f, 0.534943f, 0.502899f, 0.478646f, 0.461005f, + 1.000000f, 0.999738f, 0.995228f, 0.974062f, 0.929086f, 0.874707f, 0.820986f, 0.765529f, 0.707500f, 0.650969f, 0.600887f, 0.560050f, 0.528786f, 0.505868f, 0.489538f, 0.478098f, + 1.000000f, 0.999852f, 0.997285f, 0.984298f, 0.949907f, 0.894687f, 0.830051f, 0.764655f, 0.703610f, 0.650720f, 0.607837f, 0.574686f, 0.549707f, 0.531052f, 0.517044f, 0.506390f, + 1.000000f, 0.999903f, 0.998164f, 0.988845f, 0.961108f, 0.909217f, 0.842075f, 0.774576f, 0.716020f, 0.668788f, 0.631760f, 0.602815f, 0.580035f, 0.561884f, 0.547230f, 0.535234f, + 1.000000f, 0.999929f, 0.998507f, 0.990285f, 0.965135f, 0.917992f, 0.857129f, 0.795963f, 0.742667f, 0.699055f, 0.663951f, 0.635517f, 0.612188f, 0.592805f, 0.576520f, 0.562709f, + 1.000000f, 0.999930f, 0.997985f, 0.987991f, 0.965712f, 0.929365f, 0.880981f, 0.827897f, 0.777686f, 0.734212f, 0.698025f, 0.668119f, 0.643237f, 0.622258f, 0.604347f, 0.588895f, + 1.000000f, 0.999892f, 0.998245f, 0.991593f, 0.976269f, 0.949053f, 0.909388f, 0.861824f, 0.813348f, 0.769138f, 0.731260f, 0.699559f, 0.673029f, 0.650560f, 0.631217f, 0.614335f, + 1.000000f, 0.999951f, 0.999193f, 0.995758f, 0.986165f, 0.966390f, 0.934469f, 0.892812f, 0.847190f, 0.803233f, 0.764153f, 0.730780f, 0.702574f, 0.678537f, 0.657746f, 0.639441f, + 1.000000f, 0.999967f, 0.999464f, 0.997169f, 0.990665f, 0.976632f, 0.952374f, 0.918124f, 0.877615f, 0.835913f, 0.796893f, 0.762354f, 0.732463f, 0.706676f, 0.684154f, 0.664217f, + 1.000000f, 0.999976f, 0.999599f, 0.997898f, 0.993113f, 0.982787f, 0.964563f, 0.937646f, 0.903767f, 0.866396f, 0.829112f, 0.794260f, 0.762877f, 0.735004f, 0.710259f, 0.688126f, + 1.000000f, 0.999981f, 0.999687f, 0.998378f, 0.994751f, 0.987065f, 0.973532f, 0.953125f, 0.926150f, 0.894376f, 0.860258f, 0.826066f, 0.793349f, 0.762938f, 0.735056f, 0.709572f, + 1.000000f, 0.999985f, 0.999762f, 0.998782f, 0.996155f, 0.990674f, 0.981030f, 0.966111f, 0.945407f, 0.919258f, 0.888814f, 0.855632f, 0.821323f, 0.787139f, 0.753957f, 0.722283f, + 1.000000f, 0.999990f, 0.999832f, 0.999154f, 0.997326f, 0.993492f, 0.986639f, 0.975713f, 0.959807f, 0.938406f, 0.911476f, 0.879541f, 0.843530f, 0.804526f, 0.763704f, 0.722042f, + 1.000000f, 0.999993f, 0.999880f, 0.999393f, 0.998081f, 0.995315f, 0.990310f, 0.982153f, 0.969868f, 0.952528f, 0.929350f, 0.899824f, 0.863810f, 0.821621f, 0.773983f, 0.722012f, + + 1.000000f, 0.995279f, 0.998777f, 0.999375f, 0.999516f, 0.999502f, 0.999409f, 0.999263f, 0.999075f, 0.998852f, 0.998598f, 0.998317f, 0.998011f, 0.997682f, 0.997333f, 0.996965f, + 1.000000f, 0.997512f, 0.960193f, 0.899810f, 0.883560f, 0.886229f, 0.883754f, 0.870744f, 0.848142f, 0.818228f, 0.783377f, 0.745763f, 0.707244f, 0.669288f, 0.632992f, 0.599103f, + 1.000000f, 0.999406f, 0.989202f, 0.950635f, 0.901346f, 0.869619f, 0.848470f, 0.824120f, 0.791055f, 0.749978f, 0.704165f, 0.657309f, 0.612523f, 0.571935f, 0.536685f, 0.507097f, + 1.000000f, 0.999738f, 0.995293f, 0.974815f, 0.932797f, 0.886032f, 0.845632f, 0.806855f, 0.763730f, 0.715650f, 0.665786f, 0.618169f, 0.575818f, 0.540180f, 0.511466f, 0.489052f, + 1.000000f, 0.999852f, 0.997364f, 0.985187f, 0.954180f, 0.907250f, 0.855836f, 0.804425f, 0.752168f, 0.699650f, 0.649724f, 0.605354f, 0.568138f, 0.538243f, 0.514846f, 0.496802f, + 1.000000f, 0.999904f, 0.998287f, 0.990135f, 0.966897f, 0.924434f, 0.868932f, 0.809150f, 0.750508f, 0.696302f, 0.648748f, 0.608872f, 0.576454f, 0.550541f, 0.529942f, 0.513537f, + 1.000000f, 0.999932f, 0.998757f, 0.992664f, 0.974035f, 0.935966f, 0.880421f, 0.817418f, 0.756776f, 0.703644f, 0.659295f, 0.622981f, 0.593394f, 0.569220f, 0.549366f, 0.532937f, + 1.000000f, 0.999948f, 0.998998f, 0.993796f, 0.977216f, 0.942154f, 0.889613f, 0.829330f, 0.771355f, 0.720748f, 0.678401f, 0.643376f, 0.614334f, 0.590114f, 0.569735f, 0.552482f, + 1.000000f, 0.999956f, 0.999008f, 0.993380f, 0.976671f, 0.945269f, 0.900482f, 0.847803f, 0.794303f, 0.745187f, 0.702581f, 0.666575f, 0.636395f, 0.611019f, 0.589522f, 0.571144f, + 1.000000f, 0.999642f, 0.997254f, 0.990779f, 0.977436f, 0.953828f, 0.918026f, 0.872140f, 0.821771f, 0.772688f, 0.728481f, 0.690385f, 0.658196f, 0.631079f, 0.608078f, 0.588383f, + 1.000000f, 0.999950f, 0.999173f, 0.995700f, 0.986407f, 0.967945f, 0.938044f, 0.897296f, 0.849725f, 0.800827f, 0.754988f, 0.714460f, 0.679710f, 0.650226f, 0.625133f, 0.603566f, + 1.000000f, 0.999969f, 0.999491f, 0.997328f, 0.991190f, 0.977844f, 0.954242f, 0.919490f, 0.876027f, 0.828587f, 0.781834f, 0.738874f, 0.700951f, 0.668123f, 0.639755f, 0.615082f, + 1.000000f, 0.999977f, 0.999617f, 0.997990f, 0.993387f, 0.983289f, 0.964865f, 0.936338f, 0.898372f, 0.854074f, 0.807560f, 0.762265f, 0.720225f, 0.682178f, 0.648063f, 0.617433f, + 1.000000f, 0.999981f, 0.999683f, 0.998357f, 0.994648f, 0.986594f, 0.971921f, 0.948760f, 0.916623f, 0.876794f, 0.831897f, 0.784881f, 0.738053f, 0.692914f, 0.650113f, 0.609792f, + 1.000000f, 0.999984f, 0.999734f, 0.998629f, 0.995610f, 0.989205f, 0.977699f, 0.959459f, 0.933369f, 0.899232f, 0.857885f, 0.811010f, 0.760542f, 0.708378f, 0.655964f, 0.604417f, + 1.000000f, 0.999988f, 0.999800f, 0.998989f, 0.996796f, 0.992182f, 0.983853f, 0.970359f, 0.950269f, 0.922385f, 0.886016f, 0.841174f, 0.788665f, 0.730019f, 0.667293f, 0.602764f, + + 1.000000f, 0.995281f, 0.998789f, 0.999407f, 0.999577f, 0.999602f, 0.999558f, 0.999470f, 0.999349f, 0.999201f, 0.999030f, 0.998838f, 0.998627f, 0.998399f, 0.998155f, 0.997896f, + 1.000000f, 0.997513f, 0.960249f, 0.900406f, 0.886089f, 0.892774f, 0.896456f, 0.891395f, 0.877963f, 0.857758f, 0.832434f, 0.803495f, 0.772286f, 0.739949f, 0.707458f, 0.675561f, + 1.000000f, 0.999407f, 0.989231f, 0.951000f, 0.903200f, 0.875363f, 0.861319f, 0.847061f, 0.825875f, 0.796742f, 0.761239f, 0.721786f, 0.680816f, 0.640463f, 0.602298f, 0.567378f, + 1.000000f, 0.999738f, 0.995315f, 0.975112f, 0.934395f, 0.891271f, 0.858018f, 0.829830f, 0.799044f, 0.762384f, 0.720541f, 0.676210f, 0.632355f, 0.591401f, 0.554867f, 0.523436f, + 1.000000f, 0.999852f, 0.997386f, 0.985489f, 0.955810f, 0.912598f, 0.868448f, 0.827505f, 0.786526f, 0.742772f, 0.696651f, 0.650629f, 0.607470f, 0.569086f, 0.536346f, 0.509224f, + 1.000000f, 0.999904f, 0.998316f, 0.990504f, 0.968816f, 0.930527f, 0.882628f, 0.832611f, 0.782598f, 0.732654f, 0.683857f, 0.638184f, 0.597439f, 0.562499f, 0.533360f, 0.509454f, + 1.000000f, 0.999932f, 0.998803f, 0.993191f, 0.976633f, 0.943607f, 0.895857f, 0.840574f, 0.783946f, 0.729575f, 0.679617f, 0.635398f, 0.597373f, 0.565310f, 0.538606f, 0.516438f, + 1.000000f, 0.999948f, 0.999083f, 0.994709f, 0.981260f, 0.952269f, 0.906208f, 0.848944f, 0.789028f, 0.732726f, 0.682916f, 0.640159f, 0.603957f, 0.573434f, 0.547734f, 0.526040f, + 1.000000f, 0.999958f, 0.999244f, 0.995504f, 0.983610f, 0.957032f, 0.913261f, 0.857335f, 0.798097f, 0.742316f, 0.693015f, 0.650643f, 0.614578f, 0.583949f, 0.557917f, 0.535717f, + 1.000000f, 0.999965f, 0.999300f, 0.995552f, 0.983604f, 0.958348f, 0.918639f, 0.868000f, 0.812623f, 0.758282f, 0.708524f, 0.664736f, 0.626955f, 0.594631f, 0.567030f, 0.543396f, + 1.000000f, 0.999961f, 0.998876f, 0.993452f, 0.981396f, 0.960356f, 0.927836f, 0.883938f, 0.832391f, 0.778550f, 0.726910f, 0.680091f, 0.638976f, 0.603454f, 0.572900f, 0.546588f, + 1.000000f, 0.999948f, 0.999141f, 0.995636f, 0.986808f, 0.969928f, 0.942322f, 0.902955f, 0.853928f, 0.799818f, 0.745449f, 0.694280f, 0.648026f, 0.607120f, 0.571170f, 0.539507f, + 1.000000f, 0.999971f, 0.999515f, 0.997458f, 0.991643f, 0.978974f, 0.956207f, 0.921417f, 0.875407f, 0.821675f, 0.764848f, 0.708938f, 0.656438f, 0.608371f, 0.564828f, 0.525338f, + 1.000000f, 0.999977f, 0.999625f, 0.998046f, 0.993587f, 0.983730f, 0.965409f, 0.935992f, 0.894749f, 0.843544f, 0.786131f, 0.726560f, 0.667972f, 0.612238f, 0.560125f, 0.511730f, + 1.000000f, 0.999981f, 0.999680f, 0.998335f, 0.994583f, 0.986395f, 0.971213f, 0.946522f, 0.910722f, 0.863973f, 0.808275f, 0.746767f, 0.682739f, 0.618900f, 0.557115f, 0.498536f, + 1.000000f, 0.999981f, 0.999699f, 0.998465f, 0.995126f, 0.988082f, 0.975371f, 0.954899f, 0.924785f, 0.883853f, 0.832029f, 0.770609f, 0.702046f, 0.629568f, 0.556527f, 0.485918f, + + 1.000000f, 0.995282f, 0.998796f, 0.999425f, 0.999611f, 0.999659f, 0.999642f, 0.999587f, 0.999504f, 0.999400f, 0.999277f, 0.999137f, 0.998983f, 0.998814f, 0.998633f, 0.998441f, + 1.000000f, 0.997513f, 0.960278f, 0.900724f, 0.887483f, 0.896459f, 0.903728f, 0.903412f, 0.895650f, 0.881748f, 0.863017f, 0.840610f, 0.815525f, 0.788635f, 0.760702f, 0.732374f, + 1.000000f, 0.999406f, 0.989241f, 0.951173f, 0.904157f, 0.878444f, 0.868446f, 0.860220f, 0.846617f, 0.825875f, 0.798692f, 0.766633f, 0.731460f, 0.694854f, 0.658274f, 0.622879f, + 1.000000f, 0.999737f, 0.995320f, 0.975238f, 0.935149f, 0.893906f, 0.864579f, 0.842702f, 0.820146f, 0.792448f, 0.758869f, 0.720774f, 0.680337f, 0.639759f, 0.600864f, 0.564924f, + 1.000000f, 0.999851f, 0.997390f, 0.985602f, 0.956507f, 0.915093f, 0.874811f, 0.840192f, 0.807403f, 0.772125f, 0.732870f, 0.690663f, 0.647724f, 0.606303f, 0.568131f, 0.534194f, + 1.000000f, 0.999903f, 0.998318f, 0.990625f, 0.969560f, 0.933162f, 0.889260f, 0.845564f, 0.803221f, 0.760306f, 0.715854f, 0.670786f, 0.627061f, 0.586488f, 0.550288f, 0.518905f, + 1.000000f, 0.999931f, 0.998809f, 0.993343f, 0.977536f, 0.946684f, 0.903274f, 0.854232f, 0.804128f, 0.754285f, 0.705289f, 0.658308f, 0.614732f, 0.575639f, 0.541492f, 0.512202f, + 1.000000f, 0.999948f, 0.999096f, 0.994935f, 0.982501f, 0.956236f, 0.914970f, 0.863407f, 0.807776f, 0.752439f, 0.699918f, 0.651662f, 0.608475f, 0.570547f, 0.537739f, 0.509589f, + 1.000000f, 0.999958f, 0.999275f, 0.995902f, 0.985571f, 0.962583f, 0.923689f, 0.871527f, 0.812829f, 0.754063f, 0.699203f, 0.649900f, 0.606478f, 0.568627f, 0.535870f, 0.507601f, + 1.000000f, 0.999965f, 0.999383f, 0.996447f, 0.987229f, 0.966133f, 0.929214f, 0.878067f, 0.819103f, 0.759216f, 0.702844f, 0.651887f, 0.606737f, 0.567112f, 0.532548f, 0.502454f, + 1.000000f, 0.999969f, 0.999429f, 0.996540f, 0.987322f, 0.966773f, 0.932016f, 0.884166f, 0.827678f, 0.768075f, 0.709745f, 0.655332f, 0.605919f, 0.561753f, 0.522522f, 0.487763f, + 1.000000f, 0.999968f, 0.999268f, 0.995284f, 0.984967f, 0.966145f, 0.936275f, 0.894014f, 0.841088f, 0.781733f, 0.720705f, 0.661589f, 0.606471f, 0.556170f, 0.510737f, 0.469825f, + 1.000000f, 0.999951f, 0.999187f, 0.995914f, 0.987863f, 0.972540f, 0.946931f, 0.908810f, 0.858448f, 0.799008f, 0.735076f, 0.670924f, 0.609496f, 0.552335f, 0.499952f, 0.452233f, + 1.000000f, 0.999973f, 0.999555f, 0.997668f, 0.992328f, 0.980601f, 0.959061f, 0.924916f, 0.877395f, 0.818463f, 0.752161f, 0.683031f, 0.614861f, 0.550061f, 0.489851f, 0.434654f, + 1.000000f, 0.999978f, 0.999641f, 0.998129f, 0.993860f, 0.984408f, 0.966592f, 0.937159f, 0.894046f, 0.837539f, 0.770472f, 0.697165f, 0.622089f, 0.548834f, 0.479806f, 0.416360f, + 1.000000f, 0.999980f, 0.999677f, 0.998316f, 0.994494f, 0.986091f, 0.970357f, 0.944295f, 0.905394f, 0.852501f, 0.786514f, 0.710447f, 0.628796f, 0.546440f, 0.467649f, 0.395427f, + + 1.000000f, 0.995283f, 0.998800f, 0.999435f, 0.999631f, 0.999691f, 0.999691f, 0.999655f, 0.999595f, 0.999516f, 0.999421f, 0.999313f, 0.999192f, 0.999059f, 0.998917f, 0.998764f, + 1.000000f, 0.997512f, 0.960289f, 0.900893f, 0.888264f, 0.898575f, 0.907972f, 0.910513f, 0.906231f, 0.896299f, 0.881871f, 0.863923f, 0.843273f, 0.820621f, 0.796574f, 0.771649f, + 1.000000f, 0.999405f, 0.989242f, 0.951252f, 0.904648f, 0.880121f, 0.872458f, 0.867827f, 0.858917f, 0.843645f, 0.822263f, 0.795882f, 0.765817f, 0.733393f, 0.699798f, 0.666063f, + 1.000000f, 0.999737f, 0.995318f, 0.975282f, 0.935499f, 0.895244f, 0.868096f, 0.849903f, 0.832452f, 0.810814f, 0.783502f, 0.751086f, 0.715043f, 0.677112f, 0.638938f, 0.601879f, + 1.000000f, 0.999851f, 0.997386f, 0.985632f, 0.956797f, 0.916269f, 0.878042f, 0.847041f, 0.819403f, 0.790195f, 0.756908f, 0.719491f, 0.679341f, 0.638364f, 0.598372f, 0.560777f, + 1.000000f, 0.999902f, 0.998314f, 0.990652f, 0.969838f, 0.934317f, 0.892448f, 0.852349f, 0.815038f, 0.777756f, 0.738291f, 0.696378f, 0.653243f, 0.610715f, 0.570450f, 0.533612f, + 1.000000f, 0.999931f, 0.998805f, 0.993377f, 0.977845f, 0.947940f, 0.906676f, 0.861280f, 0.815943f, 0.770863f, 0.725219f, 0.679104f, 0.633630f, 0.590317f, 0.550417f, 0.514624f, + 1.000000f, 0.999947f, 0.999093f, 0.994984f, 0.982895f, 0.957752f, 0.918880f, 0.871041f, 0.819643f, 0.767602f, 0.716077f, 0.665972f, 0.618404f, 0.574405f, 0.534630f, 0.499381f, + 1.000000f, 0.999957f, 0.999273f, 0.995983f, 0.986141f, 0.964597f, 0.928467f, 0.879916f, 0.824267f, 0.766440f, 0.709605f, 0.655628f, 0.605583f, 0.560068f, 0.519284f, 0.483185f, + 1.000000f, 0.999964f, 0.999388f, 0.996606f, 0.988176f, 0.969082f, 0.935243f, 0.886835f, 0.828531f, 0.766332f, 0.704864f, 0.646706f, 0.592981f, 0.544086f, 0.499969f, 0.460436f, + 1.000000f, 0.999969f, 0.999462f, 0.996977f, 0.989321f, 0.971637f, 0.939471f, 0.892050f, 0.833246f, 0.769016f, 0.704403f, 0.642408f, 0.584516f, 0.531265f, 0.482743f, 0.438826f, + 1.000000f, 0.999972f, 0.999497f, 0.997057f, 0.989393f, 0.971996f, 0.941268f, 0.896395f, 0.839702f, 0.775622f, 0.708797f, 0.642841f, 0.580000f, 0.521463f, 0.467672f, 0.418720f, + 1.000000f, 0.999972f, 0.999371f, 0.996026f, 0.987157f, 0.970597f, 0.943509f, 0.903421f, 0.850272f, 0.786874f, 0.717688f, 0.647101f, 0.578407f, 0.513634f, 0.453828f, 0.399366f, + 1.000000f, 0.999962f, 0.999368f, 0.996733f, 0.989833f, 0.976117f, 0.952471f, 0.915908f, 0.865184f, 0.801869f, 0.729929f, 0.654168f, 0.578853f, 0.507031f, 0.440545f, 0.380228f, + 1.000000f, 0.999976f, 0.999611f, 0.997961f, 0.993266f, 0.982780f, 0.962941f, 0.930172f, 0.882238f, 0.819483f, 0.745055f, 0.663908f, 0.581283f, 0.501532f, 0.427616f, 0.361193f, + 1.000000f, 0.999980f, 0.999676f, 0.998309f, 0.994432f, 0.985758f, 0.969118f, 0.940802f, 0.897514f, 0.837756f, 0.762936f, 0.677418f, 0.587328f, 0.498831f, 0.416740f, 0.343944f, + + 1.000000f, 0.995284f, 0.998803f, 0.999441f, 0.999642f, 0.999710f, 0.999718f, 0.999694f, 0.999647f, 0.999582f, 0.999504f, 0.999414f, 0.999312f, 0.999201f, 0.999080f, 0.998951f, + 1.000000f, 0.997512f, 0.960292f, 0.900975f, 0.888686f, 0.899761f, 0.910395f, 0.914614f, 0.912405f, 0.904872f, 0.893093f, 0.877966f, 0.860221f, 0.840462f, 0.819208f, 0.796894f, + 1.000000f, 0.999405f, 0.989238f, 0.951276f, 0.904877f, 0.880987f, 0.874630f, 0.872074f, 0.865948f, 0.854019f, 0.836327f, 0.813747f, 0.787361f, 0.758246f, 0.727412f, 0.695734f, + 1.000000f, 0.999737f, 0.995312f, 0.975285f, 0.935633f, 0.895869f, 0.869876f, 0.853742f, 0.839276f, 0.821353f, 0.798151f, 0.769798f, 0.737350f, 0.702173f, 0.665661f, 0.629043f, + 1.000000f, 0.999850f, 0.997379f, 0.985625f, 0.956883f, 0.916759f, 0.879558f, 0.850506f, 0.825820f, 0.800359f, 0.771144f, 0.737499f, 0.700220f, 0.660799f, 0.620820f, 0.581736f, + 1.000000f, 0.999902f, 0.998306f, 0.990638f, 0.969902f, 0.934739f, 0.893834f, 0.855594f, 0.821126f, 0.787404f, 0.751594f, 0.712639f, 0.671124f, 0.628474f, 0.586340f, 0.546124f, + 1.000000f, 0.999930f, 0.998796f, 0.993357f, 0.977898f, 0.948353f, 0.908039f, 0.864468f, 0.821839f, 0.779918f, 0.737104f, 0.692614f, 0.646983f, 0.601522f, 0.557744f, 0.516844f, + 1.000000f, 0.999946f, 0.999083f, 0.994962f, 0.982947f, 0.958178f, 0.920299f, 0.874253f, 0.825298f, 0.775678f, 0.725608f, 0.675136f, 0.624987f, 0.576365f, 0.530474f, 0.488210f, + 1.000000f, 0.999956f, 0.999261f, 0.995963f, 0.986220f, 0.965139f, 0.930136f, 0.883416f, 0.829854f, 0.773384f, 0.716136f, 0.659351f, 0.604123f, 0.551503f, 0.502397f, 0.457343f, + 1.000000f, 0.999963f, 0.999381f, 0.996624f, 0.988423f, 0.970106f, 0.937845f, 0.891629f, 0.835197f, 0.773425f, 0.710114f, 0.647711f, 0.587740f, 0.531184f, 0.478705f, 0.430616f, + 1.000000f, 0.999968f, 0.999464f, 0.997068f, 0.989893f, 0.973513f, 0.943505f, 0.898286f, 0.840457f, 0.775113f, 0.707123f, 0.639883f, 0.575385f, 0.514719f, 0.458478f, 0.406970f, + 1.000000f, 0.999971f, 0.999518f, 0.997342f, 0.990741f, 0.975475f, 0.947004f, 0.903070f, 0.845362f, 0.778426f, 0.707289f, 0.635853f, 0.566724f, 0.501440f, 0.440912f, 0.385604f, + 1.000000f, 0.999974f, 0.999544f, 0.997381f, 0.990696f, 0.975518f, 0.948161f, 0.906540f, 0.851004f, 0.784431f, 0.711198f, 0.635679f, 0.561400f, 0.490787f, 0.425353f, 0.365921f, + 1.000000f, 0.999971f, 0.999304f, 0.995978f, 0.988280f, 0.974075f, 0.950003f, 0.912685f, 0.860537f, 0.794859f, 0.719504f, 0.639410f, 0.559229f, 0.482529f, 0.411669f, 0.347942f, + 1.000000f, 0.999974f, 0.999565f, 0.997708f, 0.992443f, 0.980948f, 0.959813f, 0.925528f, 0.875653f, 0.810248f, 0.732357f, 0.647157f, 0.560340f, 0.476823f, 0.400035f, 0.331897f, + 1.000000f, 0.999980f, 0.999676f, 0.998305f, 0.994391f, 0.985550f, 0.968368f, 0.938734f, 0.892932f, 0.829321f, 0.749688f, 0.659212f, 0.564921f, 0.473581f, 0.390180f, 0.317446f, + + 1.000000f, 0.995284f, 0.998804f, 0.999444f, 0.999649f, 0.999720f, 0.999733f, 0.999714f, 0.999674f, 0.999618f, 0.999548f, 0.999468f, 0.999377f, 0.999277f, 0.999169f, 0.999053f, + 1.000000f, 0.997511f, 0.960289f, 0.901005f, 0.888885f, 0.900363f, 0.911663f, 0.916803f, 0.915736f, 0.909530f, 0.899242f, 0.885721f, 0.869663f, 0.851634f, 0.832099f, 0.811466f, + 1.000000f, 0.999404f, 0.989232f, 0.951270f, 0.904948f, 0.881357f, 0.875662f, 0.874199f, 0.869582f, 0.859498f, 0.843900f, 0.823539f, 0.799383f, 0.772396f, 0.743448f, 0.713338f, + 1.000000f, 0.999736f, 0.995304f, 0.975264f, 0.935642f, 0.896072f, 0.870612f, 0.855492f, 0.842579f, 0.826666f, 0.805776f, 0.779833f, 0.749653f, 0.716403f, 0.681265f, 0.645355f, + 1.000000f, 0.999849f, 0.997370f, 0.985595f, 0.956856f, 0.916856f, 0.880077f, 0.851914f, 0.828681f, 0.805175f, 0.778204f, 0.746802f, 0.711421f, 0.673228f, 0.633628f, 0.593933f, + 1.000000f, 0.999901f, 0.998296f, 0.990603f, 0.969847f, 0.934766f, 0.894195f, 0.856719f, 0.823539f, 0.791566f, 0.757680f, 0.720436f, 0.679984f, 0.637406f, 0.594174f, 0.551717f, + 1.000000f, 0.999929f, 0.998784f, 0.993309f, 0.977807f, 0.948280f, 0.908200f, 0.865216f, 0.823601f, 0.782972f, 0.741355f, 0.697452f, 0.651329f, 0.604006f, 0.556943f, 0.511515f, + 1.000000f, 0.999945f, 0.999070f, 0.994912f, 0.982853f, 0.958118f, 0.920485f, 0.875042f, 0.827032f, 0.778447f, 0.728966f, 0.678055f, 0.625944f, 0.573684f, 0.522641f, 0.474050f, + 1.000000f, 0.999956f, 0.999251f, 0.995932f, 0.986200f, 0.965274f, 0.930739f, 0.884939f, 0.832635f, 0.777366f, 0.720585f, 0.662901f, 0.605062f, 0.548168f, 0.493456f, 0.441994f, + 1.000000f, 0.999962f, 0.999373f, 0.996618f, 0.988491f, 0.970487f, 0.938987f, 0.894031f, 0.839138f, 0.778529f, 0.715265f, 0.651254f, 0.587957f, 0.526632f, 0.468422f, 0.414199f, + 1.000000f, 0.999968f, 0.999462f, 0.997093f, 0.990092f, 0.974273f, 0.945421f, 0.901867f, 0.845664f, 0.781073f, 0.712340f, 0.642651f, 0.574201f, 0.508557f, 0.446828f, 0.389860f, + 1.000000f, 0.999971f, 0.999524f, 0.997429f, 0.991210f, 0.976951f, 0.950194f, 0.908174f, 0.851673f, 0.784555f, 0.711642f, 0.637052f, 0.563754f, 0.493742f, 0.428379f, 0.368565f, + 1.000000f, 0.999975f, 0.999569f, 0.997647f, 0.991870f, 0.978507f, 0.953171f, 0.912734f, 0.857072f, 0.789157f, 0.713541f, 0.634828f, 0.556787f, 0.482180f, 0.412907f, 0.350140f, + 1.000000f, 0.999977f, 0.999582f, 0.997604f, 0.991564f, 0.978111f, 0.953898f, 0.916014f, 0.863007f, 0.796031f, 0.718779f, 0.636196f, 0.553097f, 0.473399f, 0.399812f, 0.333928f, + 1.000000f, 0.999955f, 0.999237f, 0.996489f, 0.990324f, 0.978430f, 0.957354f, 0.923234f, 0.873265f, 0.807238f, 0.728095f, 0.641110f, 0.552257f, 0.466791f, 0.388451f, 0.319337f, + 1.000000f, 0.999980f, 0.999676f, 0.998299f, 0.994349f, 0.985351f, 0.967719f, 0.937130f, 0.889763f, 0.824107f, 0.742285f, 0.649870f, 0.554162f, 0.462036f, 0.378442f, 0.305989f, + + 1.000000f, 0.995284f, 0.998804f, 0.999446f, 0.999652f, 0.999725f, 0.999740f, 0.999724f, 0.999687f, 0.999634f, 0.999568f, 0.999492f, 0.999406f, 0.999311f, 0.999208f, 0.999098f, + 1.000000f, 0.997511f, 0.960284f, 0.901003f, 0.888942f, 0.900590f, 0.912189f, 0.917748f, 0.917206f, 0.911615f, 0.902013f, 0.889241f, 0.873977f, 0.856768f, 0.838075f, 0.818279f, + 1.000000f, 0.999403f, 0.989226f, 0.951247f, 0.904929f, 0.881422f, 0.875975f, 0.874958f, 0.870990f, 0.861727f, 0.847075f, 0.827739f, 0.804628f, 0.778648f, 0.750639f, 0.721328f, + 1.000000f, 0.999735f, 0.995295f, 0.975231f, 0.935580f, 0.896025f, 0.870709f, 0.855938f, 0.843609f, 0.828504f, 0.808588f, 0.783681f, 0.754503f, 0.722104f, 0.687576f, 0.651942f, + 1.000000f, 0.999848f, 0.997360f, 0.985556f, 0.956763f, 0.916724f, 0.879989f, 0.852036f, 0.829234f, 0.806371f, 0.780182f, 0.749567f, 0.714816f, 0.676938f, 0.637197f, 0.596804f, + 1.000000f, 0.999900f, 0.998284f, 0.990550f, 0.969710f, 0.934519f, 0.893858f, 0.856387f, 0.823348f, 0.791625f, 0.757994f, 0.720839f, 0.680069f, 0.636588f, 0.591729f, 0.546835f, + 1.000000f, 0.999928f, 0.998773f, 0.993263f, 0.977688f, 0.948075f, 0.907943f, 0.865013f, 0.823579f, 0.783224f, 0.741798f, 0.697762f, 0.650887f, 0.601974f, 0.552381f, 0.503517f, + 1.000000f, 0.999945f, 0.999062f, 0.994881f, 0.982790f, 0.958040f, 0.920489f, 0.875301f, 0.827751f, 0.779733f, 0.730697f, 0.679770f, 0.626870f, 0.572826f, 0.518979f, 0.466743f, + 1.000000f, 0.999955f, 0.999246f, 0.995916f, 0.986184f, 0.965323f, 0.931015f, 0.885691f, 0.834125f, 0.779686f, 0.723524f, 0.665834f, 0.607019f, 0.548073f, 0.490339f, 0.435150f, + 1.000000f, 0.999962f, 0.999373f, 0.996619f, 0.988535f, 0.970697f, 0.939609f, 0.895401f, 0.841545f, 0.782010f, 0.719433f, 0.655283f, 0.590734f, 0.527088f, 0.465722f, 0.407904f, + 1.000000f, 0.999968f, 0.999463f, 0.997115f, 0.990219f, 0.974709f, 0.946527f, 0.904071f, 0.849246f, 0.785904f, 0.717781f, 0.647661f, 0.577649f, 0.509486f, 0.444684f, 0.384456f, + 1.000000f, 0.999971f, 0.999528f, 0.997475f, 0.991437f, 0.977692f, 0.951962f, 0.911448f, 0.856566f, 0.790615f, 0.717942f, 0.642489f, 0.567318f, 0.494773f, 0.426595f, 0.364046f, + 1.000000f, 0.999975f, 0.999578f, 0.997733f, 0.992296f, 0.979810f, 0.955974f, 0.917293f, 0.863025f, 0.795639f, 0.719578f, 0.639531f, 0.559508f, 0.482585f, 0.410973f, 0.346112f, + 1.000000f, 0.999977f, 0.999610f, 0.997884f, 0.992738f, 0.980875f, 0.958232f, 0.921269f, 0.868446f, 0.801055f, 0.722874f, 0.638931f, 0.554163f, 0.472686f, 0.397447f, 0.330196f, + 1.000000f, 0.999978f, 0.999565f, 0.997403f, 0.991432f, 0.979516f, 0.958528f, 0.924585f, 0.874704f, 0.808512f, 0.728875f, 0.641091f, 0.551264f, 0.464814f, 0.385631f, 0.315904f, + 1.000000f, 0.999980f, 0.999676f, 0.998292f, 0.994295f, 0.985125f, 0.967084f, 0.935829f, 0.887676f, 0.821316f, 0.739011f, 0.646348f, 0.550586f, 0.458535f, 0.375096f, 0.302843f, + + 1.000000f, 0.995284f, 0.998805f, 0.999446f, 0.999652f, 0.999726f, 0.999742f, 0.999726f, 0.999690f, 0.999638f, 0.999573f, 0.999497f, 0.999412f, 0.999319f, 0.999217f, 0.999109f, + 1.000000f, 0.997511f, 0.960278f, 0.900983f, 0.888916f, 0.900587f, 0.912250f, 0.917908f, 0.917495f, 0.912056f, 0.902622f, 0.890032f, 0.874957f, 0.857948f, 0.839453f, 0.819858f, + 1.000000f, 0.999403f, 0.989217f, 0.951216f, 0.904855f, 0.881312f, 0.875855f, 0.874881f, 0.871011f, 0.861890f, 0.847414f, 0.828269f, 0.805342f, 0.779535f, 0.751654f, 0.722409f, + 1.000000f, 0.999735f, 0.995287f, 0.975194f, 0.935480f, 0.895835f, 0.870421f, 0.855571f, 0.843205f, 0.828107f, 0.808210f, 0.783319f, 0.754116f, 0.721610f, 0.686849f, 0.650834f, + 1.000000f, 0.999848f, 0.997350f, 0.985508f, 0.956627f, 0.916439f, 0.879490f, 0.851287f, 0.828198f, 0.805024f, 0.778469f, 0.747390f, 0.712022f, 0.673310f, 0.632463f, 0.590663f, + 1.000000f, 0.999900f, 0.998276f, 0.990513f, 0.969612f, 0.934314f, 0.893516f, 0.855889f, 0.822696f, 0.790800f, 0.756946f, 0.719429f, 0.678072f, 0.633700f, 0.587564f, 0.540993f, + 1.000000f, 0.999928f, 0.998768f, 0.993241f, 0.977633f, 0.947976f, 0.907810f, 0.864886f, 0.823513f, 0.783251f, 0.741884f, 0.697761f, 0.650515f, 0.600848f, 0.550036f, 0.499480f, + 1.000000f, 0.999945f, 0.999060f, 0.994873f, 0.982777f, 0.958041f, 0.920561f, 0.875536f, 0.828257f, 0.780592f, 0.731891f, 0.681116f, 0.628018f, 0.573302f, 0.518254f, 0.464324f, + 1.000000f, 0.999955f, 0.999247f, 0.995921f, 0.986211f, 0.965426f, 0.931295f, 0.886306f, 0.835243f, 0.781429f, 0.725868f, 0.668540f, 0.609650f, 0.550059f, 0.491114f, 0.434261f, + 1.000000f, 0.999962f, 0.999374f, 0.996629f, 0.988590f, 0.970879f, 0.940076f, 0.896375f, 0.843261f, 0.784609f, 0.722845f, 0.659190f, 0.594586f, 0.530250f, 0.467640f, 0.408199f, + 1.000000f, 0.999968f, 0.999465f, 0.997128f, 0.990290f, 0.974955f, 0.947163f, 0.905388f, 0.851522f, 0.789266f, 0.722065f, 0.652422f, 0.582245f, 0.513266f, 0.447157f, 0.385363f, + 1.000000f, 0.999972f, 0.999530f, 0.997493f, 0.991538f, 0.978036f, 0.952836f, 0.913211f, 0.859501f, 0.794737f, 0.722931f, 0.647753f, 0.572188f, 0.498666f, 0.429163f, 0.365186f, + 1.000000f, 0.999975f, 0.999580f, 0.997764f, 0.992463f, 0.980361f, 0.957300f, 0.919782f, 0.866810f, 0.800499f, 0.724974f, 0.644830f, 0.564130f, 0.486139f, 0.413298f, 0.347228f, + 1.000000f, 0.999977f, 0.999617f, 0.997960f, 0.993118f, 0.982006f, 0.960566f, 0.924916f, 0.873094f, 0.806184f, 0.727943f, 0.643492f, 0.557922f, 0.475485f, 0.399271f, 0.331161f, + 1.000000f, 0.999979f, 0.999637f, 0.998017f, 0.993219f, 0.982367f, 0.961927f, 0.928184f, 0.878334f, 0.812034f, 0.732125f, 0.643915f, 0.553566f, 0.466563f, 0.386869f, 0.316698f, + 1.000000f, 0.999980f, 0.999675f, 0.998280f, 0.994216f, 0.984850f, 0.966503f, 0.935014f, 0.886874f, 0.820774f, 0.738841f, 0.646535f, 0.551042f, 0.459158f, 0.375796f, 0.303554f, + + 1.000000f, 0.995284f, 0.998804f, 0.999446f, 0.999652f, 0.999725f, 0.999741f, 0.999725f, 0.999687f, 0.999635f, 0.999569f, 0.999493f, 0.999407f, 0.999312f, 0.999210f, 0.999100f, + 1.000000f, 0.997510f, 0.960272f, 0.900957f, 0.888850f, 0.900465f, 0.912056f, 0.917636f, 0.917129f, 0.911583f, 0.902026f, 0.889301f, 0.874076f, 0.856904f, 0.838235f, 0.818452f, + 1.000000f, 0.999403f, 0.989210f, 0.951184f, 0.904763f, 0.881115f, 0.875512f, 0.874354f, 0.870268f, 0.860899f, 0.846149f, 0.826693f, 0.803430f, 0.777250f, 0.748961f, 0.719274f, + 1.000000f, 0.999734f, 0.995279f, 0.975155f, 0.935366f, 0.895578f, 0.869943f, 0.854786f, 0.842031f, 0.826459f, 0.806013f, 0.780495f, 0.750587f, 0.717288f, 0.681647f, 0.644646f, + 1.000000f, 0.999848f, 0.997346f, 0.985485f, 0.956561f, 0.916289f, 0.879212f, 0.850822f, 0.827497f, 0.804019f, 0.777098f, 0.745565f, 0.709663f, 0.670316f, 0.628717f, 0.586038f, + 1.000000f, 0.999900f, 0.998275f, 0.990505f, 0.969587f, 0.934262f, 0.893425f, 0.855747f, 0.822486f, 0.790499f, 0.756509f, 0.718790f, 0.677140f, 0.632349f, 0.585661f, 0.538386f, + 1.000000f, 0.999928f, 0.998768f, 0.993243f, 0.977639f, 0.947997f, 0.907867f, 0.865006f, 0.823723f, 0.783570f, 0.742296f, 0.698204f, 0.650885f, 0.600994f, 0.549785f, 0.498656f, + 1.000000f, 0.999945f, 0.999060f, 0.994877f, 0.982795f, 0.958102f, 0.920709f, 0.875837f, 0.828783f, 0.781397f, 0.732985f, 0.682444f, 0.629450f, 0.574646f, 0.519295f, 0.464849f, + 1.000000f, 0.999955f, 0.999247f, 0.995925f, 0.986233f, 0.965502f, 0.931491f, 0.886717f, 0.835982f, 0.782584f, 0.727470f, 0.670523f, 0.611850f, 0.552237f, 0.493010f, 0.435639f, + 1.000000f, 0.999962f, 0.999374f, 0.996634f, 0.988615f, 0.970969f, 0.940313f, 0.896884f, 0.844187f, 0.786070f, 0.724876f, 0.661700f, 0.597367f, 0.533012f, 0.470085f, 0.410101f, + 1.000000f, 0.999968f, 0.999465f, 0.997134f, 0.990322f, 0.975066f, 0.947455f, 0.906016f, 0.852661f, 0.791049f, 0.724510f, 0.655390f, 0.585463f, 0.516409f, 0.449926f, 0.387555f, + 1.000000f, 0.999971f, 0.999531f, 0.997501f, 0.991579f, 0.978183f, 0.953219f, 0.914022f, 0.860936f, 0.796914f, 0.725810f, 0.651119f, 0.575713f, 0.502010f, 0.432062f, 0.367489f, + 1.000000f, 0.999975f, 0.999581f, 0.997776f, 0.992527f, 0.980582f, 0.957862f, 0.920918f, 0.868711f, 0.803199f, 0.728318f, 0.648503f, 0.567789f, 0.489490f, 0.416147f, 0.349507f, + 1.000000f, 0.999977f, 0.999620f, 0.997986f, 0.993247f, 0.982427f, 0.961553f, 0.926709f, 0.875746f, 0.809518f, 0.731656f, 0.647247f, 0.561449f, 0.478611f, 0.401907f, 0.333308f, + 1.000000f, 0.999979f, 0.999648f, 0.998134f, 0.993732f, 0.983669f, 0.964160f, 0.931158f, 0.881732f, 0.815571f, 0.735600f, 0.647188f, 0.556541f, 0.469195f, 0.389144f, 0.318641f, + 1.000000f, 0.999980f, 0.999673f, 0.998257f, 0.994093f, 0.984576f, 0.966265f, 0.935152f, 0.887595f, 0.822055f, 0.740532f, 0.648457f, 0.553048f, 0.461141f, 0.377688f, 0.305312f, + + 1.000000f, 0.995284f, 0.998804f, 0.999445f, 0.999651f, 0.999724f, 0.999739f, 0.999722f, 0.999684f, 0.999630f, 0.999563f, 0.999485f, 0.999398f, 0.999302f, 0.999198f, 0.999086f, + 1.000000f, 0.997510f, 0.960267f, 0.900933f, 0.888781f, 0.900318f, 0.911801f, 0.917239f, 0.916567f, 0.910833f, 0.901062f, 0.888105f, 0.872627f, 0.855182f, 0.836220f, 0.816125f, + 1.000000f, 0.999402f, 0.989206f, 0.951160f, 0.904689f, 0.880944f, 0.875182f, 0.873804f, 0.869439f, 0.859739f, 0.844607f, 0.824729f, 0.801003f, 0.774321f, 0.745496f, 0.715236f, + 1.000000f, 0.999734f, 0.995278f, 0.975147f, 0.935339f, 0.895510f, 0.869798f, 0.854523f, 0.841602f, 0.825821f, 0.805121f, 0.779311f, 0.749073f, 0.715413f, 0.679387f, 0.641971f, + 1.000000f, 0.999848f, 0.997346f, 0.985485f, 0.956559f, 0.916282f, 0.879189f, 0.850766f, 0.827382f, 0.803814f, 0.776771f, 0.745088f, 0.708998f, 0.669438f, 0.627598f, 0.584655f, + 1.000000f, 0.999900f, 0.998275f, 0.990506f, 0.969593f, 0.934278f, 0.893458f, 0.855801f, 0.822559f, 0.790580f, 0.756578f, 0.718819f, 0.677102f, 0.632212f, 0.585386f, 0.537943f, + 1.000000f, 0.999928f, 0.998768f, 0.993244f, 0.977646f, 0.948020f, 0.907922f, 0.865112f, 0.823896f, 0.783820f, 0.742617f, 0.698579f, 0.651280f, 0.601369f, 0.550088f, 0.498847f, + 1.000000f, 0.999945f, 0.999060f, 0.994879f, 0.982802f, 0.958127f, 0.920774f, 0.875972f, 0.829021f, 0.781764f, 0.733493f, 0.683077f, 0.630174f, 0.575404f, 0.520024f, 0.465484f, + 1.000000f, 0.999955f, 0.999247f, 0.995927f, 0.986241f, 0.965530f, 0.931565f, 0.886875f, 0.836271f, 0.783048f, 0.728128f, 0.671370f, 0.612838f, 0.553298f, 0.494056f, 0.436595f, + 1.000000f, 0.999962f, 0.999375f, 0.996635f, 0.988624f, 0.971000f, 0.940397f, 0.897068f, 0.844529f, 0.786627f, 0.725678f, 0.662737f, 0.598585f, 0.534315f, 0.471376f, 0.411283f, + 1.000000f, 0.999968f, 0.999465f, 0.997136f, 0.990333f, 0.975103f, 0.947555f, 0.906236f, 0.853072f, 0.791717f, 0.725468f, 0.656617f, 0.586883f, 0.517912f, 0.451388f, 0.388886f, + 1.000000f, 0.999972f, 0.999531f, 0.997504f, 0.991593f, 0.978230f, 0.953348f, 0.914303f, 0.861452f, 0.797735f, 0.726957f, 0.652547f, 0.577323f, 0.503668f, 0.433644f, 0.368907f, + 1.000000f, 0.999975f, 0.999582f, 0.997780f, 0.992547f, 0.980652f, 0.958047f, 0.921309f, 0.869402f, 0.804249f, 0.729712f, 0.650157f, 0.569569f, 0.491256f, 0.417789f, 0.350958f, + 1.000000f, 0.999977f, 0.999620f, 0.997993f, 0.993284f, 0.982553f, 0.961871f, 0.927340f, 0.876772f, 0.810939f, 0.733379f, 0.649135f, 0.563353f, 0.480418f, 0.403550f, 0.334740f, + 1.000000f, 0.999979f, 0.999651f, 0.998159f, 0.993858f, 0.984047f, 0.964963f, 0.932452f, 0.883441f, 0.817541f, 0.737667f, 0.649219f, 0.558458f, 0.470943f, 0.390703f, 0.320005f, + 1.000000f, 0.999980f, 0.999668f, 0.998199f, 0.993985f, 0.984715f, 0.966955f, 0.936405f, 0.889231f, 0.823875f, 0.742384f, 0.650248f, 0.554726f, 0.462681f, 0.379081f, 0.306563f, + + 1.000000f, 0.995284f, 0.998804f, 0.999445f, 0.999650f, 0.999723f, 0.999738f, 0.999720f, 0.999682f, 0.999627f, 0.999560f, 0.999482f, 0.999394f, 0.999297f, 0.999192f, 0.999079f, + 1.000000f, 0.997510f, 0.960266f, 0.900925f, 0.888755f, 0.900262f, 0.911700f, 0.917082f, 0.916341f, 0.910526f, 0.900670f, 0.887614f, 0.872031f, 0.854471f, 0.835387f, 0.815164f, + 1.000000f, 0.999402f, 0.989206f, 0.951159f, 0.904685f, 0.880930f, 0.875151f, 0.873744f, 0.869339f, 0.859591f, 0.844401f, 0.824460f, 0.800665f, 0.773907f, 0.745002f, 0.714660f, + 1.000000f, 0.999734f, 0.995278f, 0.975148f, 0.935340f, 0.895509f, 0.869794f, 0.854510f, 0.841571f, 0.825764f, 0.805031f, 0.779183f, 0.748902f, 0.715194f, 0.679117f, 0.641650f, + 1.000000f, 0.999848f, 0.997346f, 0.985485f, 0.956560f, 0.916285f, 0.879193f, 0.850771f, 0.827383f, 0.803807f, 0.776749f, 0.745046f, 0.708931f, 0.669342f, 0.627471f, 0.584496f, + 1.000000f, 0.999900f, 0.998275f, 0.990507f, 0.969594f, 0.934282f, 0.893466f, 0.855814f, 0.822578f, 0.790603f, 0.756600f, 0.718837f, 0.677111f, 0.632207f, 0.585365f, 0.537902f, + 1.000000f, 0.999928f, 0.998768f, 0.993244f, 0.977647f, 0.948023f, 0.907931f, 0.865129f, 0.823926f, 0.783862f, 0.742672f, 0.698642f, 0.651347f, 0.601434f, 0.550148f, 0.498895f, + 1.000000f, 0.999945f, 0.999060f, 0.994879f, 0.982803f, 0.958131f, 0.920784f, 0.875992f, 0.829057f, 0.781821f, 0.733571f, 0.683176f, 0.630288f, 0.575529f, 0.520149f, 0.465605f, + 1.000000f, 0.999955f, 0.999247f, 0.995927f, 0.986242f, 0.965534f, 0.931575f, 0.886898f, 0.836313f, 0.783116f, 0.728228f, 0.671499f, 0.612995f, 0.553471f, 0.494235f, 0.436771f, + 1.000000f, 0.999962f, 0.999375f, 0.996636f, 0.988625f, 0.971005f, 0.940409f, 0.897095f, 0.844579f, 0.786709f, 0.725799f, 0.662898f, 0.598779f, 0.534532f, 0.471600f, 0.411502f, + 1.000000f, 0.999968f, 0.999465f, 0.997137f, 0.990334f, 0.975108f, 0.947569f, 0.906268f, 0.853132f, 0.791816f, 0.725613f, 0.656809f, 0.587115f, 0.518167f, 0.451652f, 0.389139f, + 1.000000f, 0.999972f, 0.999531f, 0.997504f, 0.991595f, 0.978237f, 0.953366f, 0.914343f, 0.861527f, 0.797858f, 0.727135f, 0.652779f, 0.577593f, 0.503960f, 0.433938f, 0.369185f, + 1.000000f, 0.999975f, 0.999582f, 0.997781f, 0.992550f, 0.980661f, 0.958072f, 0.921364f, 0.869504f, 0.804411f, 0.729938f, 0.650437f, 0.569884f, 0.491585f, 0.418109f, 0.351255f, + 1.000000f, 0.999977f, 0.999620f, 0.997994f, 0.993289f, 0.982570f, 0.961917f, 0.927431f, 0.876930f, 0.811170f, 0.733679f, 0.649480f, 0.563719f, 0.480779f, 0.403887f, 0.335045f, + 1.000000f, 0.999979f, 0.999651f, 0.998163f, 0.993872f, 0.984095f, 0.965078f, 0.932660f, 0.883746f, 0.817923f, 0.738091f, 0.649655f, 0.558875f, 0.471330f, 0.391049f, 0.320309f, + 1.000000f, 0.999980f, 0.999658f, 0.998277f, 0.994324f, 0.985318f, 0.967688f, 0.937159f, 0.889944f, 0.824522f, 0.742959f, 0.650753f, 0.555166f, 0.463063f, 0.379413f, 0.306851f +}; + +static const float table_ggx_glass_inv_Eavg[256] = { + 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f, + 1.000000f, 0.999883f, 0.998571f, 0.994611f, 0.987932f, 0.979340f, 0.969124f, 0.957150f, 0.943358f, 0.927910f, 0.911111f, 0.893347f, 0.875001f, 0.856410f, 0.837886f, 0.819667f, + 1.000000f, 0.999879f, 0.998460f, 0.993636f, 0.983961f, 0.969802f, 0.952851f, 0.934658f, 0.915966f, 0.896938f, 0.877591f, 0.857980f, 0.838240f, 0.818537f, 0.799061f, 0.779987f, + 1.000000f, 0.999877f, 0.998430f, 0.993345f, 0.982442f, 0.964923f, 0.941902f, 0.915671f, 0.888444f, 0.861595f, 0.835705f, 0.810866f, 0.787027f, 0.764116f, 0.742069f, 0.720883f, + 1.000000f, 0.999876f, 0.998425f, 0.993276f, 0.981921f, 0.962787f, 0.936011f, 0.903450f, 0.867828f, 0.831654f, 0.796632f, 0.763575f, 0.732728f, 0.704029f, 0.677271f, 0.652272f, + 1.000000f, 0.999877f, 0.998435f, 0.993313f, 0.981879f, 0.962128f, 0.933439f, 0.896895f, 0.854943f, 0.810510f, 0.766198f, 0.723791f, 0.684211f, 0.647805f, 0.614506f, 0.584089f, + 1.000000f, 0.999877f, 0.998450f, 0.993399f, 0.982078f, 0.962279f, 0.932879f, 0.894276f, 0.848326f, 0.797836f, 0.745795f, 0.694724f, 0.646345f, 0.601608f, 0.560861f, 0.524053f, + 1.000000f, 0.999878f, 0.998470f, 0.993509f, 0.982397f, 0.962854f, 0.933472f, 0.894132f, 0.846118f, 0.791843f, 0.734286f, 0.676340f, 0.620361f, 0.567934f, 0.519922f, 0.476637f, + 1.000000f, 0.999879f, 0.998491f, 0.993625f, 0.982756f, 0.963613f, 0.934645f, 0.895397f, 0.846683f, 0.790470f, 0.729520f, 0.666816f, 0.605085f, 0.546425f, 0.492207f, 0.443121f, + 1.000000f, 0.999880f, 0.998512f, 0.993737f, 0.983113f, 0.964411f, 0.936030f, 0.897312f, 0.848722f, 0.791863f, 0.729200f, 0.663653f, 0.598087f, 0.534951f, 0.475998f, 0.422303f, + 1.000000f, 0.999881f, 0.998529f, 0.993838f, 0.983432f, 0.965152f, 0.937379f, 0.899354f, 0.851322f, 0.794586f, 0.731348f, 0.664390f, 0.596615f, 0.530632f, 0.468483f, 0.411497f, + 1.000000f, 0.999882f, 0.998544f, 0.993921f, 0.983702f, 0.965776f, 0.938551f, 0.901202f, 0.853839f, 0.797572f, 0.734403f, 0.666974f, 0.598137f, 0.530590f, 0.466524f, 0.407467f, + 1.000000f, 0.999883f, 0.998556f, 0.993986f, 0.983909f, 0.966256f, 0.939459f, 0.902655f, 0.855886f, 0.800135f, 0.737288f, 0.669858f, 0.600660f, 0.532400f, 0.467352f, 0.407150f, + 1.000000f, 0.999883f, 0.998565f, 0.994033f, 0.984050f, 0.966579f, 0.940057f, 0.903620f, 0.857258f, 0.801907f, 0.739358f, 0.672075f, 0.602828f, 0.534326f, 0.468867f, 0.408146f, + 1.000000f, 0.999883f, 0.998570f, 0.994058f, 0.984128f, 0.966748f, 0.940358f, 0.904091f, 0.857927f, 0.802767f, 0.740383f, 0.673205f, 0.603988f, 0.535434f, 0.469853f, 0.408957f, + 1.000000f, 0.999883f, 0.998572f, 0.994065f, 0.984146f, 0.966784f, 0.940421f, 0.904186f, 0.858056f, 0.802932f, 0.740578f, 0.673420f, 0.604211f, 0.535654f, 0.470057f, 0.409136f +}; + +CCL_NAMESPACE_END diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp index bdc4abae3ee..fda3e44c9c3 100644 --- a/intern/cycles/scene/shader_nodes.cpp +++ b/intern/cycles/scene/shader_nodes.cpp @@ -2350,7 +2350,7 @@ NODE_DEFINE(GlossyBsdfNode) distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID); distribution_enum.insert("ggx", CLOSURE_BSDF_MICROFACET_GGX_ID); distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID); - distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID); + distribution_enum.insert("multi_ggx", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID); SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID); SOCKET_IN_VECTOR(tangent, "Tangent", zero_float3(), SocketType::LINK_TANGENT); @@ -2444,6 +2444,7 @@ void GlossyBsdfNode::compile(SVMCompiler &compiler) if (closure == CLOSURE_BSDF_REFLECTION_ID) BsdfNode::compile(compiler, NULL, NULL); + /* TODO: Just use weight for legacy MultiGGX? Would also simplify OSL. */ else if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) BsdfNode::compile( compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color")); @@ -2471,7 +2472,7 @@ NODE_DEFINE(GlassBsdfNode) distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID); distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID); 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("multi_ggx", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); SOCKET_ENUM( distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); @@ -2749,8 +2750,8 @@ NODE_DEFINE(PrincipledBsdfNode) NodeType *type = NodeType::add("principled_bsdf", create, NodeType::SHADER); 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("ggx", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); + distribution_enum.insert("multi_ggx", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); SOCKET_ENUM( distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 4646f949413..34f79a80103 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -4752,8 +4752,8 @@ static const EnumPropertyItem node_glossy_items[] = { "MULTI_GGX", 0, "Multiscatter GGX", - "Slower than GGX but gives a more energy conserving results, which would otherwise be " - "visible as excessive darkening"}, + "GGX with additional correction to account for multiple scattering, preserve energy and " + "prevent unexpected darkening at high roughness"}, {0, NULL, 0, NULL, NULL}, }; @@ -4764,8 +4764,8 @@ static const EnumPropertyItem node_glass_items[] = { "MULTI_GGX", 0, "Multiscatter GGX", - "Slower than GGX but gives a more energy conserving results, which would otherwise be " - "visible as excessive darkening"}, + "GGX with additional correction to account for multiple scattering, preserve energy and " + "prevent unexpected darkening at high roughness"}, {0, NULL, 0, NULL, NULL}, };