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 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:
Msrc/ssf.h | 66+++++++++++++++++++++++++++++++++++++-----------------------------
Msrc/ssf_bsdf_view.c | 25+++++++++++++------------
Msrc/ssf_bxdf.c | 29+++++++++++++++--------------
Msrc/ssf_lambertian_reflection.c | 44+++++++++++++++++++++++---------------------
Msrc/ssf_specular_reflection.c | 28+++++++++++++++-------------
Msrc/test_ssf_bsdf.c | 16++++++++--------
Msrc/test_ssf_bsdf_view.c | 28++++++++++++++++++----------
Msrc/test_ssf_bxdf.c | 50++++++++++++++++++++++++++------------------------
Msrc/test_ssf_lambertian_reflection.c | 52+++++++++++++++++++++++++++++++++++++++-------------
Msrc/test_ssf_specular_reflection.c | 54+++++++++++++++++++++++++++++++++---------------------
Msrc/test_ssf_utils.h | 17+++++++++--------
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; }