commit f57ae592db312e611e55a5dce034764887a66f36
parent 863ed1ee241b1aae6870a7d30cc721f7341e6ef4
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 23 Sep 2016 10:30:02 +0200
Major update of the BSDF sample function and remove the BSDF view
Remove the BSDF view data structure since they are quite useless; the
BSDF view pre-computations can be silently performed directly into the
BSDF.
Add the rho function to the B<x|S>DF API. This functions is defined as:
rho(wi) = \int_{2\Pi} B<x|S>DF(wo, wi) |wi.N| dwi
The BSDF components are now sampled wrt to Wi*rho_i(wo)/rho(wo) where Wi
is the weight of the i^th component, rho_i(wo) its rho value and rho(wo)
the rho value of the BSDF. The PDF of the sampled direction becomes:
P(wi, wo) = \sum_{i=1..N} Wi*rho_i(wo)/rho(wo) * Pi(wo, wi)
with Pi(wo, wi) the probability to sample the direction wi wrt to wo for
the i^th component. Finally the BSDF reflectivity along wi is defined
as:
R(wi, wo) = \sum_{i=1..N} Wi*BxDF(wi, wo)
Diffstat:
8 files changed, 220 insertions(+), 464 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -46,8 +46,6 @@ set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
set(SSF_FILES_DOC COPYING README.md)
set(SSF_FILES_INC_API ssf.h)
set(SSF_FILES_INC
- ssf_bsdf_c.h
- ssf_bsdf_view_c.h
ssf_bxdf_c.h
ssf_fresnel_c.h
ssf_microfacet_distribution_c.h
@@ -55,7 +53,6 @@ set(SSF_FILES_INC
set(SSF_FILES_SRC
ssf_beckmann_distribution.c
ssf_bsdf.c
- ssf_bsdf_view.c
ssf_bxdf.c
ssf_fresnel.c
ssf_fresnel_dielectric_conductor.c
@@ -100,7 +97,6 @@ if(NOT NO_TEST)
endfunction()
new_test(test_ssf_bsdf)
- new_test(test_ssf_bsdf_view)
new_test(test_ssf_bxdf)
new_test(test_ssf_fresnel)
new_test(test_ssf_fresnel_dielectric_conductor)
diff --git a/src/ssf.h b/src/ssf.h
@@ -166,7 +166,9 @@ SSF_API const struct ssf_microfacet_distribution_type ssf_beckmann_distribution;
/*******************************************************************************
* BSDF API - Bidirectionnal Scattering Distribution Function. Describes the
- * way the light is scattered by a surface with a combination of BxDFs.
+ * way the light is scattered by a surface with a combination of BxDFs. Note
+ * that by convention the outgoing direction `wo' and the incoming direction
+ * `wi' point outward the surface.
******************************************************************************/
SSF_API res_T
ssf_bsdf_create
@@ -191,26 +193,9 @@ SSF_API res_T
ssf_bsdf_clear
(struct ssf_bsdf* bsdf);
-/*******************************************************************************
- * BSDF view API - State of the BSDF. Note that by convention the outgoing
- * direction `wo' and the incoming direction `wi' point outward the surface.
- ******************************************************************************/
-SSF_API res_T
-ssf_bsdf_view_create
- (struct ssf_bsdf* bsdf,
- struct ssf_bsdf_view** view);
-
-SSF_API res_T
-ssf_bsdf_view_ref_get
- (struct ssf_bsdf_view* view);
-
-SSF_API res_T
-ssf_bsdf_view_ref_put
- (struct ssf_bsdf_view* view);
-
SSF_API double /* Value of the BSDF wrt to wo and the sampled wi */
-ssf_bsdf_view_sample
- (struct ssf_bsdf_view* view,
+ssf_bsdf_sample
+ (struct ssf_bsdf* bsdf,
const double u, /* Canonical number */
const double v, /* Canonical number */
const double wo[3], /* Normalized outgoing direction */
@@ -219,22 +204,22 @@ ssf_bsdf_view_sample
double* pdf); /* PDF to sample wi wrt wo */
SSF_API double /* Reflectivity */
-ssf_bsdf_view_eval
- (struct ssf_bsdf_view* view,
+ssf_bsdf_eval
+ (struct ssf_bsdf* bsdf,
const double wo[3], /* Normalized outgoing direction */
const double N[3], /* Normalized surface normal */
const double wi[3]); /* Normalized incoming direction */
SSF_API double
-ssf_bsdf_view_pdf
- (struct ssf_bsdf_view* view,
+ssf_bsdf_pdf
+ (struct ssf_bsdf* bsdf,
const double wo[3], /* Normalized incoming direction */
const double N[3], /* Normalized surface normal */
const double wi[3]); /* Normalized outgoing direction */
SSF_API double /* \int_{2\pi} BSDF(wi, wo) |wi.N| dwi */
-ssf_bsdf_view_rho
- (struct ssf_bsdf_view* view,
+ssf_bsdf_rho
+ (struct ssf_bsdf* bsdf,
const double wo[3]);
/*******************************************************************************
diff --git a/src/ssf_bsdf.c b/src/ssf_bsdf.c
@@ -13,29 +13,51 @@
* 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 */
+
#include "ssf.h"
-#include "ssf_bsdf_c.h"
-#include "ssf_bsdf_view_c.h"
#include "ssf_bxdf_c.h"
#include <rsys/double3.h>
#include <rsys/double4.h>
#include <rsys/mem_allocator.h>
+#include <rsys/ref_count.h>
+
+#define MAX_BxDFs 8
+
+struct ssf_bsdf {
+ struct ssf_bxdf* bxdfs[MAX_BxDFs];
+
+ double uweights[MAX_BxDFs]; /* Unormalized component weights */
+ double weights[MAX_BxDFs]; /* Normalized weights */
+ int outdated_weights; /* Define if the normalized weights are outdated */
+
+ size_t nbxdfs;
+
+ ref_T ref;
+ struct mem_allocator* allocator;
+};
/*******************************************************************************
* Helper functions
******************************************************************************/
+static INLINE void
+bsdf_normalize_weights(struct ssf_bsdf* bsdf)
+{
+ double weights_sum = 0;
+ size_t i;
+ ASSERT(bsdf);
+ if(!bsdf->outdated_weights) return;
+ FOR_EACH(i, 0, bsdf->nbxdfs) weights_sum += bsdf->uweights[i];
+ FOR_EACH(i, 0, bsdf->nbxdfs) bsdf->weights[i] = bsdf->uweights[i]/weights_sum;
+ bsdf->outdated_weights = 0;
+}
+
static void
bsdf_release(ref_T* ref)
{
struct ssf_bsdf* bsdf = CONTAINER_OF(ref, struct ssf_bsdf, ref);
- struct list_node* tmp;
- struct list_node* node;
ASSERT(ref);
-
- LIST_FOR_EACH_SAFE(node, tmp, &bsdf->views) {
- bsdf_view_destroy(CONTAINER_OF(node, struct ssf_bsdf_view, node));
- }
SSF(bsdf_clear(bsdf));
MEM_RM(bsdf->allocator, bsdf);
}
@@ -63,7 +85,6 @@ ssf_bsdf_create(struct mem_allocator* allocator, struct ssf_bsdf** out_bsdf)
}
bsdf->allocator = mem_allocator;
ref_init(&bsdf->ref);
- list_init(&bsdf->views);
exit:
if(out_bsdf) *out_bsdf = bsdf;
@@ -96,12 +117,13 @@ res_T
ssf_bsdf_add(struct ssf_bsdf* bsdf, struct ssf_bxdf* bxdf, const double weight)
{
if(!bsdf || !bxdf || weight < 0) return RES_BAD_ARG;
- if(bsdf->ncomponents >= BSDF_MAX_COMPONENTS) return RES_MEM_ERR;
+ if(bsdf->nbxdfs >= MAX_BxDFs) return RES_MEM_ERR;
if(weight == 0) return RES_OK;
SSF(bxdf_ref_get(bxdf));
- bsdf->components[bsdf->ncomponents] = bxdf;
- bsdf->weights[bsdf->ncomponents] = weight;
- ++bsdf->ncomponents;
+ bsdf->bxdfs[bsdf->nbxdfs] = bxdf;
+ bsdf->uweights[bsdf->nbxdfs] = weight;
+ bsdf->outdated_weights = 1;
+ ++bsdf->nbxdfs;
return RES_OK;
}
@@ -110,10 +132,137 @@ ssf_bsdf_clear(struct ssf_bsdf* bsdf)
{
size_t i;
if(!bsdf) return RES_BAD_ARG;
- FOR_EACH(i, 0, bsdf->ncomponents) {
- SSF(bxdf_ref_put(bsdf->components[i]));
+ FOR_EACH(i, 0, bsdf->nbxdfs) {
+ SSF(bxdf_ref_put(bsdf->bxdfs[i]));
}
- bsdf->ncomponents = 0;
+ bsdf->nbxdfs = 0;
return RES_OK;
}
+double
+ssf_bsdf_sample
+ (struct ssf_bsdf* bsdf,
+ const double u,
+ const double v,
+ const double wo[3],
+ const double N[3],
+ double wi[3],
+ double* out_pdf)
+{
+ double probas[MAX_BxDFs];
+ double cumul[MAX_BxDFs];
+ double reflectivity;
+ double pdf;
+ double rho;
+ double r;
+ size_t i, j;
+ ASSERT(bsdf && u>=0 && u<1 && v>=0 && v<1 && wi && N && wo && out_pdf);
+ ASSERT(d3_is_normalized(wo) && d3_is_normalized(N));
+
+ if(!bsdf->nbxdfs) {
+ *out_pdf = 0;
+ return 0;
+ }
+ if(bsdf->nbxdfs == 1) {
+ return ssf_bxdf_sample(bsdf->bxdfs[0], u, v, wo, N, wi, out_pdf);
+ }
+ bsdf_normalize_weights(bsdf);
+
+ /* Compute the probabilities to sample each component as well as the
+ * cumulative. For the i^th, component the proba is `Wi * rho_i(wo)/rho(wo)'
+ * with Wi the component weight, rho_i(wo) its associated rho wrt to wo, and
+ * rho the overall rho of the BSDF */
+ rho = 0;
+ FOR_EACH(i, 0, bsdf->nbxdfs) {
+ probas[i] = bsdf->weights[i] * ssf_bxdf_rho(bsdf->bxdfs[i], wo);
+ rho += probas[i];
+ }
+ cumul[0] = (probas[0] /= rho);
+ FOR_EACH(i, 1, bsdf->nbxdfs) {
+ probas[i] /= rho;
+ cumul[i] = probas[i] + cumul[i-1];
+ }
+
+ /* Sample a component */
+ FOR_EACH(i, 0, bsdf->nbxdfs-1) {
+ if(u >= cumul[i]) break;
+ }
+
+ /* Rescale the random number u in [0, 1) */
+ r = (u - cumul[i]) / nextafter(cumul[i+1] - cumul[i], DBL_MAX);
+
+ /* Sample a direction from the selected component */
+ reflectivity = ssf_bxdf_sample(bsdf->bxdfs[i], r, v, wo, N, wi, &pdf);
+
+ /* Compute the overall probabilities to sample this direction and the overall
+ * reflectivity along this direction */
+ pdf *= probas[i];
+ reflectivity *= bsdf->weights[i];
+ FOR_EACH(j, 0, bsdf->nbxdfs) {
+ if(i == j) continue;
+ pdf += probas[j] * ssf_bxdf_pdf(bsdf->bxdfs[j], wo, N, wi);
+ reflectivity += bsdf->weights[j] * ssf_bxdf_eval(bsdf->bxdfs[j], wo, N, wi);
+ }
+ *out_pdf = pdf;
+#ifndef NDEBUG
+ {
+ const double R = rho * pdf / fabs(d3_dot(wi, N));
+ ASSERT(eq_eps(R, reflectivity, 1.e-6));
+ }
+#endif
+ return reflectivity;
+}
+
+double
+ssf_bsdf_pdf
+ (struct ssf_bsdf* bsdf,
+ const double wo[3],
+ const double N[3],
+ const double wi[3])
+{
+ double pdf = 0;
+ double rho = 0;
+ size_t i;
+ ASSERT(bsdf);
+ bsdf_normalize_weights(bsdf);
+ FOR_EACH(i, 0, bsdf->nbxdfs) {
+ const double tmp = bsdf->weights[i] * ssf_bxdf_rho(bsdf->bxdfs[i], wo);
+ pdf += ssf_bxdf_pdf(bsdf->bxdfs[i], wo, N, wi) * tmp;
+ rho += tmp;
+ }
+ pdf /= rho;
+ return pdf;
+}
+
+double
+ssf_bsdf_eval
+ (struct ssf_bsdf* bsdf,
+ const double wo[3],
+ const double N[3],
+ const double wi[3])
+{
+ double R = 0;
+ size_t i;
+ ASSERT(bsdf);
+ bsdf_normalize_weights(bsdf);
+ FOR_EACH(i, 0, bsdf->nbxdfs) {
+ R += bsdf->weights[i] * ssf_bxdf_eval(bsdf->bxdfs[i], wo, N, wi);
+ }
+ return R;
+}
+
+double
+ssf_bsdf_rho
+ (struct ssf_bsdf* bsdf,
+ const double wo[3])
+{
+ double rho = 0;
+ size_t i;
+ ASSERT(bsdf);
+ bsdf_normalize_weights(bsdf);
+ FOR_EACH(i, 0, bsdf->nbxdfs) {
+ rho += bsdf->weights[i] * ssf_bxdf_rho(bsdf->bxdfs[i], wo);
+ }
+ return rho;
+}
+
diff --git a/src/ssf_bsdf_c.h b/src/ssf_bsdf_c.h
@@ -16,24 +16,7 @@
#ifndef SSF_BSDF_C_H
#define SSF_BSDF_C_H
-#include <rsys/list.h>
-#include <rsys/ref_count.h>
-struct ssf_bxdf;
-struct mem_allocator;
-
-#define BSDF_MAX_COMPONENTS 8
-
-struct ssf_bsdf {
- struct list_node views; /* Pool of available ssf_bsdf_view */
- struct ssf_bxdf* components[BSDF_MAX_COMPONENTS];
- /* Unormalized weights to sample the components */
- double weights[BSDF_MAX_COMPONENTS];
- size_t ncomponents;
-
- ref_T ref;
- struct mem_allocator* allocator;
-};
#endif /* SSF_BSDF_C_H */
diff --git a/src/ssf_bsdf_view.c b/src/ssf_bsdf_view.c
@@ -1,237 +0,0 @@
-/* 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/>. */
-
-#define _POSIX_C_SOURCE 200112L /* nextafter */
-
-#include "ssf.h"
-#include "ssf_bsdf_view_c.h"
-
-#include <rsys/double3.h>
-#include <rsys/mem_allocator.h>
-
-#include <float.h>
-#include <math.h>
-
-/*******************************************************************************
- * Helper functions
- ******************************************************************************/
-static void
-bsdf_view_release(ref_T* ref)
-{
- struct ssf_bsdf_view* view;
- size_t i;
- ASSERT(ref);
- view = CONTAINER_OF(ref, struct ssf_bsdf_view, ref);
-
- /* Release the BxDFs */
- FOR_EACH(i, 0, view->ncomponents) {
- SSF(bxdf_ref_put(view->components[i]));
- }
- view->ncomponents = 0;
-
- /* Do not physically release the memory of the view. Add it to the pool of
- * available BSDF views */
- list_add(&view->bsdf->views, &view->node);
- SSF(bsdf_ref_put(view->bsdf));
-}
-
-/*******************************************************************************
- * Exported functions
- ******************************************************************************/
-res_T
-ssf_bsdf_view_create(struct ssf_bsdf* bsdf, struct ssf_bsdf_view** out_view)
-{
- struct ssf_bsdf_view* view = NULL;
- double weights_sum;
- size_t i;
- res_T res = RES_OK;
-
- if(!bsdf || !out_view) {
- res = RES_BAD_ARG;
- goto error;
- }
-
- if(!is_list_empty(&bsdf->views)) {
- /* Retrieve an already allocated BSDF view */
- view = CONTAINER_OF(list_head(&bsdf->views), struct ssf_bsdf_view, node);
- list_del(&view->node);
- ref_get(&view->ref);
- } else { /* Allocate a new BSDF view */
- view = MEM_CALLOC(bsdf->allocator, 1, sizeof(struct ssf_bsdf_view));
- if(!view) {
- res = RES_MEM_ERR;
- goto error;
- }
- list_init(&view->node);
- ref_init(&view->ref);
- }
- SSF(bsdf_ref_get(bsdf));
- view->bsdf = bsdf;
- view->ncomponents = bsdf->ncomponents;
-
- if(!view->ncomponents)
- goto exit;
-
- /* Get a reference onto the BxDFs and compute the overall weight sum */
- weights_sum = 0;
- FOR_EACH(i, 0, view->ncomponents) {
- SSF(bxdf_ref_get(bsdf->components[i]));
- view->components[i] = bsdf->components[i];
- weights_sum += bsdf->weights[i];
- }
-
- /* Compute the probabilities of the components and the cumulative */
- view->probas[0] = bsdf->weights[0] / weights_sum;
- view->cumulative[0] = view->probas[0];
- FOR_EACH(i, 1, view->ncomponents) {
- view->probas[i] = bsdf->weights[i] / weights_sum;
- view->cumulative[i] = view->cumulative[i-1] + view->probas[i];
- }
-exit:
- if(out_view) *out_view = view;
- return res;
-error:
- if(view) {
- SSF(bsdf_view_ref_put(view));
- view = NULL;
- }
- goto exit;
-}
-
-res_T
-ssf_bsdf_view_ref_get(struct ssf_bsdf_view* view)
-{
- if(!view) return RES_BAD_ARG;
- ref_get(&view->ref);
- return RES_OK;
-}
-
-res_T
-ssf_bsdf_view_ref_put(struct ssf_bsdf_view* view)
-{
- if(!view) return RES_BAD_ARG;
- ref_put(&view->ref, bsdf_view_release);
- return RES_OK;
-}
-
-/* TODO fix this */
-double
-ssf_bsdf_view_sample
- (struct ssf_bsdf_view* view,
- const double u,
- const double v,
- const double wo[3],
- const double N[3],
- double wi[3],
- double* pdf)
-{
- double reflectivity;
- double w;
- size_t i, icomponent;
- ASSERT(view && u>=0 && u<1 && v>=0 && v<1 && wi && N && wo);
- ASSERT(d3_is_normalized(wo) && d3_is_normalized(N));
-
- if(!view->ncomponents) return 0;
- if(view->ncomponents == 1) {
- return ssf_bxdf_sample(view->components[0], u, v, wo, N, wi, pdf);
- }
-
- /* Sample a component */
- FOR_EACH(icomponent, 0, view->ncomponents-1) {
- if(u >= view->cumulative[icomponent]) break;
- }
-
- /* Rescale the random number to reuse it */
- w = (u - view->cumulative[icomponent] )/ nextafter
- (view->cumulative[icomponent+1] - view->cumulative[icomponent], DBL_MAX);
-
- /* Sample the component */
- reflectivity = ssf_bxdf_sample
- (view->components[icomponent], w, v, wo, N, wi, pdf);
- if(reflectivity == 0) return 0;
-
- *pdf *= view->probas[icomponent];
- reflectivity *= *pdf;
-
- /* Add the contribution of the others components */
- FOR_EACH(i, 0, view->ncomponents) {
- if(i == icomponent) continue;
- *pdf += ssf_bxdf_pdf(view->components[i], wo, N, wi) * view->probas[i];
- reflectivity += ssf_bxdf_eval(view->components[i], wo, N, wi) * view->probas[i];
- }
- return reflectivity / *pdf;
-}
-
-double
-ssf_bsdf_view_eval
- (struct ssf_bsdf_view* view,
- const double wo[3],
- const double N[3],
- const double wi[3])
-{
- double R = 0;
- size_t i;
- ASSERT(view && wi && wo);
- ASSERT(d3_is_normalized(wi) && d3_is_normalized(wo));
-
- FOR_EACH(i, 0, view->ncomponents) {
- R += ssf_bxdf_eval(view->components[i], wo, N, wi) * view->probas[i];
- }
- return R;
-}
-
-double
-ssf_bsdf_view_pdf
- (struct ssf_bsdf_view* view,
- const double wo[3],
- const double N[3],
- const double wi[3])
-{
- double pdf = 0;
- size_t i;
- ASSERT(view && wi && wo);
- ASSERT(d3_is_normalized(wi) && d3_is_normalized(wo));
-
- FOR_EACH(i, 0, view->ncomponents) {
- pdf += ssf_bxdf_pdf(view->components[i], wo, N, wi) * view->probas[i];
- }
- return pdf;
-}
-
-double
-ssf_bsdf_view_rho
- (struct ssf_bsdf_view* view,
- const double wo[3])
-{
- double rho = 0;
- size_t i;
- ASSERT(view && wo);
- FOR_EACH(i, 0, view->ncomponents) {
- rho += ssf_bxdf_rho(view->components[i], wo) * view->probas[i];
- }
- return rho;
-}
-
-/*******************************************************************************
- * Local functions
- ******************************************************************************/
-void
-bsdf_view_destroy(struct ssf_bsdf_view* view)
-{
- ASSERT(view);
- list_del(&view->node);
- MEM_RM(view->bsdf->allocator, view);
-}
-
diff --git a/src/ssf_bsdf_view_c.h b/src/ssf_bsdf_view_c.h
@@ -1,38 +0,0 @@
-/* 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/>. */
-
-#ifndef SSF_BSDF_VIEW_C_H
-#define SSF_BSDF_VIEW_C_H
-
-#include "ssf_bsdf_c.h"
-
-#include <rsys/list.h>
-#include <rsys/ref_count.h>
-
-struct ssf_bsdf_view {
- struct list_node node; /* Attachment point to the BSDF views pool */
-
- struct ssf_bxdf* components[BSDF_MAX_COMPONENTS];
- double probas[BSDF_MAX_COMPONENTS]; /*Probabilities to sample the components*/
- double cumulative[BSDF_MAX_COMPONENTS]; /* Cumulative of probas */
- size_t ncomponents;
-
- ref_T ref;
- struct ssf_bsdf* bsdf;
-};
-
-extern LOCAL_SYM void bsdf_view_destroy(struct ssf_bsdf_view* view);
-
-#endif /* SSF_BSDF_VIEW_C_H */
diff --git a/src/test_ssf_bsdf.c b/src/test_ssf_bsdf.c
@@ -21,13 +21,17 @@
int
main(int argc, char** argv)
{
+ const size_t NSTEPS = 100000;
struct mem_allocator allocator;
struct ssf_bsdf* bsdf;
struct ssf_bxdf* bxdf;
- struct ssf_bsdf_view* view;
+ struct ssf_bxdf* bxdf2;
double wo[3], wi[3], pdf;
+ double rho;
double N[3];
- double R;
+ double E, V, SE, R;
+ double sum, sqr_sum;
+ size_t i;
(void)argc, (void)argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
@@ -44,36 +48,61 @@ main(int argc, char** argv)
CHECK(ssf_bsdf_create(&allocator, &bsdf), RES_OK);
CHECK(ssf_bxdf_create(&allocator, &ssf_specular_reflection, &bxdf), RES_OK);
+ CHECK(ssf_bxdf_create(&allocator, &ssf_specular_reflection, &bxdf2), RES_OK);
CHECK(ssf_specular_reflection_setup(bxdf, 0.123), RES_OK);
+ CHECK(ssf_specular_reflection_setup(bxdf2, 0.6789), RES_OK);
CHECK(ssf_bsdf_add(NULL, NULL, -1.0), RES_BAD_ARG);
CHECK(ssf_bsdf_add(bsdf, NULL, -1.0), RES_BAD_ARG);
CHECK(ssf_bsdf_add(NULL, bxdf, -1.0), RES_BAD_ARG);
CHECK(ssf_bsdf_add(bsdf, bxdf, -1.0), RES_BAD_ARG);
- CHECK(ssf_bsdf_add(NULL, NULL, 1.0), RES_BAD_ARG);
- CHECK(ssf_bsdf_add(bsdf, NULL, 1.0), RES_BAD_ARG);
- CHECK(ssf_bsdf_add(NULL, bxdf, 1.0), RES_BAD_ARG);
- CHECK(ssf_bsdf_add(bsdf, bxdf, 1.0), RES_OK);
-
- CHECK(ssf_bsdf_view_create(bsdf, &view), RES_OK);
+ CHECK(ssf_bsdf_add(NULL, NULL, 1), RES_BAD_ARG);
+ CHECK(ssf_bsdf_add(bsdf, NULL, 1), RES_BAD_ARG);
+ CHECK(ssf_bsdf_add(NULL, bxdf, 1), RES_BAD_ARG);
+ CHECK(ssf_bsdf_add(bsdf, bxdf, 1), RES_OK);
d3_normalize(wo, d3(wo, 1, 1, 0));
d3(N, 0.0, 1.0, 0.0);
- R = ssf_bsdf_view_sample(view, 0.5, 0.5, wo, N, wi, &pdf);
+ R = ssf_bsdf_sample(bsdf, 0.5, 0.5, wo, N, wi, &pdf);
CHECK(eq_eps(R, 0.123/d3_dot(wi, N), 1.e-6), 1);
- CHECK(ssf_bsdf_view_eval(view, wo, N, wi), 0);
- CHECK(ssf_bsdf_view_pdf(view, wo, N, wi), 0);
+ CHECK(ssf_bsdf_eval(bsdf, wo, N, wi), 0);
+ CHECK(ssf_bsdf_pdf(bsdf, wo, N, wi), 0);
+
+ CHECK(ssf_specular_reflection_setup(bxdf, 0.1234), RES_OK);
+ R = ssf_bsdf_sample(bsdf, 0.5, 0.5, wo, N, wi, &pdf);
+ CHECK(eq_eps(R, 0.1234 / d3_dot(wi, N), 1.e-6), 1);
+
+ CHECK(ssf_bsdf_add(bsdf, bxdf2, 1), RES_OK);
+
+ /* Estimate the BSDF rho */
+ sum = 0;
+ sqr_sum = 0;
+ d3(wo, 0, 1, 0);
+ FOR_EACH(i, 0, NSTEPS) {
+ const double u = rand_canonic();
+ const double v = rand_canonic();
+ double weight = ssf_bsdf_sample(bsdf, u, v, wo, N, wi, &pdf);
+ weight *= d3_dot(N, wi) / pdf;
+ CHECK(ssf_bsdf_eval(bsdf, wo, N, wi), 0);
+ CHECK(ssf_bsdf_pdf(bsdf, wo, N, wi), 0);
+ sum += weight;
+ sqr_sum += weight*weight;
+ }
+ E = sum / (double)NSTEPS;
+ V = sqr_sum / (double)NSTEPS - E*E;
+ SE = sqrt(V / (double)NSTEPS);
+ rho = ssf_bsdf_rho(bsdf, wo);
+ CHECK(eq_eps(rho, E, SE), 1);
CHECK(ssf_bsdf_clear(NULL), RES_BAD_ARG);
CHECK(ssf_bsdf_clear(bsdf), RES_OK);
- CHECK(ssf_bsdf_view_ref_put(view), RES_OK);
- CHECK(ssf_bsdf_view_create(bsdf, &view), RES_OK);
- CHECK(ssf_bsdf_view_sample(view, 0, 0, wo, N, wi, &pdf), 0.0);
+ CHECK(ssf_bsdf_sample(bsdf, 0, 0, wo, N, wi, &pdf), 0.0);
+ CHECK(pdf, 0.0);
CHECK(ssf_bsdf_ref_put(bsdf), RES_OK);
CHECK(ssf_bxdf_ref_put(bxdf), RES_OK);
- CHECK(ssf_bsdf_view_ref_put(view), RES_OK);
+ CHECK(ssf_bxdf_ref_put(bxdf2), RES_OK);
check_memory_allocator(&allocator);
mem_shutdown_proxy_allocator(&allocator);
diff --git a/src/test_ssf_bsdf_view.c b/src/test_ssf_bsdf_view.c
@@ -1,111 +0,0 @@
-/* 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 ssf_bxdf* bxdf;
- struct ssf_bxdf* bxdf2;
- struct ssf_bsdf* bsdf;
- struct ssf_bsdf_view* view;
- struct mem_allocator allocator;
- double N[3], wi[3], wo[3];
- double pdf;
- double R;
- double rho;
- double E, V, SE;
- double sum, sqr_sum;
- size_t i;
- (void)argc, (void)argv;
-
- mem_init_proxy_allocator(&allocator, &mem_default_allocator);
-
- CHECK(ssf_bsdf_create(&allocator, &bsdf), RES_OK);
- CHECK(ssf_bxdf_create(&allocator, &ssf_specular_reflection, &bxdf), RES_OK);
- CHECK(ssf_bxdf_create(&allocator, &ssf_specular_reflection, &bxdf2), RES_OK);
- CHECK(ssf_specular_reflection_setup(bxdf, 1.0), RES_OK);
- CHECK(ssf_specular_reflection_setup(bxdf2, 0.6789), RES_OK);
-
- CHECK(ssf_bsdf_view_create(NULL, NULL), RES_BAD_ARG);
- CHECK(ssf_bsdf_view_create(bsdf, NULL), RES_BAD_ARG);
- CHECK(ssf_bsdf_view_create(NULL, &view), RES_BAD_ARG);
- CHECK(ssf_bsdf_view_create(bsdf, &view), RES_OK);
-
- d3_normalize(wo, d3(wo, 1, 1, 0));
- d3(N, 0.0, 1.0, 0.0);
- CHECK(ssf_bsdf_view_sample(view, 0.5, 0.5, wo, N, wi, &pdf), 0.0);
-
- CHECK(ssf_bsdf_add(bsdf, bxdf, 0.5), RES_OK);
- CHECK(ssf_bsdf_view_sample(view, 0.5, 0.5, wo, N, wi, &pdf), 0.0);
- CHECK(ssf_bsdf_view_ref_put(view), RES_OK);
- CHECK(ssf_bsdf_view_create(bsdf, &view), RES_OK);
- R = ssf_bsdf_view_sample(view, 0.5, 0.5, wo, N, wi, &pdf);
- CHECK(eq_eps(R, 1.0 / d3_dot(wi, N), 1.e-6), 1);
- CHECK(pdf, 1);
-
- CHECK(ssf_specular_reflection_setup(bxdf, 0.1234), RES_OK);
- R = ssf_bsdf_view_sample(view, 0.5, 0.5, wo, N, wi, &pdf);
- CHECK(eq_eps(R, 0.1234 / d3_dot(wi, N), 1.e-6), 1);
-
- CHECK(ssf_bsdf_add(bsdf, bxdf2, 0.5), RES_OK);
- FOR_EACH(i, 0, NSTEPS) {
- R = ssf_bsdf_view_sample(view, 0.5, 0.5, wo, N, wi, &pdf);
- CHECK(eq_eps(R, 0.1234 / d3_dot(wi, N), 1.e-6), 1);
- }
- CHECK(ssf_bsdf_view_ref_put(view), RES_OK);
- CHECK(ssf_bsdf_view_create(bsdf, &view), RES_OK);
-
- sum = 0;
- sqr_sum = 0;
- d3(wo, 0, 1, 0);
- FOR_EACH(i, 0, NSTEPS) {
- const double u = rand_canonic();
- const double v = rand_canonic();
- const double weight = ssf_bsdf_view_sample(view, u, v, wo, N, wi, &pdf);
- CHECK(ssf_bsdf_view_eval(view, wo, N, wi), 0);
- CHECK(ssf_bsdf_view_pdf(view, wo, N, wi), 0);
- sum += weight;
- sqr_sum += weight*weight;
- }
- E = sum / (double)NSTEPS;
- V = sqr_sum / (double)NSTEPS - E*E;
- SE = sqrt(V / (double)NSTEPS);
- CHECK(eq_eps((0.1234+0.6789) * 0.5, E, SE), 1);
-
- rho = ssf_bsdf_view_rho(view, wo);
- CHECK(eq_eps(rho, (0.1234+0.6789)*0.5, 1.e-6), 1);
-
- CHECK(ssf_bsdf_view_ref_get(NULL), RES_BAD_ARG);
- CHECK(ssf_bsdf_view_ref_get(view), RES_OK);
- CHECK(ssf_bsdf_view_ref_put(NULL), RES_BAD_ARG);
- CHECK(ssf_bsdf_view_ref_put(view), RES_OK);
- CHECK(ssf_bsdf_view_ref_put(view), RES_OK);
-
- CHECK(ssf_bxdf_ref_put(bxdf), RES_OK);
- CHECK(ssf_bxdf_ref_put(bxdf2), RES_OK);
- CHECK(ssf_bsdf_ref_put(bsdf), RES_OK);
-
- check_memory_allocator(&allocator);
- mem_shutdown_proxy_allocator(&allocator);
- CHECK(mem_allocated_size(), 0);
- return 0;
-}
-