Cycles: Remove MultiGGX code, replace with albedo scaling #107958

Merged
Lukas Stockner merged 8 commits from LukasStockner/blender:remove-multiggx into main 2023-06-05 02:21:03 +02:00
24 changed files with 1294 additions and 1826 deletions

View File

@ -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)

View File

@ -119,3 +119,22 @@ if(WITH_CYCLES_STANDALONE)
$<TARGET_FILE:cycles>
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
$<TARGET_FILE:cycles_precompute>
DESTINATION ${CMAKE_INSTALL_PREFIX})
endif()

View File

@ -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 <iostream>
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<float(float, float, float, float3)> evaluation;
};
static bool cycles_precompute(std::string name)
{
std::map<string, PrecomputeTerm> 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<float> 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;
}

View File

@ -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

View File

@ -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:

View File

@ -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<MicrofacetType::GGX>(sc, Ng, wi, wo, pdf);
ccl_private const MicrofacetBsdf *bsdf = (ccl_private const MicrofacetBsdf *)sc;
return bsdf->energy_scale * bsdf_microfacet_eval<MicrofacetType::GGX>(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<MicrofacetType::GGX>(
int label = bsdf_microfacet_sample<MicrofacetType::GGX>(
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:

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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,

View File

@ -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)

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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(

View File

@ -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,

View File

@ -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);

View File

@ -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

View File

@ -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<float> entries(table, table + n);
bsdf_tables[table] = scene->lookup_tables->add_table(dscene, entries);
}
return bsdf_tables[table];
}
CCL_NAMESPACE_END

View File

@ -233,6 +233,15 @@ class ShaderManager {
static thread_mutex lookup_table_mutex;
unordered_map<const float *, size_t> bsdf_tables;
template<std::size_t n>
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_;

View File

@ -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

View File

@ -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);

View File

@ -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},
};