commit a8ebdb94c0b0ac38131818a4c6ddc8c569212541
parent b81ccffe8f2cb5674edce6e6f22c114129b003f7
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 20 Sep 2016 16:05:44 +0200
Add and test the lambertian BRDF
Diffstat:
6 files changed, 230 insertions(+), 6 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -58,6 +58,7 @@ set(SSF_FILES_SRC
ssf_fresnel_dielectric_conductor.c
ssf_fresnel_dielectric_dielectric.c
ssf_fresnel_no_op.c
+ ssf_lambertian_reflection.c
ssf_specular_reflection.c)
rcmake_prepend_path(SSF_FILES_SRC ${SSF_SOURCE_DIR})
rcmake_prepend_path(SSF_FILES_INC ${SSF_SOURCE_DIR})
@@ -100,6 +101,7 @@ if(NOT NO_TEST)
new_test(test_ssf_fresnel_dielectric_conductor)
new_test(test_ssf_fresnel_dielectric_dielectric)
new_test(test_ssf_fresnel_no_op)
+ new_test(test_ssf_lambertian_reflection)
new_test(test_ssf_specular_reflection)
endif()
diff --git a/src/ssf.h b/src/ssf.h
@@ -96,6 +96,8 @@ BEGIN_DECLS
/* Reflects the incoming direction with respect to the surface normal */
SSF_API const struct ssf_bxdf_type ssf_specular_reflection;
+/* Reflects the same intensity independent of the incoming direction */
+SSF_API const struct ssf_bxdf_type ssf_lambertian_reflection;
/* Glossy reflections with respect to a microfacet distribution */
SSF_API const struct ssf_bxdf_type ssf_microfacet_reflection;
@@ -270,6 +272,11 @@ ssf_specular_reflection_setup
(struct ssf_bxdf* bxdf,
const double reflectivity);
+SSF_API res_T
+ssf_lambertian_reflection_setup
+ (struct ssf_bxdf* bxdf,
+ const double reflectivity);
+
END_DECLS
#endif /* SSF_H */
diff --git a/src/ssf_lambertian_reflection.c b/src/ssf_lambertian_reflection.c
@@ -0,0 +1,115 @@
+/* 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 "ssf_bxdf_c.h"
+
+#include <rsys/double3.h>
+#include <rsys/double33.h>
+
+struct lambertian_reflection {
+ double reflectivity;
+};
+
+/*******************************************************************************
+ * Private functions
+ ******************************************************************************/
+static res_T
+lambertian_reflection_init(struct mem_allocator* allocator, void* bxdf)
+{
+ ASSERT(bxdf);
+ (void)allocator;
+ ((struct lambertian_reflection*)bxdf)->reflectivity = 0.0;
+ return RES_OK;
+}
+
+static void
+lambertian_reflection_release(void* bxdf)
+{ (void)bxdf; }
+
+static double
+lambertian_reflection_eval
+ (void* data, const double wi[3], const double N[3], const double wo[3])
+{
+ struct lambertian_reflection* brdf = data;
+ double coso;
+ ASSERT(data && N && wo);
+ ASSERT(d3_is_normalized(N) && d3_is_normalized(wo));
+ (void)wi;
+ coso = d3_dot(wo, N);
+ return coso <= 0.0 ? 0.0 : brdf->reflectivity / PI;
+}
+
+static double
+lambertian_reflection_sample
+ (void* data,
+ const double u,
+ const double v,
+ const double wi[3],
+ const double N[3],
+ double wo[4])
+{
+ double basis[9];
+ double dir[3];
+ double cos_theta, sin_theta;
+ double phi;
+ ASSERT(data && u>=0 && u<1 && v>=0 && v<1 && wi && N && wo);
+ ASSERT(d3_is_normalized(wi) && d3_is_normalized(N));
+
+ phi = 2.0 * PI * u;
+ cos_theta = sqrt(v);
+ sin_theta = sqrt(1.0 - v);
+ dir[0] = cos(phi) * sin_theta;
+ dir[1] = sin(phi) * sin_theta;
+ dir[2] = cos_theta;
+ d33_muld3(wo, d33_basis(basis, N), dir);
+ wo[3] = cos_theta / PI;
+ return lambertian_reflection_eval(data, wi, N, wo);
+}
+
+static double
+lambertian_reflection_pdf
+ (void* data, const double wi[3], const double N[3], const double wo[3])
+{
+ double coso;
+ ASSERT(data && wi && N && wo);
+ ASSERT(d3_is_normalized(N) && d3_is_normalized(wo));
+ (void)data, (void)wi;
+ coso = d3_dot(wo, N);
+ return coso <= 0.0 ? 0.0 : coso / PI;
+}
+
+/*******************************************************************************
+ * Exorted functions
+ ******************************************************************************/
+const struct ssf_bxdf_type ssf_lambertian_reflection = {
+ lambertian_reflection_init,
+ lambertian_reflection_release,
+ lambertian_reflection_sample,
+ lambertian_reflection_eval,
+ lambertian_reflection_pdf,
+ sizeof(struct lambertian_reflection),
+ ALIGNOF(struct lambertian_reflection)
+};
+
+res_T
+ssf_lambertian_reflection_setup(struct ssf_bxdf* bxdf, const double reflectivity)
+{
+ if(!bxdf || reflectivity < 0 || reflectivity > 1) return RES_BAD_ARG;
+ if(!BXDF_TYPE_EQ(&bxdf->type, &ssf_lambertian_reflection)) return RES_BAD_ARG;
+ ((struct lambertian_reflection*)bxdf->data)->reflectivity = reflectivity;
+ return RES_OK;
+}
+
diff --git a/src/test_ssf_bsdf_view.c b/src/test_ssf_bsdf_view.c
@@ -18,12 +18,6 @@
#include <rsys/double3.h>
-static INLINE double
-rand_canonic(void)
-{
- return (double)rand()/(double)RAND_MAX;
-}
-
int
main(int argc, char** argv)
{
diff --git a/src/test_ssf_lambertian_reflection.c b/src/test_ssf_lambertian_reflection.c
@@ -0,0 +1,100 @@
+/* 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"
+
+#include <rsys/double3.h>
+
+int
+main(int argc, char** argv)
+{
+ const size_t NSTEPS = 100000;
+ struct mem_allocator allocator;
+ struct ssf_bxdf* brdf;
+ struct ssf_bxdf* dummy;
+ double E, SE, V;
+ double sum;
+ double sum_sqr;
+ double wi[3];
+ double N[3];
+ double wo[4];
+ size_t i;
+ (void)argc, (void)argv;
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ CHECK(ssf_bxdf_create(&allocator, &ssf_lambertian_reflection, &brdf), RES_OK);
+ CHECK(ssf_bxdf_create(&allocator, &bxdf_dummy, &dummy), RES_OK);
+
+ CHECK(ssf_lambertian_reflection_setup(NULL, -1.0), RES_BAD_ARG);
+ CHECK(ssf_lambertian_reflection_setup(brdf, -1.0), RES_BAD_ARG);
+ CHECK(ssf_lambertian_reflection_setup(NULL, 1.0), RES_BAD_ARG);
+ CHECK(ssf_lambertian_reflection_setup(brdf, 1.0), RES_OK);
+ CHECK(ssf_lambertian_reflection_setup(brdf, 0.0), RES_OK);
+ CHECK(ssf_lambertian_reflection_setup(brdf, 1.1), RES_BAD_ARG);
+ CHECK(ssf_lambertian_reflection_setup(dummy, 0.0), RES_BAD_ARG);
+
+ d3(N, 0.0, 0.0, 1.0);
+ d3_normalize(wi, d3(wi, -1.0, 0.0, -1.0));
+ CHECK(ssf_bxdf_sample(brdf, 0, 0, wi, N, wo), 0.0);
+ CHECK(eq_eps(wo[2]/PI, wo[3], 1.e-6), 1);
+
+ CHECK(ssf_lambertian_reflection_setup(brdf, 0.7), RES_OK);
+ CHECK(ssf_bxdf_sample(brdf, 0.5, 0.5, wi, N, wo), 0.7/PI);
+
+ sum = sum_sqr = 0;
+ FOR_EACH(i, 0, NSTEPS) {
+ const double u = rand_canonic();
+ const double v = rand_canonic();
+ const double R = ssf_bxdf_sample(brdf, u, v, wi, N, wo);
+ CHECK(eq_eps(R, 0.7/PI, 1.e-6), 1);
+ CHECK(eq_eps(d3_dot(wo, N), wo[2], 1.e-6), 1);
+ sum += wo[2];
+ sum_sqr += wo[2]*wo[2];
+ }
+ E = sum/(double)NSTEPS;
+ V = sum_sqr/(double)NSTEPS - E*E;
+ SE = sqrt(V/(double)NSTEPS);
+ CHECK(eq_eps(E, 2.0/3.0, SE), 1);
+
+ sum = sum_sqr = 0;
+ FOR_EACH(i, 0, NSTEPS) {
+ const double u = rand_canonic();
+ const double v = rand_canonic();
+ double R = ssf_bxdf_sample(brdf, u, v, wi, N, wo);
+ double w;
+ CHECK(eq_eps(R, 0.7/PI, 1.e-6), 1);
+ CHECK(eq_eps(d3_dot(wo, N), wo[2], 1.e-6), 1);
+ w = wo[2]*wo[2];
+ sum += w;
+ sum_sqr += w*w;
+ }
+
+ E = sum/(double)NSTEPS;
+ V = sum_sqr/(double)NSTEPS - E*E;
+ SE = sqrt(V/(double)NSTEPS);
+ CHECK(eq_eps(E, 2.0/4.0, 2.0*SE), 1);
+ CHECK(eq_eps(SE, 1.0/sqrt((double)NSTEPS) * sqrt(1.0/3.0 - 1.0/4.0), 1.e-6), 1);
+
+ CHECK(ssf_bxdf_ref_put(brdf), RES_OK);
+ CHECK(ssf_bxdf_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
@@ -114,6 +114,12 @@ static const struct ssf_fresnel_type fresnel_dummy = {
/*******************************************************************************
* Miscellaneous functions
******************************************************************************/
+static INLINE double
+rand_canonic(void)
+{
+ return (double)rand()/(double)RAND_MAX;
+}
+
static INLINE void
check_memory_allocator(struct mem_allocator* allocator)
{