commit ed3a9e1d8d09adeca8c7e6c6a54690af684e2110
parent a8ebdb94c0b0ac38131818a4c6ddc8c569212541
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 21 Sep 2016 14:24:57 +0200
Fix the specular BxDFs & upd the API conventions
When sampled, the specular BRDF returned the reflectivity rather than
the reflectivity divided by the cosine between the sampled direction and
the surface normal.
The `wo' and `wi' direction now point outward the surface. Swap the `wo'
and `wi' directions of the sample, eval and pdf functions of the
B<x|S>DF.
Diffstat:
11 files changed, 236 insertions(+), 173 deletions(-)
diff --git a/src/ssf.h b/src/ssf.h
@@ -44,35 +44,38 @@ struct ssf_bsdf_view; /* Current state of the BSDF */
struct ssf_bxdf; /* Bidirectional <Reflec|Transmit>tance Distribution Function */
struct ssf_fresnel; /* Equation of the Fresnel term */
-/* Generic BxDF type descriptor */
+/* Generic BxDF type descriptor. Note that by convention the outgoing direction
+ * `wo' and the incoming direction `wi' point outward the surface. */
struct ssf_bxdf_type {
res_T (*init)(struct mem_allocator* allocator, void* bxdf);
void (*release)(void* bxdf);
- /* Sample an outgoing direction `wo' with respect to the ingoing direction
- * `wi' and return the BxDF reflectivity along the sampled direction */
+ /* Sample an incoming direction `wi' with respect to the outgoign direction
+ * `wo' and return the valud of the BxDF wrt to wo and wi */
double
(*sample)
(void* bxdf,
const double u, /* Canonical random number */
const double v, /* Canonical random number */
- const double wi[3], /* Normalized incoming dir. Point inward the surface */
- const double N[3], /* Normalized normal */
- double wo[4]); /* Sampled direction. The PDF is stored in wo[3] */
+ const double wo[3], /* Normalized outgoing direction */
+ const double N[3], /* Normalized surface normal */
+ double wi[3], /* Sampled normalized incoming direction */
+ double* pdf); /* PDF to sample wi wrt wo */
- double /* Reflectivity */
+ /* Evaluate the BxDF wrt to wo and wi */
+ double
(*eval)
(void* bxdf,
- const double wi[3], /* Normalized incoming dir. Point inward the surface */
+ const double wo[3], /* Normalized outgoing direction */
const double N[3], /* Normalized surface normal */
- const double wo[3]);/* Normalized outgoing dir. Point outward the surface */
+ const double wi[3]);/* Normalized incoming direction */
double
(*pdf)
(void* bxdf,
- const double wi[3], /* Normalized incoming dir. Point inward the surface */
+ const double wo[3], /* Normalized outgoing direction */
const double N[3], /* Normalized surface normal */
- const double wo[3]);/* Normalized outgoing dir. Point outward the surface */
+ const double wi[3]);/* Normalized incoming direction */
size_t sizeof_bxdf; /* In Bytes */
size_t alignof_bxdf; /* In Bytes */
@@ -136,7 +139,8 @@ ssf_bsdf_clear
(struct ssf_bsdf* bsdf);
/*******************************************************************************
- * BSDF view API - State of the 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
@@ -151,28 +155,29 @@ SSF_API res_T
ssf_bsdf_view_ref_put
(struct ssf_bsdf_view* view);
-SSF_API double /* Reflectivity */
+SSF_API double /* Value of the BSDF wrt to wo and the sampled wi */
ssf_bsdf_view_sample
(struct ssf_bsdf_view* view,
const double u, /* Canonical number */
const double v, /* Canonical number */
- const double wi[3], /* Normalized incoming direction */
- const double N[3], /* Normalized normal */
- double wo[4]); /* Sampled direction. The PDF is stored in dir[3] */
+ const double wo[3], /* Normalized outgoing direction */
+ const double N[3], /* Normalized surface normal */
+ double wi[3], /* Sampeled normalized incoming direction */
+ double* pdf); /* PDF to sample wi wrt wo */
SSF_API double /* Reflectivity */
ssf_bsdf_view_eval
(struct ssf_bsdf_view* view,
- const double wi[3], /* Normalized incoming direction */
+ const double wo[3], /* Normalized outgoing direction */
const double N[3], /* Normalized surface normal */
- const double wo[3]); /* Normalized outgoing direction */
+ const double wi[3]); /* Normalized incoming direction */
SSF_API double
ssf_bsdf_view_pdf
(struct ssf_bsdf_view* view,
- const double wi[3], /* Normalized incoming direction */
+ const double wo[3], /* Normalized incoming direction */
const double N[3], /* Normalized surface normal */
- const double wo[3]); /* Normalized outgoing direction */
+ const double wi[3]); /* Normalized outgoing direction */
/*******************************************************************************
* Fresnel API - Define the equation of the fresnel term
@@ -221,7 +226,9 @@ ssf_fresnel_dielectric_conductor_setup
/*******************************************************************************
* BxDF API - Bidirectional <Reflectance|Transmittance> distribution function.
- * Describes how the light is reflected|transmitted by a surface.
+ * Describes how the light is reflected|transmitted by a surface. Note that by
+ * convention the outgoing direction `wo' and the incoming direction `wi' point
+ * outward the surface.
******************************************************************************/
SSF_API res_T
ssf_bxdf_create
@@ -237,28 +244,29 @@ SSF_API res_T
ssf_bxdf_ref_put
(struct ssf_bxdf* bxdf);
-SSF_API double /* Reflectivity */
+SSF_API double /* Value of the BRDF for the submitted wo and the sampled wi */
ssf_bxdf_sample
(struct ssf_bxdf* bxdf,
const double u, /* Canonical random number */
const double v, /* Canonical random number */
- const double wi[3], /* Normalized incoming dir. Point inward the surface */
- const double N[3], /* Normalized normal */
- double wo[4]); /* Sampled direction. The PDF is stored in dir[3] */
+ const double wo[3], /* Normalized outgoing direction */
+ const double N[3], /* Normalized surface normal */
+ double wi[3], /* Sampled normalized incoming direction. */
+ double* pdf); /* PDF of the sampled direction */
SSF_API double /* Reflectivity */
ssf_bxdf_eval
(struct ssf_bxdf* bxdf,
- const double wi[3], /* Normalized incoming dir. Point inward the surface */
+ const double wo[3], /* Normalized outgoing direction */
const double N[3], /* Normalized surface normal */
- const double wo[3]);/* Normalized outgoing dir. Point outward the surface */
+ const double wi[3]);/* Normalized incoming direction */
SSF_API double /* Probability */
ssf_bxdf_pdf
(struct ssf_bxdf* bxdf,
- const double wi[3], /* Normalized incoming dir. Point inward the surface */
+ const double wo[3], /* Normalized incoming direction */
const double N[3], /* Normalized surface normal */
- const double wo[3]);/* Normalized outgoing dir. Point outward the surface */
+ const double wi[3]);/* Normalized outgoing dir. Point outward the surface */
/* Retrieve the internal data of the BxDF. Usefull for user defined BxDFs on
* which the caller has to retrieve their data to setup their parameters */
diff --git a/src/ssf_bsdf_view.c b/src/ssf_bsdf_view.c
@@ -126,25 +126,26 @@ ssf_bsdf_view_ref_put(struct ssf_bsdf_view* view)
return RES_OK;
}
+/* TODO fix this */
double
ssf_bsdf_view_sample
(struct ssf_bsdf_view* view,
const double u,
const double v,
- const double wi[3],
+ const double wo[3],
const double N[3],
- double wo[4])
+ double wi[3],
+ double* pdf)
{
double reflectivity;
- double pdf;
double w;
size_t i, icomponent;
ASSERT(view && u>=0 && u<1 && v>=0 && v<1 && wi && N && wo);
- ASSERT(d3_is_normalized(wi) && d3_is_normalized(N));
+ 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, wi, N, wo);
+ return ssf_bxdf_sample(view->components[0], u, v, wo, N, wi, pdf);
}
/* Sample a component */
@@ -157,20 +158,20 @@ ssf_bsdf_view_sample
(view->cumulative[icomponent+1] - view->cumulative[icomponent], DBL_MAX);
/* Sample the component */
- reflectivity = ssf_bxdf_sample(view->components[icomponent], w, v, wi, N, wo);
+ reflectivity = ssf_bxdf_sample
+ (view->components[icomponent], w, v, wo, N, wi, pdf);
if(reflectivity == 0) return 0;
- pdf = wo[3] * view->probas[icomponent];
- reflectivity *= pdf;
+ *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], wi, N, wo) * view->probas[i];
- reflectivity += ssf_bxdf_eval(view->components[i], wi, N, wo) * view->probas[i];
+ *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];
}
- wo[3] = pdf;
- return reflectivity / pdf;
+ return reflectivity / *pdf;
}
double
diff --git a/src/ssf_bxdf.c b/src/ssf_bxdf.c
@@ -118,37 +118,38 @@ ssf_bxdf_sample
(struct ssf_bxdf* bxdf,
const double u,
const double v,
- const double wi[3],
+ const double wo[3],
const double N[3],
- double wo[4])
+ double wi[3],
+ double* pdf)
{
- ASSERT(bxdf && u>=0 && u<1 && v>=0 && v<1 && wi && N && wo);
- ASSERT(d3_is_normalized(wi) && d3_is_normalized(N));
- return bxdf->type.sample(bxdf->data, u, v, wi, N, wo);
+ ASSERT(bxdf && u>=0 && u<1 && v>=0 && v<1 && wo && N && wi && pdf);
+ ASSERT(d3_is_normalized(wo) && d3_is_normalized(N));
+ return bxdf->type.sample(bxdf->data, u, v, wo, N, wi, pdf);
}
double
ssf_bxdf_eval
(struct ssf_bxdf* bxdf,
- const double wi[3],
+ const double wo[3],
const double N[3],
- const double wo[3])
+ const double wi[3])
{
- ASSERT(bxdf && wi && N && wo);
- ASSERT(d3_is_normalized(wi) && d3_is_normalized(N) && d3_is_normalized(wo));
- return bxdf->type.eval(bxdf->data, wi, N, wo);
+ ASSERT(bxdf && wo && N && wi);
+ ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wi));
+ return bxdf->type.eval(bxdf->data, wo, N, wi);
}
double
ssf_bxdf_pdf
(struct ssf_bxdf* bxdf,
- const double wi[3],
+ const double wo[3],
const double N[3],
- const double wo[3])
+ const double wi[3])
{
ASSERT(bxdf && wi && wo);
- ASSERT(d3_is_normalized(wi) && d3_is_normalized(N) && d3_is_normalized(wo));
- return bxdf->type.pdf(bxdf->data, wi, N, wo);
+ ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wi));
+ return bxdf->type.pdf(bxdf->data, wo, N, wi);
}
res_T
diff --git a/src/ssf_lambertian_reflection.c b/src/ssf_lambertian_reflection.c
@@ -41,15 +41,15 @@ lambertian_reflection_release(void* bxdf)
static double
lambertian_reflection_eval
- (void* data, const double wi[3], const double N[3], const double wo[3])
+ (void* data, const double wo[3], const double N[3], const double wi[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;
+ double cos_wi_N;
+ ASSERT(data && N && wi);
+ ASSERT(d3_is_normalized(N) && d3_is_normalized(wi));
+ (void)wo;
+ cos_wi_N = d3_dot(wi, N);
+ return cos_wi_N <= 0.0 ? 0.0 : brdf->reflectivity / PI;
}
static double
@@ -57,16 +57,17 @@ lambertian_reflection_sample
(void* data,
const double u,
const double v,
- const double wi[3],
+ const double wo[3],
const double N[3],
- double wo[4])
+ double wi[3],
+ double* pdf)
{
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));
+ ASSERT(data && u>=0 && u<1 && v>=0 && v<1 && wo && N && wi);
+ ASSERT(d3_is_normalized(wo) && d3_is_normalized(N));
phi = 2.0 * PI * u;
cos_theta = sqrt(v);
@@ -74,21 +75,22 @@ lambertian_reflection_sample
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);
+ if(d3_dot(wo, N) < 0) dir[2] = -dir[2];
+ d33_muld3(wi, d33_basis(basis, N), dir);
+ *pdf = cos_theta / PI;
+ return lambertian_reflection_eval(data, wo, N, wi);
}
static double
lambertian_reflection_pdf
- (void* data, const double wi[3], const double N[3], const double wo[3])
+ (void* data, const double wo[3], const double N[3], const double wi[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;
+ double cos_wi_N;
+ ASSERT(data && wi && N);
+ ASSERT(d3_is_normalized(N) && d3_is_normalized(wi));
+ (void)data, (void)wo;
+ cos_wi_N = d3_dot(wi, N);
+ return cos_wi_N <= 0.0 ? 0.0 : cos_wi_N / PI;
}
/*******************************************************************************
diff --git a/src/ssf_specular_reflection.c b/src/ssf_specular_reflection.c
@@ -43,29 +43,31 @@ specular_reflection_sample
(void* data,
const double u,
const double v,
- const double wi[3],
+ const double wo[3],
const double N[3],
- double wo[4])
+ double wi[3],
+ double* pdf)
{
struct specular_reflection* brdf = data;
- double cosi;
+ double cos_wo_N;
double dir[3];
ASSERT(u >= 0 && u < 1 && v >= 0 && v < 1 && wi && N && wo);
- ASSERT(d3_is_normalized(wi) && d3_is_normalized(N));
+ ASSERT(d3_is_normalized(wo) && d3_is_normalized(N));
(void)u, (void)v;
- /* Reflection the incoming direction w[3] with respect to the normal */
- cosi = -d3_dot(wi, N);
- d3_muld(dir, N, 2*cosi);
- d3_add(dir, dir, wi);
- d3_set(wo, dir);
- wo[3] = 1.0; /* pdf */
- return brdf->reflectivity;
+ /* Reflect the outgoing direction wo with respect to the surface normal */
+ cos_wo_N = d3_dot(wo, N);
+ d3_muld(dir, N, 2*cos_wo_N);
+ d3_sub(dir, dir, wo);
+ d3_set(wi, dir);
+ *pdf = 1.0; /* pdf */
+ /* TODO check this */
+ return cos_wo_N <= 0 ? 0 : brdf->reflectivity / cos_wo_N/*|wi.N|*/;
}
static double
specular_reflection_eval
- (void* data, const double wi[3], const double N[3], const double wo[3])
+ (void* data, const double wo[3], const double N[3], const double wi[3])
{
(void)data, (void)wi, (void)N, (void)wo;
return 0.0;
@@ -73,7 +75,7 @@ specular_reflection_eval
static double
specular_reflection_pdf
- (void* data, const double wi[3], const double N[3], const double wo[3])
+ (void* data, const double wo[3], const double N[3], const double wi[3])
{
(void)data, (void)wi, (void)N, (void)wo;
return 0.0;
diff --git a/src/test_ssf_bsdf.c b/src/test_ssf_bsdf.c
@@ -25,9 +25,9 @@ main(int argc, char** argv)
struct ssf_bsdf* bsdf;
struct ssf_bxdf* bxdf;
struct ssf_bsdf_view* view;
- double w[3];
+ double wo[3], wi[3], pdf;
double N[3];
- double dir[4];
+ double R;
(void)argc, (void)argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
@@ -57,19 +57,19 @@ main(int argc, char** argv)
CHECK(ssf_bsdf_view_create(bsdf, &view), RES_OK);
- d3_normalize(w, d3(w, -1, -1, 0));
+ d3_normalize(wo, d3(wo, 1, 1, 0));
d3(N, 0.0, 1.0, 0.0);
- CHECK(ssf_bsdf_view_sample(view, 0, 0, w, N, dir), 0.123);
- CHECK(ssf_bsdf_view_sample(view, 0.5, 0.5, w, N, dir), 0.123);
- CHECK(ssf_bsdf_view_eval(view, w, N, dir), 0);
- CHECK(ssf_bsdf_view_pdf(view, w, N, dir), 0);
+ R = ssf_bsdf_view_sample(view, 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_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, w, N, dir), 0.0);
+ CHECK(ssf_bsdf_view_sample(view, 0, 0, wo, N, wi, &pdf), 0.0);
CHECK(ssf_bsdf_ref_put(bsdf), RES_OK);
CHECK(ssf_bxdf_ref_put(bxdf), RES_OK);
diff --git a/src/test_ssf_bsdf_view.c b/src/test_ssf_bsdf_view.c
@@ -27,7 +27,9 @@ main(int argc, char** argv)
struct ssf_bsdf* bsdf;
struct ssf_bsdf_view* view;
struct mem_allocator allocator;
- double N[3], dir[4], w[3];
+ double N[3], wi[3], wo[3];
+ double pdf;
+ double R;
double E, V, SE;
double sum, sqr_sum;
size_t i;
@@ -46,33 +48,39 @@ main(int argc, char** argv)
CHECK(ssf_bsdf_view_create(NULL, &view), RES_BAD_ARG);
CHECK(ssf_bsdf_view_create(bsdf, &view), RES_OK);
- d3_normalize(w, d3(w, -1, -1, 0));
+ 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, w, N, dir), 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, w, N, dir), 0.0);
+ 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);
- CHECK(ssf_bsdf_view_sample(view, 0.5, 0.5, w, N, dir), 1.0);
+ 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);
- CHECK(ssf_bsdf_view_sample(view, 0.5, 0.5, w, N, dir), 0.1234);
+ 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) {
- CHECK(ssf_bsdf_view_sample(view, 0.5, 0.5, w, N, dir), 0.1234);
+ 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, w, N, dir);
- CHECK(ssf_bsdf_view_eval(view, w, N, dir), 0);
- CHECK(ssf_bsdf_view_pdf(view, w, N, dir), 0);
+ 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;
}
diff --git a/src/test_ssf_bxdf.c b/src/test_ssf_bxdf.c
@@ -17,7 +17,6 @@
#include "test_ssf_utils.h"
#include <rsys/double3.h>
-#include <rsys/double4.h>
static int bxdf_is_init = 0;
@@ -57,51 +56,53 @@ bxdf_sample
(void* bxdf,
const double u,
const double v,
- const double wi[3],
+ const double wo[3],
const double N[3],
- double wo[4])
+ double wi[3],
+ double* pdf)
{
struct bxdf* BxDF = bxdf;
NCHECK(BxDF, NULL);
CHECK(BxDF->u, u);
CHECK(BxDF->v, v);
- CHECK(d3_eq(BxDF->wi, wi), 1);
+ CHECK(d3_eq(BxDF->wo, wo), 1);
CHECK(d3_eq(BxDF->N, N), 1);
- d4(wo, 1.0, 2.0, 3.0, 4.0);
+ d3(wi, 1.0, 2.0, 3.0);
+ *pdf = 4;
return BxDF->reflectivity;
}
static double
bxdf_eval
(void* bxdf,
- const double wi[3],
+ const double wo[3],
const double N[3],
- const double wo[3])
+ const double wi[3])
{
struct bxdf* BxDF = bxdf;
NCHECK(BxDF, NULL);
NCHECK(wi, NULL);
NCHECK(wo, NULL);
- CHECK(d3_eq(BxDF->wi, wi), 1);
- CHECK(d3_eq(BxDF->N, N), 1);
CHECK(d3_eq(BxDF->wo, wo), 1);
+ CHECK(d3_eq(BxDF->N, N), 1);
+ CHECK(d3_eq(BxDF->wi, wi), 1);
return BxDF->value;
}
static double
bxdf_pdf
(void* bxdf,
- const double wi[3],
+ const double wo[3],
const double N[3],
- const double wo[3])
+ const double wi[3])
{
struct bxdf* BxDF = bxdf;
NCHECK(BxDF, NULL);
NCHECK(wi, NULL);
NCHECK(wo, NULL);
- CHECK(d3_eq(BxDF->wi, wi), 1);
- CHECK(d3_eq(BxDF->N, N), 1);
CHECK(d3_eq(BxDF->wo, wo), 1);
+ CHECK(d3_eq(BxDF->N, N), 1);
+ CHECK(d3_eq(BxDF->wi, wi), 1);
return BxDF->pdf;
}
@@ -112,9 +113,10 @@ main(int argc, char** argv)
struct bxdf* data;
struct ssf_bxdf* bxdf;
struct ssf_bxdf_type type;
- double w[3];
+ double wo[3];
double N[3];
- double dir[4];
+ double wi[4];
+ double pdf;
(void)argc, (void)argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
@@ -177,28 +179,28 @@ main(int argc, char** argv)
CHECK(data->id, 0xDECAFBAD);
- d3_normalize(w, d3(w, -1, -1, 0));
+ d3_normalize(wo, d3(wo, -1, -1, 0));
d3(N, 0.0, 1.0, 0.0);
- d3_set(data->wi, w);
+ d3_set(data->wo, wo);
d3_set(data->N, N);
data->u = 0.0;
data->v = 0.0;
data->reflectivity = 1.234;
- CHECK(ssf_bxdf_sample(bxdf, 0, 0, w, N, dir), 1.234);
+ CHECK(ssf_bxdf_sample(bxdf, 0, 0, wo, N, wi, &pdf), 1.234);
data->u = 0.5;
data->v = 0.5;
- CHECK(ssf_bxdf_sample(bxdf, 0.5, 0.5, w, N, dir), 1.234);
+ CHECK(ssf_bxdf_sample(bxdf, 0.5, 0.5, wo, N, wi, &pdf), 1.234);
data->reflectivity = 3.14;
- CHECK(ssf_bxdf_sample(bxdf, 0.5, 0.5, w, N, dir), 3.14);
+ CHECK(ssf_bxdf_sample(bxdf, 0.5, 0.5, wo, N, wi, &pdf), 3.14);
- d3_normalize(dir, dir);
- d3_set(data->wo, dir);
+ d3_normalize(wi, wi);
+ d3_set(data->wi, wi);
data->value = 4.567;
- CHECK(ssf_bxdf_eval(bxdf, w, N, dir), data->value);
+ CHECK(ssf_bxdf_eval(bxdf, wo, N, wi), data->value);
data->pdf = 8.90;
- CHECK(ssf_bxdf_pdf(bxdf, w, N, dir), data->pdf);
+ CHECK(ssf_bxdf_pdf(bxdf, wo, N, wi), data->pdf);
CHECK(bxdf_is_init, 1);
CHECK(ssf_bxdf_ref_put(bxdf), RES_OK);
diff --git a/src/test_ssf_lambertian_reflection.c b/src/test_ssf_lambertian_reflection.c
@@ -17,6 +17,7 @@
#include "test_ssf_utils.h"
#include <rsys/double3.h>
+#include <rsys/double33.h>
int
main(int argc, char** argv)
@@ -28,9 +29,11 @@ main(int argc, char** argv)
double E, SE, V;
double sum;
double sum_sqr;
- double wi[3];
+ double basis[9];
+ double wo[3], wi[3];
double N[3];
- double wo[4];
+ double pdf;
+ double R;
size_t i;
(void)argc, (void)argv;
@@ -48,22 +51,42 @@ main(int argc, char** argv)
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);
+ d3_normalize(wo, d3(wo, 1.0, 0.0, 1.0));
+ R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf);
+ CHECK(eq_eps(wi[2]/PI, pdf, 1.e-6), 1);
+ CHECK(R, 0);
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);
+ R = ssf_bxdf_sample(brdf, rand_canonic(), rand_canonic(), wo, N, wi, &pdf);
+ CHECK(eq_eps(ssf_bxdf_eval(brdf, wo, N, wi), R, 1.e-6), 1);
+ CHECK(eq_eps(R, 0.7/PI, 1.e-6), 1);
+ CHECK(eq_eps(pdf, d3_dot(wi, N)/PI, 1.e-6), 1);
+
+ d3_normalize(wo, d3(wo, 1.0, 0.0, -1.0));
+ R = ssf_bxdf_sample(brdf, rand_canonic(), rand_canonic(), wo, N, wi, &pdf);
+ CHECK(R, 0);
+
+ d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0));
+ R = ssf_bxdf_sample(brdf, rand_canonic(), rand_canonic(), wo, N, wi, &pdf);
+ CHECK(eq_eps(R, 0.7/PI, 1.e-6), 1);
+
+ d3_normalize(wo, d3(wo, 1.0, 0.0, 1.0));
+ d3(N, rand_canonic(), rand_canonic(), rand_canonic());
+ d3_normalize(N, N);
+ d33_basis(basis, N);
+ d33_muld3(wo, basis, wo);
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);
+ double cos_wi_N;
+ R = ssf_bxdf_sample(brdf, u, v, wo, N, wi, &pdf);
+ cos_wi_N = d3_dot(wi, N);
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];
+ CHECK(eq_eps(cos_wi_N/PI, pdf, 1.e-6), 1);
+ sum += cos_wi_N;
+ sum_sqr += cos_wi_N * cos_wi_N;
}
E = sum/(double)NSTEPS;
V = sum_sqr/(double)NSTEPS - E*E;
@@ -74,11 +97,14 @@ main(int argc, char** argv)
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 cos_wi_N;
double w;
+
+ R = ssf_bxdf_sample(brdf, u, v, wo, N, wi, &pdf);
+ cos_wi_N = d3_dot(wi, N);
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];
+ CHECK(eq_eps(cos_wi_N/PI, pdf, 1.e-6), 1);
+ w = cos_wi_N*cos_wi_N;
sum += w;
sum_sqr += w*w;
}
diff --git a/src/test_ssf_specular_reflection.c b/src/test_ssf_specular_reflection.c
@@ -24,9 +24,10 @@ main(int argc, char** argv)
struct mem_allocator allocator;
struct ssf_bxdf* brdf;
struct ssf_bxdf* dummy;
- double w[3];
+ double wo[3], wi[3];
double N[3];
- double dir[4];
+ double pdf;
+ double R;
(void)argc, (void)argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
@@ -42,32 +43,43 @@ main(int argc, char** argv)
CHECK(ssf_specular_reflection_setup(dummy, 0.0), RES_BAD_ARG);
d3(N, 0.0, 1.0, 0.0);
- d3_normalize(w, d3(w, -1.0, -1.0, 0.0));
- CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir), 0.0);
+ d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0));
+ R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf);
+ CHECK(R, 0);
+ CHECK(pdf, 1);
- d3_normalize(w, d3(w, -1.0, -1.0, 0.0));
+ d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0));
CHECK(ssf_specular_reflection_setup(brdf, 0.123), RES_OK);
- CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir), 0.123);
- CHECK(d3_eq_eps(d3(w, w[0], -w[1], 0.0), dir, 1.e-6), 1);
+ R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf);
+ CHECK(eq_eps(R, 0.123 / d3_dot(N, wi), 1.e-6), 1);
+ CHECK(pdf, 1);
+ CHECK(d3_eq_eps(d3(wo, -wo[0], wo[1], 0.0), wi, 1.e-6), 1);
- CHECK(ssf_bxdf_eval(brdf, w, N, dir), 0.0);
- CHECK(ssf_bxdf_pdf(brdf, w, N, dir), 0.0);
+ CHECK(ssf_bxdf_eval(brdf, wo, N, wi), 0.0);
+ CHECK(ssf_bxdf_pdf(brdf, wo, N, wi), 0.0);
- d3(w, 0.0, -1.0, 0.0);
- CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir), 0.123);
- CHECK(d3_eq_eps(d3(w, 0.0, 1.0, 0.0), dir, 1.e-6), 1);
+ d3(wo, 0.0, 1.0, 0.0);
+ R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf);
+ CHECK(eq_eps(R, 0.123, 1.e-6), 1);
+ CHECK(pdf, 1);
+ CHECK(d3_eq_eps(d3(wo, 0.0, 1.0, 0.0), wi, 1.e-6), 1);
- d3_normalize(w, d3(w, -1.0, 1.0, 0.0));
- CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir), 0.123);
- CHECK(d3_eq_eps(d3(w, w[0], -w[1], 0.0), dir, 1.e-6), 1);
+ d3_normalize(wo, d3(wo, -1.0, 1.0, 0.0));
+ R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf);
+ CHECK(eq_eps(R, 0.123 / d3_dot(N, wi), 1.e-6), 1);
+ CHECK(pdf, 1);
+ CHECK(d3_eq_eps(d3(wo, -wo[0], wo[1], 0.0), wi, 1.e-6), 1);
- d3(w, 0.0, 1.0, 0.0);
- CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir), 0.123);
- CHECK(d3_eq_eps(d3(w, 0.0, -1.0, 0.0), dir, 1.e-6), 1);
+ d3(wo, 0.0, -1.0, 0.0);
+ R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf);
+ CHECK(eq_eps(R, 0, 1.e-6), 1);
+ CHECK(pdf, 1);
+ CHECK(d3_eq_eps(d3(wo, 0.0, -1.0, 0.0), wi, 1.e-6), 1);
- d3(w, -1.0, 0.0, 0.0);
- CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir), 0.123);
- CHECK(d3_eq_eps(w, dir, 1.e-6), 1);
+ d3(wo, 1.0, 0.0, 0.0);
+ R = ssf_bxdf_sample(brdf, 0, 0, wo, N, wi, &pdf);
+ CHECK(eq_eps(R, 0, 1.e-6), 1);
+ CHECK(d3_eq_eps(d3(wo, -1.0, 0, 0), wi, 1.e-6), 1);
CHECK(ssf_bxdf_ref_put(brdf), RES_OK);
CHECK(ssf_bxdf_ref_put(dummy), RES_OK);
diff --git a/src/test_ssf_utils.h b/src/test_ssf_utils.h
@@ -42,31 +42,32 @@ bxdf_dummy_sample
const double v,
const double w[3],
const double N[3],
- double dir[4])
+ double dir[3],
+ double* pdf)
{
- (void)bxdf, (void)u, (void)v, (void)w, (void)N, (void)dir;
+ (void)bxdf, (void)u, (void)v, (void)w, (void)N, (void)dir, (void)pdf;
return 0.0;
}
static double
bxdf_dummy_eval
(void* bxdf,
- const double wi[3],
+ const double wo[3],
const double N[3],
- const double wo[3])
+ const double wi[3])
{
- (void)bxdf, (void)wi, (void)N, (void)wo;
+ (void)bxdf, (void)wo, (void)N, (void)wi;
return 0.0;
}
static double
bxdf_dummy_pdf
(void* bxdf,
- const double wi[3],
+ const double wo[3],
const double N[3],
- const double wo[3])
+ const double wi[3])
{
- (void)bxdf, (void)wi, (void)N, (void)wo;
+ (void)bxdf, (void)wo, (void)N, (void)wi;
return 0.0;
}