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