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 232c959b557d644334ca5e85d9246f341e9e6605
parent 8bbe0f6e6e8682e788633e71db304d2ce4dcc034
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon, 11 Dec 2017 10:38:18 +0100

Add and test the Pillbox microfacet distribution

Diffstat:
Mcmake/CMakeLists.txt | 2++
Msrc/ssf.h | 11++++++++++-
Asrc/ssf_pillbox_distribution.c | 132+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/test_ssf_pillbox_distribution.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 212 insertions(+), 1 deletion(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -62,6 +62,7 @@ set(SSF_FILES_SRC ssf_lambertian_reflection.c ssf_microfacet_distribution.c ssf_microfacet_reflection.c + ssf_pillbox_distribution.c ssf_specular_dielectric_dielectric_interface.c ssf_specular_reflection.c ssf_thin_specular_dielectric.c) @@ -101,6 +102,7 @@ if(NOT NO_TEST) new_test(test_ssf_beckmann_distribution) new_test(test_ssf_blinn_distribution) + new_test(test_ssf_pillbox_distribution) new_test(test_ssf_bsdf) new_test(test_ssf_fresnel) new_test(test_ssf_fresnel_constant) diff --git a/src/ssf.h b/src/ssf.h @@ -255,6 +255,10 @@ SSF_API const struct ssf_microfacet_distribution_type ssf_beckmann_distribution; * with `e' an exponent in [0, SSF_BLINN_DISTRIBUTION_MAX_EXPONENT] */ SSF_API const struct ssf_microfacet_distribution_type ssf_blinn_distribution; +/* Pillbox microfacet distribution. + * D(wh) = */ +SSF_API const struct ssf_microfacet_distribution_type ssf_pillbox_distribution; + /******************************************************************************* * BSDF API - Bidirectional Scattering Distribution Function. Describes the way * the light is scattered by a surface. Note that by convention the outgoing @@ -438,13 +442,18 @@ ssf_microfacet_distribution_get_data SSF_API res_T ssf_beckmann_distribution_setup (struct ssf_microfacet_distribution* distrib, - const double roughness); /* Must be > 0 */ + const double roughness); /* In ]0, 1] */ SSF_API res_T ssf_blinn_distribution_setup (struct ssf_microfacet_distribution* distrib, const double exponent); /* in [0, SSF_BLINN_DISTRIBUTION_MAX_EXPONENT] */ +SSF_API res_T +ssf_pillbox_distribution_setup + (struct ssf_microfacet_distribution* distrib, + const double roughness); /* In ]0, 1] */ + END_DECLS #endif /* SSF_H */ diff --git a/src/ssf_pillbox_distribution.c b/src/ssf_pillbox_distribution.c @@ -0,0 +1,132 @@ +/* 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_microfacet_distribution_c.h" + +#include <rsys/double3.h> +#include <rsys/double33.h> + +#include <star/ssp.h> + +struct pillbox_distribution { + double sin2_theta_max; +}; + +/******************************************************************************* + * Private functions + ******************************************************************************/ +static res_T +pillbox_distribution_init(struct mem_allocator* allocator, void* distrib) +{ + ASSERT(distrib); + (void)allocator; + ((struct pillbox_distribution*)distrib)->sin2_theta_max = 1.0; + return RES_OK; +} + +static void +pillbox_distribution_release(void* distrib) +{ (void)distrib; } + +static double +pillbox_distribution_eval(void* distrib, const double N[3], const double wh[3]) +{ + struct pillbox_distribution* pillbox = distrib; + double cos2_theta_max; + double cos2_wh_N; + ASSERT(distrib && N && wh); + ASSERT(d3_is_normalized(wh) && d3_is_normalized(N)); + cos2_wh_N = d3_dot(N, wh); + cos2_wh_N *= cos2_wh_N; + cos2_theta_max = 1.0 - pillbox->sin2_theta_max; + /* if |wh.N| >= theta_max then 0 + * <=> if cos(|wh.N|)^2 < cos(theta_max)^2 then 0 */ + return (cos2_wh_N >= cos2_theta_max) ? 1.0 / (PI - PI*cos2_theta_max) : 0.0; +} + +static void +pillbox_distribution_sample + (void* distrib, + struct ssp_rng* rng, + const double N[3], + double wh[3], + double* pdf) +{ + struct pillbox_distribution* pillbox = distrib; + double basis[9]; + double dir[3]; + double cos2_theta_max; + double phi, sin2_theta, sin_theta, cos_theta; + ASSERT(rng && wh && N); + ASSERT(d3_is_normalized(N)); + + cos2_theta_max = 1 - pillbox->sin2_theta_max; + sin2_theta = ssp_rng_uniform_double(rng, 0, pillbox->sin2_theta_max); + sin_theta = sqrt(sin2_theta); + cos_theta = sqrt(1 - sin2_theta); + phi = ssp_rng_uniform_double(rng, 0, 2 * PI); + dir[0] = cos(phi) * sin_theta; + dir[1] = sin(phi) * sin_theta; + dir[2] = cos_theta; + d33_muld3(wh, d33_basis(basis, N), dir); + *pdf = cos_theta / (PI-PI*cos2_theta_max); +} + +static double +pillbox_distribution_pdf(void* distrib, const double N[3], const double wh[3]) +{ + struct pillbox_distribution* pillbox = distrib; + double cos_wh_N; + double cos2_wh_N; + double cos2_theta_max; + ASSERT(distrib && N && wh); + ASSERT(d3_is_normalized(wh) && d3_is_normalized(N)); + cos_wh_N = d3_dot(wh, N); + if(cos_wh_N < 0.0) return 0.0; + cos2_theta_max = 1 - pillbox->sin2_theta_max; + cos2_wh_N = cos_wh_N * cos_wh_N; + if(cos2_wh_N < cos2_theta_max) return 0.0; + return cos_wh_N / (PI-PI*cos2_theta_max); +} + +/******************************************************************************* + * Exported symbols + ******************************************************************************/ +const struct ssf_microfacet_distribution_type ssf_pillbox_distribution = { + pillbox_distribution_init, + pillbox_distribution_release, + pillbox_distribution_sample, + pillbox_distribution_eval, + pillbox_distribution_pdf, + sizeof(struct pillbox_distribution), + ALIGNOF(struct pillbox_distribution) +}; + +res_T +ssf_pillbox_distribution_setup + (struct ssf_microfacet_distribution* distrib, + const double roughness) +{ + double sin2_theta_max; + if(!distrib || roughness <= 0 || roughness > 1) return RES_BAD_ARG; + if(!MICROFACET_DISTRIBUTION_TYPE_EQ(&distrib->type, &ssf_pillbox_distribution)) + return RES_BAD_ARG; + sin2_theta_max = sin(roughness); + sin2_theta_max *= sin2_theta_max; + ((struct pillbox_distribution*)distrib->data)->sin2_theta_max = sin2_theta_max; + return RES_OK; +} + diff --git a/src/test_ssf_pillbox_distribution.c b/src/test_ssf_pillbox_distribution.c @@ -0,0 +1,68 @@ +/* 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/>. */ + +#define _POSIX_C_SOURCE 200112L /* nextafter support */ + +#include "ssf.h" +#include "test_ssf_utils.h" + +#include <math.h> + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct ssp_rng* rng; + struct ssf_microfacet_distribution* distrib; + struct ssf_microfacet_distribution* dummy; + const size_t NTESTS = 10; + size_t itest; + (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_microfacet_distribution_create + (&allocator, &ssf_pillbox_distribution, &distrib), RES_OK); + CHECK(ssf_microfacet_distribution_create + (&allocator, &microfacet_dummy, &dummy), RES_OK); + + CHECK(ssf_pillbox_distribution_setup(NULL, -1), RES_BAD_ARG); + CHECK(ssf_pillbox_distribution_setup(distrib, -1), RES_BAD_ARG); + CHECK(ssf_pillbox_distribution_setup(NULL, 0.5), RES_BAD_ARG); + CHECK(ssf_pillbox_distribution_setup(distrib, 0.5), RES_OK); + CHECK(ssf_pillbox_distribution_setup(dummy, 0.5), RES_BAD_ARG); + + CHECK(ssf_pillbox_distribution_setup(distrib, 1), RES_OK); + CHECK(ssf_pillbox_distribution_setup(distrib, nextafter(0, 1)), RES_OK); + CHECK(ssf_pillbox_distribution_setup(distrib, nextafter(1, 2)), RES_BAD_ARG); + CHECK(ssf_pillbox_distribution_setup(distrib, 0), RES_BAD_ARG); + + FOR_EACH(itest, 0, NTESTS) { + const double roughness = nextafter(ssp_rng_canonical(rng), 2); /*in ]0, 1]*/ + CHECK(ssf_pillbox_distribution_setup(distrib, roughness), RES_OK); + check_microfacet_distribution(distrib, rng); + } + + CHECK(ssf_microfacet_distribution_ref_put(distrib), RES_OK); + CHECK(ssf_microfacet_distribution_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; +} +