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:
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, µfacet_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)
{