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 8621fd538153443dd896cf59a3dffb07a8c94595
parent 5f8c118e1ef0ff29b556aad687e2370212b1e3dd
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 28 Sep 2016 15:32:42 +0200

Test the Beckmann microfacet distribution

Diffstat:
Mcmake/CMakeLists.txt | 1+
Msrc/ssf_beckmann_distribution.c | 3++-
Asrc/test_ssf_beckmann_distribution.c | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test_ssf_utils.h | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 171 insertions(+), 1 deletion(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -96,6 +96,7 @@ if(NOT NO_TEST) add_test(${_name} ${_name}) endfunction() + new_test(test_ssf_beckmann_distribution) new_test(test_ssf_bsdf) new_test(test_ssf_bxdf) new_test(test_ssf_fresnel) diff --git a/src/ssf_beckmann_distribution.c b/src/ssf_beckmann_distribution.c @@ -81,8 +81,9 @@ beckmann_distribution_sample ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); (void)wo; - m2 = beckmann->roughness * beckmann->roughness; + phi = 2.0*PI*u; + m2 = beckmann->roughness * beckmann->roughness; sin_theta_T = sqrt(-log(v)); cos_theta_T = sqrt(1.0/m2); rcp_T = 1.0 / sqrt(cos_theta_T*cos_theta_T + sin_theta_T*sin_theta_T); diff --git a/src/test_ssf_beckmann_distribution.c b/src/test_ssf_beckmann_distribution.c @@ -0,0 +1,85 @@ +/* Copyright (C) |Meso|Star> 2016 (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" + +int +main(int argc, char** argv) +{ + struct mem_allocator allocator; + struct ssf_microfacet_distribution* distrib; + struct ssf_microfacet_distribution* dummy; + double N[3], wo[3]; + double sum, sum_sqr; + double E, V, SE; + const size_t NSTEPS = 10000; + size_t i; + (void)argc, (void)argv; + + mem_init_proxy_allocator(&allocator, &mem_default_allocator); + + CHECK(ssf_microfacet_distribution_create + (&allocator, &ssf_beckmann_distribution, &distrib), RES_OK); + CHECK(ssf_microfacet_distribution_create + (&allocator, &microfacet_dummy, &dummy), RES_OK); + + CHECK(ssf_beckmann_distribution_setup(NULL, -1), RES_BAD_ARG); + CHECK(ssf_beckmann_distribution_setup(distrib, -1), RES_BAD_ARG); + CHECK(ssf_beckmann_distribution_setup(NULL, 0.5), RES_BAD_ARG); + CHECK(ssf_beckmann_distribution_setup(distrib, 0.5), RES_OK); + CHECK(ssf_beckmann_distribution_setup(dummy, 0.5), RES_BAD_ARG); + + /* Check that D(wh) is normalized wrt \int_{2PI} D(wh) |wh.n| dwh */ + d3(N, 0, 0, 1); + ran_hemisphere_cos(N, wo, NULL); + sum = sum_sqr = 0; + FOR_EACH(i, 0, NSTEPS) { + double wh[3], pdf; + double D, weight; + ran_hemisphere_cos(N, wh, &pdf); + D = ssf_microfacet_distribution_eval(distrib, wo, N, wh); + weight = D * d3_dot(wh, N) / pdf; + sum += weight; + sum_sqr += weight*weight; + + } + E = sum / (double)NSTEPS; + V = sum_sqr / (double)NSTEPS - E*E; + SE = sqrt(V/(double)NSTEPS); + CHECK(eq_eps(E, 1.0, SE), 1); + + /* Check the sampling of a direction wh and the returned pdf */ + sum = sum_sqr = 0; + FOR_EACH(i, 0, NSTEPS) { + const double u = rand_canonic(); + const double v = rand_canonic(); + double wh[3], pdf; + double D, weight; + + ssf_microfacet_distribution_sample(distrib, u, v, wo, N, wh, &pdf); + D = ssf_microfacet_distribution_eval(distrib, wo, N, wh); + weight = D * d3_dot(wh, N) / pdf; + CHECK(eq_eps(weight, 1, 1.e-6), 1); + } + + CHECK(ssf_microfacet_distribution_ref_put(distrib), RES_OK); + CHECK(ssf_microfacet_distribution_ref_put(dummy), RES_OK); + + check_memory_allocator(&allocator); + mem_shutdown_proxy_allocator(&allocator); + CHECK(mem_allocated_size(), 0); + return 0; +} diff --git a/src/test_ssf_utils.h b/src/test_ssf_utils.h @@ -16,6 +16,8 @@ #ifndef TEST_SSF_UTILS_H #define TEST_SSF_UTILS_H +#include <rsys/double33.h> +#include <rsys/math.h> #include <rsys/mem_allocator.h> #include <stdio.h> @@ -121,6 +123,66 @@ static const struct ssf_fresnel_type fresnel_dummy = { }; /******************************************************************************* + * Dummy microfacet distribution type + ******************************************************************************/ +static res_T +microfacet_dummy_init(struct mem_allocator* allocator, void* distrib) +{ + (void)allocator, (void)distrib; + return RES_OK; +} + +static void +microfacet_dummy_release(void* distrib) +{ + (void)distrib; +} + +static void +microfacet_dummy_sample + (void* distrib, + const double u, + const double v, + const double w[3], + const double N[3], + double dir[3], + double* pdf) +{ + (void)distrib, (void)u, (void)v, (void)w, (void)N, (void)dir, (void)pdf; +} + +static double +microfacet_dummy_eval + (void* distrib, + const double wo[3], + const double N[3], + const double wi[3]) +{ + (void)distrib, (void)wo, (void)N, (void)wi; + return 0.0; +} + +static double +microfacet_dummy_pdf + (void* distrib, + const double wo[3], + const double N[3], + const double wi[3]) +{ + (void)distrib, (void)wo, (void)N, (void)wi; + return 0.0; +} + +static const struct ssf_microfacet_distribution_type microfacet_dummy = { + microfacet_dummy_init, + microfacet_dummy_release, + microfacet_dummy_sample, + microfacet_dummy_eval, + microfacet_dummy_pdf, + 0, 1 +}; + +/******************************************************************************* * Miscellaneous functions ******************************************************************************/ static INLINE double @@ -129,6 +191,27 @@ rand_canonic(void) return (double)rand()/(double)RAND_MAX; } +static INLINE double* +ran_hemisphere_cos + (const double N[3], + double dir[3], + double *pdf) +{ + const double u = rand_canonic(); + const double v = rand_canonic(); + const double phi = 2.0 * PI * u; + const double cos_theta = sqrt(v); + const double sin_theta = sqrt(1.0 - v); + double basis[9]; + double tmp[3]; + tmp[0] = cos(phi) * sin_theta; + tmp[1] = sin(phi) * sin_theta; + tmp[2] = cos_theta; + d33_muld3(dir, d33_basis(basis, N), tmp); + if(pdf) *pdf = cos_theta / PI; + return dir; +} + static INLINE void check_memory_allocator(struct mem_allocator* allocator) {