star-sf

Set of surface and volume scattering functions
git clone git://git.meso-star.fr/star-sf.git
Log | Files | Refs | README | LICENSE

commit 069846d48c0a19086eea3953008e9a1fa6797682
parent cfe84c5d96e733cee2e5b07238c1ed5285751810
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  1 Mar 2017 17:14:01 +0100

Rename ssf_thin_transparent_dielectric in ssf_thin_specular_dielectric

Diffstat:
Mcmake/CMakeLists.txt | 4++--
Msrc/ssf.h | 36+++++++++++++++++++++++++++---------
Asrc/ssf_thin_specular_dielectric.c | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/ssf_thin_transparent_dielectric.c | 168-------------------------------------------------------------------------------
Asrc/test_ssf_thin_specular_dielectric.c | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/test_ssf_thin_transparent_dielectric.c | 123-------------------------------------------------------------------------------
6 files changed, 320 insertions(+), 302 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -65,7 +65,7 @@ set(SSF_FILES_SRC ssf_microfacet_distribution.c ssf_microfacet_reflection.c ssf_specular_reflection.c - ssf_thin_transparent_dielectric.c) + ssf_thin_specular_dielectric.c) rcmake_prepend_path(SSF_FILES_SRC ${SSF_SOURCE_DIR}) rcmake_prepend_path(SSF_FILES_INC ${SSF_SOURCE_DIR}) rcmake_prepend_path(SSF_FILES_INC_API ${SSF_SOURCE_DIR}) @@ -114,7 +114,7 @@ if(NOT NO_TEST) new_test(test_ssf_microfacet_distribution) new_test(test_ssf_microfacet_reflection) new_test(test_ssf_specular_reflection) - new_test(test_ssf_thin_transparent_dielectric) + new_test(test_ssf_thin_specular_dielectric) rcmake_copy_runtime_libraries(test_ssf_beckmann_distribution) endif() diff --git a/src/ssf.h b/src/ssf.h @@ -181,8 +181,28 @@ SSF_API const struct ssf_bxdf_type ssf_microfacet_reflection; * associated directional reflectance */ SSF_API const struct ssf_bxdf_type ssf_microfacet2_reflection; -/* TODO comment me */ -SSF_API const struct ssf_bxdf_type ssf_thin_transparent_dielectric; +/* This BSDF consists in a model of refraction effects within a thin slab of a + * dielectric material, combine with a dirac distribution of the reflection at + * the interfaces as provided by ssf_specular_reflection. Global reflection (R), + * absorption (A) and transmission (T) parameters are computed from the + * infinite series of contributions that come from multiple refraction effects + * within the slab. + * + * Assuming a perfect dielectric material, the Fresnel term provided by + * ssf_fresnel_dielectric_dielectric is used to compute "rho", i.e. the + * reflected part during a single refraction event. But since real materials + * are not ideal dielectrics, the slab is also supposed to absorb incoming + * radiation. The absorption coefficient "alpha" of the material can be either + * provided by the user, or explicitly computed from "kappa", the imaginary + * part of the material's refraction index, when available using: + * alpha = 4*pi*kappa / lambda + * lambda is the wavelength of the radiation inside the slab, computed as + * lambda=lambda_in*n2/n1, with lambda_in the incoming wavelength, n1 and n2 + * being the real parts of the refraction indices respectively outside and + * inside the material. + * + * TODO computing alpha from the kappa is actually not implemented */ +SSF_API const struct ssf_bxdf_type ssf_thin_specular_dielectric; /******************************************************************************* * Built-in Fresnel terms @@ -352,14 +372,12 @@ ssf_microfacet_reflection_setup struct ssf_microfacet_distribution* distrib); SSF_API res_T -ssf_thin_transparent_dielectric_setup +ssf_thin_specular_dielectric_setup (struct ssf_bxdf* data, - const double transmissivity, - /* Refraction id of the medium the incoming ray travels in */ - const double eta_i, - /* Refraction id of the medium the outgoing transmission ray travels in */ - const double eta_t, - const double thickness); + const double absorption, /* In [0, 1] */ + const double eta_i, /* Refraction id of the medium the ray travels in */ + const double eta_t, /* Refraction id of the thin dielectric slab */ + const double thickness); /* Thickness of the slab */ /******************************************************************************* * Fresnel API - Define the equation of the fresnel term diff --git a/src/ssf_thin_specular_dielectric.c b/src/ssf_thin_specular_dielectric.c @@ -0,0 +1,168 @@ +/* Copyright (C) |Meso|Star> 2016-2017 (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "ssf.h" +#include "ssf_bxdf_c.h" +#include "ssf_optics.h" + +#include <rsys/double3.h> +#include <star/ssp.h> + +struct thin_specular_dielectric { + struct ssf_fresnel* fresnel; + double absorption; /* In [0, 1] */ + double eta_i; /* Refractive index of the incoming medium */ + double eta_t; /* Refractive index of the transmissive medium */ + double thickness; +}; + +/******************************************************************************* + * Private functions + ******************************************************************************/ +static res_T +thin_specular_dielectric_init + (struct mem_allocator* allocator, void* bxdf) +{ + struct thin_specular_dielectric* bsdf = bxdf; + ASSERT(bxdf); + return ssf_fresnel_create + (allocator, &ssf_fresnel_dielectric_dielectric, &bsdf->fresnel); +} + +static void +thin_specular_dielectric_release(void* bxdf) +{ + struct thin_specular_dielectric* bsdf = bxdf; + SSF(fresnel_ref_put(bsdf->fresnel)); +} + +static double +thin_specular_dielectric_sample + (void* bxdf, + struct ssp_rng* rng, + const double wo[3], + const double N[3], + double wi[3], + double* pdf) +{ + struct thin_specular_dielectric* bsdf = bxdf; + struct ssf_fresnel* fresnel; + double wt[3], tmp[3]; + double cos_wo_N, cos_wt_N; + double dst; + double eta; /* Ratio of eta_i / eta_t */ + double R, T; + double rho1, rho2, rho2_sqr; + double tau, tau_sqr; + ASSERT(bxdf && rng && wi && N && wo); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); + (void)rng; + + eta = bsdf->eta_i / bsdf->eta_t; + if(!refract(wt, wo, N, eta)) { + d3_splat(wi, 0); /* TODO handle this case */ + return 0; + } + fresnel = bsdf->fresnel; + + cos_wo_N = d3_dot(wo, N); + SSF(fresnel_dielectric_dielectric_setup(fresnel, bsdf->eta_i, bsdf->eta_t)); + rho1 = ssf_fresnel_eval(fresnel, cos_wo_N); + + cos_wt_N = d3_dot(wt, d3_minus(tmp, N)); + SSF(fresnel_dielectric_dielectric_setup(fresnel, bsdf->eta_t, bsdf->eta_i)); + rho2 = ssf_fresnel_eval(fresnel, cos_wt_N); + + dst = bsdf->thickness / cos_wt_N; + tau = exp(-bsdf->absorption * dst); + + tau_sqr = tau * tau; + rho2_sqr = rho2 * rho2; + + R = rho1 + (1-rho1) * (1-rho2) * (rho2 * tau_sqr) / (1 - rho2_sqr*tau_sqr); + T = (tau * (1 - rho1) * ( 1 - rho2)) / (1-tau_sqr*rho2_sqr); +#ifndef NDEBUG + { + const double A = ((1-tau) * (1-rho1)) / (1-rho2*tau); + ASSERT(eq_eps(R + A + T, 1, 1.e-6)); /* Check energy conservation */ + } +#endif + + *pdf = INF; + + /* Importance sample the BTDF wrt R */ + if(ssp_rng_canonical(rng) < R) { /* Sample the reflective part */ + reflect(wi, wo, N); + return 1; + } else { /* Sample the transmissive part */ + d3_minus(wi, wo); + return T; + } +} + +static double +thin_specular_dielectric_eval + (void* bxdf, const double wo[3], const double N[3], const double wi[3]) +{ + (void)bxdf, (void)wo, (void)N, (void)wi; + return 0.0; +} + +static double +thin_specular_dielectric_pdf + (void* bxdf, const double wo[3], const double N[3], const double wi[3]) +{ + (void)bxdf, (void)wo, (void)N, (void)wi; + return 0.0; +} + +/******************************************************************************* + * Exported symbols + ******************************************************************************/ +const struct ssf_bxdf_type ssf_thin_specular_dielectric = { + thin_specular_dielectric_init, + thin_specular_dielectric_release, + thin_specular_dielectric_sample, + thin_specular_dielectric_eval, + thin_specular_dielectric_pdf, + sizeof(struct thin_specular_dielectric), + ALIGNOF(struct thin_specular_dielectric) +}; + +res_T +ssf_thin_specular_dielectric_setup + (struct ssf_bxdf* bxdf, + const double absorption, + const double eta_i, + const double eta_t, + const double thickness) +{ + struct thin_specular_dielectric* bsdf; + + if(!bxdf || thickness <= 0 || eta_i <= 0 || eta_t <= 0 || absorption < 0 + || absorption > 1) + return RES_BAD_ARG; + if(!BXDF_TYPE_EQ(&bxdf->type, &ssf_thin_specular_dielectric)) + return RES_BAD_ARG; + + bsdf = bxdf->data; + + bsdf->absorption = absorption; + bsdf->thickness = thickness; + bsdf->eta_i = eta_i; + bsdf->eta_t = eta_t; + return RES_OK; +} + diff --git a/src/ssf_thin_transparent_dielectric.c b/src/ssf_thin_transparent_dielectric.c @@ -1,168 +0,0 @@ -/* Copyright (C) |Meso|Star> 2016-2017 (contact@meso-star.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "ssf.h" -#include "ssf_bxdf_c.h" -#include "ssf_optics.h" - -#include <rsys/double3.h> -#include <star/ssp.h> - -struct thin_transparent_dielectric { - struct ssf_fresnel* fresnel; - double T; /* Transmissivity in [0, 1] */ - double eta_i; /* Refractive index of the incoming medium */ - double eta_t; /* Refractive index of the transmissive medium */ - double thickness; -}; - -/******************************************************************************* - * Private functions - ******************************************************************************/ -static res_T -thin_transparent_dielectric_init - (struct mem_allocator* allocator, void* bxdf) -{ - struct thin_transparent_dielectric* bsdf = bxdf; - ASSERT(bxdf); - return ssf_fresnel_create - (allocator, &ssf_fresnel_dielectric_dielectric, &bsdf->fresnel); -} - -static void -thin_transparent_dielectric_release(void* bxdf) -{ - struct thin_transparent_dielectric* bsdf = bxdf; - SSF(fresnel_ref_put(bsdf->fresnel)); -} - -static double -thin_transparent_dielectric_sample - (void* bxdf, - struct ssp_rng* rng, - const double wo[3], - const double N[3], - double wi[3], - double* pdf) -{ - struct thin_transparent_dielectric* bsdf = bxdf; - struct ssf_fresnel* fresnel; - double wt[3], tmp[3]; - double cos_wo_N, cos_wt_N; - double dst; - double eta; /* Ratio of eta_i / eta_t */ - double R, T; - double rho1, rho2, rho2_sqr; - double tau, tau_sqr; - ASSERT(bxdf && rng && wi && N && wo); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); - (void)rng; - - eta = bsdf->eta_i / bsdf->eta_t; - if(!refract(wt, wo, N, eta)) { - d3_splat(wi, 0); /* TODO handle this case */ - return 0; - } - fresnel = bsdf->fresnel; - - cos_wo_N = d3_dot(wo, N); - SSF(fresnel_dielectric_dielectric_setup(fresnel, bsdf->eta_i, bsdf->eta_t)); - rho1 = ssf_fresnel_eval(fresnel, cos_wo_N); - - cos_wt_N = d3_dot(wt, d3_minus(tmp, N)); - SSF(fresnel_dielectric_dielectric_setup(fresnel, bsdf->eta_t, bsdf->eta_i)); - rho2 = ssf_fresnel_eval(fresnel, cos_wt_N); - - dst = bsdf->thickness / cos_wt_N; - tau = exp(-bsdf->T * dst); - - tau_sqr = tau * tau; - rho2_sqr = rho2 * rho2; - - R = rho1 + (1-rho1) * (1-rho2) * (rho2 * tau_sqr) / (1 - rho2_sqr*tau_sqr); - T = (tau * (1 - rho1) * ( 1 - rho2)) / (1-tau_sqr*rho2_sqr); -#ifndef NDEBUG - { - const double A = ((1-tau) * (1-rho1)) / (1-rho2*tau); - ASSERT(eq_eps(R + A + T, 1, 1.e-6)); /* Check energy conservation */ - } -#endif - - *pdf = INF; - - /* Importance sample the BTDF wrt R */ - if(ssp_rng_canonical(rng) < R) { /* Sample the reflective part */ - reflect(wi, wo, N); - return 1; - } else { /* Sample the transmissive part */ - d3_minus(wi, wo); - return T; - } -} - -static double -thin_transparent_dielectric_eval - (void* bxdf, const double wo[3], const double N[3], const double wi[3]) -{ - (void)bxdf, (void)wo, (void)N, (void)wi; - return 0.0; -} - -static double -thin_transparent_dielectric_pdf - (void* bxdf, const double wo[3], const double N[3], const double wi[3]) -{ - (void)bxdf, (void)wo, (void)N, (void)wi; - return 0.0; -} - -/******************************************************************************* - * Exported symbols - ******************************************************************************/ -const struct ssf_bxdf_type ssf_thin_transparent_dielectric = { - thin_transparent_dielectric_init, - thin_transparent_dielectric_release, - thin_transparent_dielectric_sample, - thin_transparent_dielectric_eval, - thin_transparent_dielectric_pdf, - sizeof(struct thin_transparent_dielectric), - ALIGNOF(struct thin_transparent_dielectric) -}; - -res_T -ssf_thin_transparent_dielectric_setup - (struct ssf_bxdf* bxdf, - const double transmissivity, - const double eta_i, - const double eta_t, - const double thickness) -{ - struct thin_transparent_dielectric* bsdf; - - if(!bxdf || thickness <= 0 || eta_i <= 0 || eta_t <= 0 || transmissivity < 0 - || transmissivity > 1) - return RES_BAD_ARG; - if(!BXDF_TYPE_EQ(&bxdf->type, &ssf_thin_transparent_dielectric)) - return RES_BAD_ARG; - - bsdf = bxdf->data; - - bsdf->T = transmissivity; - bsdf->thickness = thickness; - bsdf->eta_i = eta_i; - bsdf->eta_t = eta_t; - return RES_OK; -} - diff --git a/src/test_ssf_thin_specular_dielectric.c b/src/test_ssf_thin_specular_dielectric.c @@ -0,0 +1,123 @@ +/* Copyright (C) |Meso|Star> 2016-2017 (contact@meso-star.com) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "ssf.h" +#include "test_ssf_utils.h" + +#include <rsys/double3.h> + +int +main(int argc, char** argv) +{ + const size_t NSTEPS = 100000; + struct mem_allocator allocator; + struct ssp_rng* rng; + struct ssf_bxdf* bsdf; + struct ssf_bxdf* dummy; + double wo[3], wi[3]; + double N[3]; + double tmp[3]; + double reflect[3]; + double refract[3]; + double pdf; + double R; /* Directional reflectance */ + size_t i; + (void)argc, (void)argv; + + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); + CHECK(ssf_bxdf_create + (&allocator, &ssf_thin_specular_dielectric, &bsdf), RES_OK); + CHECK(ssf_bxdf_create(&allocator, &bxdf_dummy, &dummy), RES_OK); + + #define SETUP ssf_thin_specular_dielectric_setup + CHECK(SETUP(NULL, -1, 0, 0, -1), RES_BAD_ARG); + CHECK(SETUP(bsdf, -1, 0, 0, -1), RES_BAD_ARG); + CHECK(SETUP(NULL, 1, 0, 0, -1), RES_BAD_ARG); + CHECK(SETUP(bsdf, 1, 0, 0, -1), RES_BAD_ARG); + CHECK(SETUP(NULL, -1, 1.00027, 0, -1), RES_BAD_ARG); + CHECK(SETUP(bsdf, -1, 1.00027, 0, -1), RES_BAD_ARG); + CHECK(SETUP(NULL, 1, 1.00027, 0, -1), RES_BAD_ARG); + CHECK(SETUP(bsdf, 1, 1.00027, 0, -1), RES_BAD_ARG); + CHECK(SETUP(NULL, -1, 0, 1.5, -1), RES_BAD_ARG); + CHECK(SETUP(bsdf, -1, 0, 1.5, -1), RES_BAD_ARG); + CHECK(SETUP(NULL, 1, 0, 1.5, -1), RES_BAD_ARG); + CHECK(SETUP(bsdf, 1, 0, 1.5, -1), RES_BAD_ARG); + CHECK(SETUP(NULL, -1, 1.00027, 1.5, -1), RES_BAD_ARG); + CHECK(SETUP(bsdf, -1, 1.00027, 1.5, -1), RES_BAD_ARG); + CHECK(SETUP(NULL, 1, 1.00027, 1.5, -1), RES_BAD_ARG); + CHECK(SETUP(bsdf, 1, 1.00027, 1.5, -1), RES_BAD_ARG); + CHECK(SETUP(NULL, -1, 0, 0, 0.1), RES_BAD_ARG); + CHECK(SETUP(bsdf, -1, 0, 0, 0.1), RES_BAD_ARG); + CHECK(SETUP(NULL, 1, 0, 0, 0.1), RES_BAD_ARG); + CHECK(SETUP(bsdf, 1, 0, 0, 0.1), RES_BAD_ARG); + CHECK(SETUP(NULL, -1, 1.00027, 0, 0.1), RES_BAD_ARG); + CHECK(SETUP(bsdf, -1, 1.00027, 0, 0.1), RES_BAD_ARG); + CHECK(SETUP(NULL, 1, 1.00027, 0, 0.1), RES_BAD_ARG); + CHECK(SETUP(bsdf, 1, 1.00027, 0, 0.1), RES_BAD_ARG); + CHECK(SETUP(NULL, -1, 0, 1.5, 0.1), RES_BAD_ARG); + CHECK(SETUP(bsdf, -1, 0, 1.5, 0.1), RES_BAD_ARG); + CHECK(SETUP(NULL, 1, 0, 1.5, 0.1), RES_BAD_ARG); + CHECK(SETUP(bsdf, 1, 0, 1.5, 0.1), RES_BAD_ARG); + CHECK(SETUP(NULL, -1, 1.00027, 1.5, 0.1), RES_BAD_ARG); + CHECK(SETUP(bsdf, -1, 1.00027, 1.5, 0.1), RES_BAD_ARG); + CHECK(SETUP(NULL, 1, 1.00027, 1.5, 0.1), RES_BAD_ARG); + CHECK(SETUP(bsdf, 1, 1.00027, 1.5, 0.1), RES_OK); + CHECK(SETUP(dummy, 1, 1.00027, 1.5, 0.1), RES_BAD_ARG); + #undef SETUP + + d3(N, 0.0, 1.0, 0.0); + d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0)); + R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &pdf); + NCHECK(R, 0); + CHECK(IS_INF(pdf), 1); + CHECK(d3_eq_eps(wi, d3(tmp, -wo[0], wo[1], 0), 1.e-6) + || d3_eq_eps(wi, d3(tmp, -wo[0], -wo[1], 0), 1.e-6), 1); + + CHECK(ssf_bxdf_eval(bsdf, wo, N, wi), 0.0); + CHECK(ssf_bxdf_pdf(bsdf, wo, N, wi), 0.0); + + d3(wo, 0.0, 1.0, 0.0); + R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &pdf); + NCHECK(R, 0); + CHECK(IS_INF(pdf), 1); + CHECK(d3_eq_eps(wi, d3(tmp, -wo[0], -wo[1], 0), 1.e-6), 1); + + d3(wo, 1.0, 0.0, 0.0); + R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &pdf); + NCHECK(R, 0); + CHECK(IS_INF(pdf), 1); + CHECK(d3_eq_eps(wi, d3(tmp, -wo[0], wo[1], 0), 1.e-6), 1); + + wo[0] = ssp_rng_uniform_double(rng, -1, 1); + wo[1] = ssp_rng_uniform_double(rng, -1, 1); + wo[2] = ssp_rng_uniform_double(rng, -1, 1); + d3_normalize(wo, wo); + d3_sub(reflect, d3_muld(reflect, N, 2*d3_dot(wo, N)), wo); + d3_minus(refract, wo); + + FOR_EACH(i, 0, NSTEPS) { + R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &pdf); + NCHECK(R, 0); + CHECK(IS_INF(pdf), 1); + CHECK(d3_eq_eps(wi, reflect, 1.e-6) || d3_eq_eps(wi, refract, 1e-6), 1); + } + + CHECK(ssp_rng_ref_put(rng), RES_OK); + CHECK(ssf_bxdf_ref_put(bsdf), RES_OK); + CHECK(ssf_bxdf_ref_put(dummy), RES_OK); + + return 0; +} diff --git a/src/test_ssf_thin_transparent_dielectric.c b/src/test_ssf_thin_transparent_dielectric.c @@ -1,123 +0,0 @@ -/* Copyright (C) |Meso|Star> 2016-2017 (contact@meso-star.com) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#include "ssf.h" -#include "test_ssf_utils.h" - -#include <rsys/double3.h> - -int -main(int argc, char** argv) -{ - const size_t NSTEPS = 100000; - struct mem_allocator allocator; - struct ssp_rng* rng; - struct ssf_bxdf* bsdf; - struct ssf_bxdf* dummy; - double wo[3], wi[3]; - double N[3]; - double tmp[3]; - double reflect[3]; - double refract[3]; - double pdf; - double R; /* Directional reflectance */ - size_t i; - (void)argc, (void)argv; - - mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK); - CHECK(ssf_bxdf_create - (&allocator, &ssf_thin_transparent_dielectric, &bsdf), RES_OK); - CHECK(ssf_bxdf_create(&allocator, &bxdf_dummy, &dummy), RES_OK); - - #define SETUP ssf_thin_transparent_dielectric_setup - CHECK(SETUP(NULL, -1, 0, 0, -1), RES_BAD_ARG); - CHECK(SETUP(bsdf, -1, 0, 0, -1), RES_BAD_ARG); - CHECK(SETUP(NULL, 1, 0, 0, -1), RES_BAD_ARG); - CHECK(SETUP(bsdf, 1, 0, 0, -1), RES_BAD_ARG); - CHECK(SETUP(NULL, -1, 1.00027, 0, -1), RES_BAD_ARG); - CHECK(SETUP(bsdf, -1, 1.00027, 0, -1), RES_BAD_ARG); - CHECK(SETUP(NULL, 1, 1.00027, 0, -1), RES_BAD_ARG); - CHECK(SETUP(bsdf, 1, 1.00027, 0, -1), RES_BAD_ARG); - CHECK(SETUP(NULL, -1, 0, 1.5, -1), RES_BAD_ARG); - CHECK(SETUP(bsdf, -1, 0, 1.5, -1), RES_BAD_ARG); - CHECK(SETUP(NULL, 1, 0, 1.5, -1), RES_BAD_ARG); - CHECK(SETUP(bsdf, 1, 0, 1.5, -1), RES_BAD_ARG); - CHECK(SETUP(NULL, -1, 1.00027, 1.5, -1), RES_BAD_ARG); - CHECK(SETUP(bsdf, -1, 1.00027, 1.5, -1), RES_BAD_ARG); - CHECK(SETUP(NULL, 1, 1.00027, 1.5, -1), RES_BAD_ARG); - CHECK(SETUP(bsdf, 1, 1.00027, 1.5, -1), RES_BAD_ARG); - CHECK(SETUP(NULL, -1, 0, 0, 0.1), RES_BAD_ARG); - CHECK(SETUP(bsdf, -1, 0, 0, 0.1), RES_BAD_ARG); - CHECK(SETUP(NULL, 1, 0, 0, 0.1), RES_BAD_ARG); - CHECK(SETUP(bsdf, 1, 0, 0, 0.1), RES_BAD_ARG); - CHECK(SETUP(NULL, -1, 1.00027, 0, 0.1), RES_BAD_ARG); - CHECK(SETUP(bsdf, -1, 1.00027, 0, 0.1), RES_BAD_ARG); - CHECK(SETUP(NULL, 1, 1.00027, 0, 0.1), RES_BAD_ARG); - CHECK(SETUP(bsdf, 1, 1.00027, 0, 0.1), RES_BAD_ARG); - CHECK(SETUP(NULL, -1, 0, 1.5, 0.1), RES_BAD_ARG); - CHECK(SETUP(bsdf, -1, 0, 1.5, 0.1), RES_BAD_ARG); - CHECK(SETUP(NULL, 1, 0, 1.5, 0.1), RES_BAD_ARG); - CHECK(SETUP(bsdf, 1, 0, 1.5, 0.1), RES_BAD_ARG); - CHECK(SETUP(NULL, -1, 1.00027, 1.5, 0.1), RES_BAD_ARG); - CHECK(SETUP(bsdf, -1, 1.00027, 1.5, 0.1), RES_BAD_ARG); - CHECK(SETUP(NULL, 1, 1.00027, 1.5, 0.1), RES_BAD_ARG); - CHECK(SETUP(bsdf, 1, 1.00027, 1.5, 0.1), RES_OK); - CHECK(SETUP(dummy, 1, 1.00027, 1.5, 0.1), RES_BAD_ARG); - #undef SETUP - - d3(N, 0.0, 1.0, 0.0); - d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0)); - R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &pdf); - NCHECK(R, 0); - CHECK(IS_INF(pdf), 1); - CHECK(d3_eq_eps(wi, d3(tmp, -wo[0], wo[1], 0), 1.e-6) - || d3_eq_eps(wi, d3(tmp, -wo[0], -wo[1], 0), 1.e-6), 1); - - CHECK(ssf_bxdf_eval(bsdf, wo, N, wi), 0.0); - CHECK(ssf_bxdf_pdf(bsdf, wo, N, wi), 0.0); - - d3(wo, 0.0, 1.0, 0.0); - R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &pdf); - NCHECK(R, 0); - CHECK(IS_INF(pdf), 1); - CHECK(d3_eq_eps(wi, d3(tmp, -wo[0], -wo[1], 0), 1.e-6), 1); - - d3(wo, 1.0, 0.0, 0.0); - R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &pdf); - NCHECK(R, 0); - CHECK(IS_INF(pdf), 1); - CHECK(d3_eq_eps(wi, d3(tmp, -wo[0], wo[1], 0), 1.e-6), 1); - - wo[0] = ssp_rng_uniform_double(rng, -1, 1); - wo[1] = ssp_rng_uniform_double(rng, -1, 1); - wo[2] = ssp_rng_uniform_double(rng, -1, 1); - d3_normalize(wo, wo); - d3_sub(reflect, d3_muld(reflect, N, 2*d3_dot(wo, N)), wo); - d3_minus(refract, wo); - - FOR_EACH(i, 0, NSTEPS) { - R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &pdf); - NCHECK(R, 0); - CHECK(IS_INF(pdf), 1); - CHECK(d3_eq_eps(wi, reflect, 1.e-6) || d3_eq_eps(wi, refract, 1e-6), 1); - } - - CHECK(ssp_rng_ref_put(rng), RES_OK); - CHECK(ssf_bxdf_ref_put(bsdf), RES_OK); - CHECK(ssf_bxdf_ref_put(dummy), RES_OK); - - return 0; -}