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 b01aea4e75394c4a4ec7b7123a76a1b98ce50638
parent 74cdf4cf0cc81459ed3649201e146a54142d5e1f
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 22 Mar 2017 09:39:43 +0100

Add and test the specular transmission BTDF

Diffstat:
Mcmake/CMakeLists.txt | 2++
Msrc/ssf.h | 21+++++++++++----------
Asrc/ssf_specular_transmission.c | 118+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_ssf_specular_transmission.c | 97+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 228 insertions(+), 10 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -64,6 +64,7 @@ set(SSF_FILES_SRC ssf_microfacet_distribution.c ssf_microfacet_reflection.c ssf_specular_reflection.c + ssf_specular_transmission.c ssf_thin_specular_dielectric.c) rcmake_prepend_path(SSF_FILES_SRC ${SSF_SOURCE_DIR}) rcmake_prepend_path(SSF_FILES_INC ${SSF_SOURCE_DIR}) @@ -112,6 +113,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_specular_transmission) new_test(test_ssf_thin_specular_dielectric) rcmake_copy_runtime_libraries(test_ssf_beckmann_distribution) diff --git a/src/ssf.h b/src/ssf.h @@ -192,18 +192,13 @@ SSF_API const struct ssf_bxdf_type ssf_microfacet2_reflection; * 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 */ + * radiation. The absorption coefficient "alpha" of the material is provided + * by the user. */ SSF_API const struct ssf_bxdf_type ssf_thin_specular_dielectric; +/* TODO comment me */ +SSF_API const struct ssf_bxdf_type ssf_specular_transmission; + /******************************************************************************* * Built-in Fresnel terms ******************************************************************************/ @@ -379,6 +374,12 @@ ssf_thin_specular_dielectric_setup const double eta_t, /* Refraction id of the thin dielectric slab */ const double thickness); /* Thickness of the slab */ +SSF_API res_T +ssf_specular_transmission_setup + (struct ssf_bxdf* data, + const double eta_i, /* Refraction id of the medium the ray travels in */ + const double eta_t); /* Refraction id of the opposite medium */ + /******************************************************************************* * Fresnel API - Define the equation of the fresnel term ******************************************************************************/ diff --git a/src/ssf_specular_transmission.c b/src/ssf_specular_transmission.c @@ -0,0 +1,118 @@ +/* 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> + +struct specular_transmission { + struct ssf_fresnel* fresnel; + double eta_i, eta_t; +}; + +/******************************************************************************* + * Private functions + ******************************************************************************/ +static res_T +specular_transmission_init + (struct mem_allocator* allocator, void* bxdf) +{ + struct specular_transmission* btdf = bxdf; + ASSERT(btdf); + return ssf_fresnel_create + (allocator, &ssf_fresnel_dielectric_dielectric, &btdf->fresnel); +} + +static void +specular_transmission_release(void* bxdf) +{ + struct specular_transmission* btdf = bxdf; + ASSERT(btdf); + if(btdf->fresnel) SSF(fresnel_ref_put(btdf->fresnel)); +} + +static double +specular_transmission_sample + (void* bxdf, + struct ssp_rng* rng, + const double wo[3], + const double N[3], + double wi[3], + double* pdf) +{ + struct specular_transmission* btdf = bxdf; + double eta; + double cos_wi_N; + ASSERT(rng && wo && N && wi && pdf); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(wo, N) > 0); + (void)rng; + + SSF(fresnel_dielectric_dielectric_setup + (btdf->fresnel, btdf->eta_t, btdf->eta_i)); + + eta = btdf->eta_i / btdf->eta_t; + if(!refract(wi, wo, N, eta)) { /* Total internal reflection */ + reflect(wi, wo, N); /* TODO ensure this */ + return 0.0; + } + cos_wi_N = d3_dot(wi, N); + *pdf = INF; + return 1.0 - ssf_fresnel_eval(btdf->fresnel, fabs(cos_wi_N)); +} + +static double +specular_transmission_eval + (void* data, const double wo[3], const double N[3], const double wi[3]) +{ + (void)data, (void)wi, (void)N, (void)wo; + return 0.0; +} + +static double +specular_transmission_pdf + (void* data, const double wo[3], const double N[3], const double wi[3]) +{ + (void)data, (void)wi, (void)N, (void)wo; + return 0.0; +} + +/******************************************************************************* + * Exported symbols + ******************************************************************************/ +const struct ssf_bxdf_type ssf_specular_transmission = { + specular_transmission_init, + specular_transmission_release, + specular_transmission_sample, + specular_transmission_eval, + specular_transmission_pdf, + sizeof(struct specular_transmission), + ALIGNOF(struct specular_transmission) +}; + +res_T +ssf_specular_transmission_setup + (struct ssf_bxdf* bxdf, const double eta_i, const double eta_t) +{ + struct specular_transmission* btdf; + if(!bxdf || eta_i <= 0 || eta_t <= 0) return RES_BAD_ARG; + if(!BXDF_TYPE_EQ(&bxdf->type, &ssf_specular_transmission)) return RES_BAD_ARG; + btdf = bxdf->data; + btdf->eta_i = eta_i; + btdf->eta_t = eta_t; + return RES_OK; +} + diff --git a/src/test_ssf_specular_transmission.c b/src/test_ssf_specular_transmission.c @@ -0,0 +1,97 @@ +/* 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_optics.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* btdf; + struct ssf_bxdf* dummy; + struct ssf_fresnel* fresnel; + double wo[3], wi[3], tmp[3]; + double N[3]; + double pdf; + double R; + (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_specular_transmission, &btdf), RES_OK); + CHECK(ssf_bxdf_create(&allocator, &bxdf_dummy, &dummy), RES_OK); + CHECK(ssf_fresnel_create + (&allocator, &ssf_fresnel_dielectric_dielectric, &fresnel), RES_OK); + CHECK(ssf_fresnel_dielectric_dielectric_setup(fresnel, 1.00027, 1.5), RES_OK); + + CHECK(ssf_specular_transmission_setup(NULL, -1, -1), RES_BAD_ARG); + CHECK(ssf_specular_transmission_setup(btdf, -1, -1), RES_BAD_ARG); + CHECK(ssf_specular_transmission_setup(NULL, 1.00027, -1), RES_BAD_ARG); + CHECK(ssf_specular_transmission_setup(btdf, 1.00027, -1), RES_BAD_ARG); + CHECK(ssf_specular_transmission_setup(NULL, -1, 1.5), RES_BAD_ARG); + CHECK(ssf_specular_transmission_setup(btdf, -1, 1.5), RES_BAD_ARG); + CHECK(ssf_specular_transmission_setup(NULL, 1.00027, 1.5), RES_BAD_ARG); + CHECK(ssf_specular_transmission_setup(btdf, 1.00027, 1.5), RES_OK); + CHECK(ssf_specular_transmission_setup(dummy, 1.00027, 1.5), RES_BAD_ARG); + + d3(N, 0.0, 1.0, 0.0); + d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0)); + R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &pdf); + CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, fabs(d3_dot(N, wi))), 1.e-6), RES_OK); + CHECK(d3_eq_eps(wi, d3_minus(tmp, wo), 1.e-6), 0); + CHECK(wi[1] < 0, 1); + CHECK(IS_INF(pdf), 1); + + CHECK(ssf_bxdf_eval(btdf, wo, N, wi), 0.0); + CHECK(ssf_bxdf_pdf(btdf, wo, N, wi), 0.0); + + d3(wo, 0.0, 1.0, 0.0); + R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &pdf); + CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, fabs(d3_dot(N, wi))), 1.e-6), RES_OK); + CHECK(IS_INF(pdf), 1); + CHECK(d3_eq_eps(wi, d3_minus(tmp, wo), 1.e-6), 1); + + d3_normalize(wo, d3(wo, -1.0, 1.0, 0.0)); + R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &pdf); + reflect(tmp, wi, N); + d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0)); + R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &pdf); + CHECK(d3_eq_eps(wi, tmp, 1.e-6), 1); + + d3_normalize(wo, d3(wo, -1, 1.e-6, 0)); + R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &pdf); + CHECK(eq_eps(R, 0, 1.e-3), 1); + + /* Check total internal reflection */ + CHECK(ssf_specular_transmission_setup(btdf, 1.5, 1.00027), RES_OK); + R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &pdf); + CHECK(eq_eps(R, 0, 1.e-3), 1); + + CHECK(ssf_fresnel_ref_put(fresnel), RES_OK); + CHECK(ssf_bxdf_ref_put(btdf), RES_OK); + CHECK(ssf_bxdf_ref_put(dummy), RES_OK); + CHECK(ssp_rng_ref_put(rng), RES_OK); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +}