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 d2427ce9dec95a44e38cc9db5812a0f518b90221
parent 549eeb8ef88321a1a37938d2a94e4edc30b3a63c
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 23 Mar 2017 15:47:21 +0100

Update the BxDF sample API

On B<x|S>DF sampling return the type of the sampled component.

Diffstat:
Msrc/ssf.h | 11+++++++++++
Msrc/ssf_bsdf.c | 8+++++---
Msrc/ssf_bxdf.c | 5+++--
Msrc/ssf_lambertian_reflection.c | 4+++-
Msrc/ssf_microfacet_reflection.c | 8++++++--
Msrc/ssf_specular_reflection.c | 4+++-
Msrc/ssf_specular_transmission.c | 8++++++--
Msrc/ssf_thin_specular_dielectric.c | 7++++++-
Msrc/test_ssf_bsdf.c | 13+++++++++----
Msrc/test_ssf_bxdf.c | 11++++++++---
Msrc/test_ssf_lambertian_reflection.c | 16+++++++++++-----
Msrc/test_ssf_microfacet_reflection.c | 4+++-
Msrc/test_ssf_specular_reflection.c | 20++++++++++++++------
Msrc/test_ssf_specular_transmission.c | 19+++++++++++++------
Msrc/test_ssf_thin_specular_dielectric.c | 23+++++++++++++++++------
Msrc/test_ssf_utils.h | 3++-
16 files changed, 120 insertions(+), 44 deletions(-)

diff --git a/src/ssf.h b/src/ssf.h @@ -49,6 +49,14 @@ struct ssf_bxdf; /* Bidirectional <Reflec|Transmit>tance Distribution Function * struct ssf_fresnel; /* Equation of the Fresnel term */ struct ssf_microfacet_distribution; +enum ssf_bxdf_flag { + SSF_REFLECTION = BIT(0), + SSF_TRANSMISSION = BIT(1), + SSF_SPECULAR = BIT(2), + SSF_DIFFUSE = BIT(3), + SSF_GLOSSY = BIT(4) +}; + /* Generic BxDF type descriptor. Note that by convention the outgoing direction * `wo' and the incoming direction `wi' point outward the surface. Furthermore, * `wo' and the normal N must point on the same side of the surface. As a @@ -67,6 +75,7 @@ struct ssf_bxdf_type { const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized surface normal */ double wi[3], /* Sampled normalized incoming direction */ + int* type, /* Type of the sampled component. Combination of ssf_bxdf_flag */ double* pdf); /* PDF to sample wi wrt wo */ /* Evaluate the BxDF wrt to wo and wi */ @@ -292,6 +301,7 @@ ssf_bsdf_sample const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized surface normal */ double wi[3], /* Sampled normalized incoming direction */ + int* type, /* Type of the sampled component. Combination of ssf_bxdf_flag */ double* pdf); /* PDF to sample wi wrt wo */ SSF_API double @@ -338,6 +348,7 @@ ssf_bxdf_sample const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized surface normal */ double wi[3], /* Sampled normalized incoming direction. */ + int* type, /* Sampled BxDF type. Combination of ssf_bxdf_flag */ double* pdf); /* PDF of the sampled direction */ SSF_API double diff --git a/src/ssf_bsdf.c b/src/ssf_bsdf.c @@ -148,6 +148,7 @@ ssf_bsdf_sample const double wo[3], const double N[3], double wi[3], + int* type, double* out_pdf) { double cumul[MAX_BxDFs]; @@ -155,15 +156,16 @@ ssf_bsdf_sample double r; double pdf; size_t i; - ASSERT(bsdf && rng && wi && N && wo && out_pdf); + ASSERT(bsdf && rng && wi && N && wo && type && out_pdf); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); if(!bsdf->nbxdfs) { *out_pdf = 0; + *type = 0; return 0; } if(bsdf->nbxdfs == 1) { - return ssf_bxdf_sample(bsdf->bxdfs[0], rng, wo, N, wi, out_pdf); + return ssf_bxdf_sample(bsdf->bxdfs[0], rng, wo, N, wi, type, out_pdf); } bsdf_normalize_weights(bsdf); @@ -181,7 +183,7 @@ ssf_bsdf_sample } /* Sample a direction from the selected component */ - R = ssf_bxdf_sample(bsdf->bxdfs[i], rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(bsdf->bxdfs[i], rng, wo, N, wi, type, &pdf); *out_pdf = pdf*bsdf->weights[i]; return R; } diff --git a/src/ssf_bxdf.c b/src/ssf_bxdf.c @@ -120,11 +120,12 @@ ssf_bxdf_sample const double wo[3], const double N[3], double wi[3], + int* type, double* pdf) { - ASSERT(bxdf && rng && wo && N && wi && pdf); + ASSERT(bxdf && rng && wo && N && wi && type && pdf); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); - return bxdf->type.sample(bxdf->data, rng, wo, N, wi, pdf); + return bxdf->type.sample(bxdf->data, rng, wo, N, wi, type, pdf); } double diff --git a/src/ssf_lambertian_reflection.c b/src/ssf_lambertian_reflection.c @@ -60,16 +60,18 @@ lambertian_reflection_sample const double wo[3], const double N[3], double wi[3], + int* type, double* pdf) { double sample[4]; - ASSERT(data && rng && wo && N && wi); + ASSERT(data && rng && wo && N && wi && type && pdf); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(wo, N) > 0); (void)wo; ssp_ran_hemisphere_cos(rng, N, sample); d3_set(wi, sample); *pdf = sample[3]; + *type = SSF_REFLECTION | SSF_DIFFUSE; return ((struct lambertian_reflection*)data)->reflectivity; } diff --git a/src/ssf_microfacet_reflection.c b/src/ssf_microfacet_reflection.c @@ -86,6 +86,7 @@ microfacet_reflection_sample const double wo[3], const double N[3], double wi[3], + int* type, double* pdf) { struct microfacet_reflection* bxdf = data; @@ -93,13 +94,14 @@ microfacet_reflection_sample double wh[3]; double pdf_wh; double R; - ASSERT(data && wo && N && wi); + ASSERT(data && wo && N && wi && pdf && type); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(wo, N) > 0); ASSERT(bxdf->distrib && bxdf->fresnel); ssf_microfacet_distribution_sample(bxdf->distrib, rng, wo, N, wh, &pdf_wh); reflect(dir, wo, wh); *pdf = pdf_wh / (4.0*fabs(d3_dot(wo, wh))); + *type = SSF_REFLECTION | SSF_GLOSSY; R = d3_dot(dir, N) > 0 ? ssf_fresnel_eval(bxdf->fresnel, d3_dot(dir, wh)) : 0; d3_set(wi, dir); return R; @@ -131,6 +133,7 @@ microfacet2_reflection_sample const double wo[3], const double N[3], double wi[3], + int* type, double* pdf) { struct microfacet_reflection* bxdf = data; @@ -138,7 +141,7 @@ microfacet2_reflection_sample double wh[3]; double p; double troughput = 1; - ASSERT(data && wo && N && wi); + ASSERT(data && wo && N && wi && pdf && type); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(N, wo) > 0.0); ASSERT(bxdf->distrib); @@ -163,6 +166,7 @@ microfacet2_reflection_sample } *pdf = NaN; + *type = SSF_REFLECTION | SSF_GLOSSY; d3_set(wi, dir); return troughput; } diff --git a/src/ssf_specular_reflection.c b/src/ssf_specular_reflection.c @@ -49,18 +49,20 @@ specular_reflection_sample const double wo[3], const double N[3], double wi[3], + int* type, double* pdf) { struct specular_reflection* brdf = data; double cos_wo_N; double cos_wi_N; - ASSERT(rng && wi && N && wo && pdf); + ASSERT(rng && wi && N && wo && type && pdf); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(wo, N) > 0); (void)rng; /* Reflect the outgoing direction wo with respect to the surface normal N */ reflect(wi, wo, N); *pdf = INF; + *type = SSF_REFLECTION | SSF_SPECULAR; cos_wi_N = cos_wo_N = d3_dot(wo, N); return ssf_fresnel_eval(brdf->fresnel, cos_wi_N); diff --git a/src/ssf_specular_transmission.c b/src/ssf_specular_transmission.c @@ -52,12 +52,13 @@ specular_transmission_sample const double wo[3], const double N[3], double wi[3], + int* type, double* pdf) { struct specular_transmission* btdf = bxdf; double eta; double cos_wi_N; - ASSERT(rng && wo && N && wi && pdf); + ASSERT(rng && wo && N && wi && type && pdf); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(wo, N) > 0); (void)rng; @@ -66,11 +67,14 @@ specular_transmission_sample eta = btdf->eta_i / btdf->eta_t; if(!refract(wi, wo, N, eta)) { /* Total internal reflection */ - reflect(wi, wo, N); /* TODO ensure this */ + reflect(wi, wo, N); + *pdf = INF; + *type = SSF_REFLECTION | SSF_SPECULAR; return 0.0; } cos_wi_N = d3_dot(wi, N); *pdf = INF; + *type = SSF_TRANSMISSION | SSF_SPECULAR; return 1.0 - ssf_fresnel_eval(btdf->fresnel, fabs(cos_wi_N)); } diff --git a/src/ssf_thin_specular_dielectric.c b/src/ssf_thin_specular_dielectric.c @@ -55,6 +55,7 @@ thin_specular_dielectric_sample const double wo[3], const double N[3], double wi[3], + int* type, double* pdf) { struct thin_specular_dielectric* bsdf = bxdf; @@ -66,7 +67,7 @@ thin_specular_dielectric_sample double R, T; double rho1, rho2, rho2_sqr; double tau, tau_sqr; - ASSERT(bxdf && rng && wi && N && wo); + ASSERT(bxdf && rng && wi && N && wo && type && pdf); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); ASSERT(d3_dot(wo, N) > -1.e-6); (void)rng; @@ -74,6 +75,8 @@ thin_specular_dielectric_sample eta = bsdf->eta_i / bsdf->eta_t; if(!refract(wt, wo, N, eta)) { /* Total internal reflection */ reflect(wi, wo, N); + *pdf = INF; + *type = SSF_SPECULAR | SSF_REFLECTION; return 1; } fresnel = bsdf->fresnel; @@ -106,9 +109,11 @@ thin_specular_dielectric_sample /* Importance sample the BTDF wrt R */ if(ssp_rng_canonical(rng) < R) { /* Sample the reflective part */ reflect(wi, wo, N); + *type = SSF_SPECULAR | SSF_REFLECTION; return 1; } else { /* Sample the transmissive part */ d3_minus(wi, wo); + *type = SSF_SPECULAR | SSF_TRANSMISSION; return T; } } diff --git a/src/test_ssf_bsdf.c b/src/test_ssf_bsdf.c @@ -34,6 +34,7 @@ main(int argc, char** argv) double sum, sqr_sum; double sample[4]; size_t i; + int type; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -67,14 +68,16 @@ main(int argc, char** argv) d3_normalize(wo, d3(wo, 1, 1, 0)); d3(N, 0.0, 1.0, 0.0); - R = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &pdf); + R = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &type, &pdf); + CHECK(type, SSF_SPECULAR | SSF_REFLECTION); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, d3_dot(wi, N)), 1.e-6), 1); CHECK(ssf_bsdf_eval(bsdf, wo, N, wi), 0); CHECK(ssf_bsdf_pdf(bsdf, wo, N, wi), 0); CHECK(ssf_specular_reflection_setup(bxdf, fresnel), RES_OK); - R = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &pdf); + R = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &type, &pdf); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, d3_dot(wi, N)), 1.e-6), 1); + CHECK(type, SSF_SPECULAR | SSF_REFLECTION); CHECK(ssf_bsdf_add(bsdf, bxdf2, 1), RES_OK); @@ -85,7 +88,8 @@ main(int argc, char** argv) ssp_ran_hemisphere_uniform(rng, N, sample); d3_set(wo, sample); FOR_EACH(i, 0, NSTEPS) { - double weight = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &pdf); + double weight = ssf_bsdf_sample(bsdf, rng, wo, N, wi, &type, &pdf); + CHECK(type, SSF_SPECULAR | SSF_REFLECTION); CHECK(ssf_bsdf_eval(bsdf, wo, N, wi), 0); CHECK(ssf_bsdf_pdf(bsdf, wo, N, wi), 0); sum += weight; @@ -99,7 +103,8 @@ main(int argc, char** argv) CHECK(ssf_bsdf_clear(NULL), RES_BAD_ARG); CHECK(ssf_bsdf_clear(bsdf), RES_OK); - CHECK(ssf_bsdf_sample(bsdf, rng, wo, N, wi, &pdf), 0.0); + CHECK(ssf_bsdf_sample(bsdf, rng, wo, N, wi, &type, &pdf), 0.0); + CHECK(type, 0); CHECK(pdf, 0.0); CHECK(ssf_bsdf_ref_put(bsdf), RES_OK); diff --git a/src/test_ssf_bxdf.c b/src/test_ssf_bxdf.c @@ -58,6 +58,7 @@ bxdf_sample const double wo[3], const double N[3], double wi[3], + int* type, double* pdf) { struct bxdf* BxDF = bxdf; @@ -66,6 +67,7 @@ bxdf_sample CHECK(d3_eq(BxDF->wo, wo), 1); CHECK(d3_eq(BxDF->N, N), 1); d3(wi, 1.0, 2.0, 3.0); + *type = 314; *pdf = 4; return BxDF->reflectivity; } @@ -116,6 +118,7 @@ main(int argc, char** argv) double N[3]; double wi[4]; double pdf; + int i; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -186,11 +189,13 @@ main(int argc, char** argv) data->rng = rng; data->reflectivity = 0.1234; - CHECK(ssf_bxdf_sample(bxdf, rng, wo, N, wi, &pdf), 0.1234); - CHECK(ssf_bxdf_sample(bxdf, rng, wo, N, wi, &pdf), 0.1234); + CHECK(ssf_bxdf_sample(bxdf, rng, wo, N, wi, &i, &pdf), 0.1234); + CHECK(ssf_bxdf_sample(bxdf, rng, wo, N, wi, &i, &pdf), 0.1234); + CHECK(i, 314); + CHECK(pdf, 4); data->reflectivity = 0.314; - CHECK(ssf_bxdf_sample(bxdf, rng, wo, N, wi, &pdf), 0.314); + CHECK(ssf_bxdf_sample(bxdf, rng, wo, N, wi, &i, &pdf), 0.314); d3_normalize(wi, wi); d3_set(data->wi, wi); diff --git a/src/test_ssf_lambertian_reflection.c b/src/test_ssf_lambertian_reflection.c @@ -36,6 +36,7 @@ main(int argc, char** argv) double pdf; double R; size_t i; + int type; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -54,14 +55,16 @@ main(int argc, char** argv) d3(N, 0.0, 0.0, 1.0); d3_normalize(wo, d3(wo, 1.0, 0.0, 1.0)); - R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &type, &pdf); CHECK(eq_eps(wi[2]/PI, pdf, 1.e-6), 1); CHECK(R, 0); + CHECK(type, SSF_DIFFUSE|SSF_REFLECTION); CHECK(ssf_lambertian_reflection_setup(brdf, 0.7), RES_OK); - R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &type, &pdf); CHECK(eq_eps(R, 0.7, 1.e-6), 1); CHECK(eq_eps(pdf, d3_dot(wi, N)/PI, 1.e-6), 1); + CHECK(type, SSF_DIFFUSE|SSF_REFLECTION); d3_normalize(wo, d3(wo, 1.0, 0.0, 1.0)); N[0] = ssp_rng_uniform_double(rng, -1, 1); @@ -74,10 +77,11 @@ main(int argc, char** argv) sum = sum_sqr = 0; FOR_EACH(i, 0, NSTEPS) { double cos_wi_N; - R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf) / PI; + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &type, &pdf) / PI; cos_wi_N = d3_dot(wi, N); CHECK(eq_eps(R, 0.7/PI, 1.e-6), 1); CHECK(eq_eps(cos_wi_N/PI, pdf, 1.e-6), 1); + CHECK(type, SSF_DIFFUSE|SSF_REFLECTION); sum += cos_wi_N; sum_sqr += cos_wi_N * cos_wi_N; } @@ -91,10 +95,11 @@ main(int argc, char** argv) double cos_wi_N; double w; - R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf)/PI; + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &type, &pdf)/PI; cos_wi_N = d3_dot(wi, N); CHECK(eq_eps(R, 0.7/PI, 1.e-6), 1); CHECK(eq_eps(cos_wi_N/PI, pdf, 1.e-6), 1); + CHECK(type, SSF_DIFFUSE|SSF_REFLECTION); w = cos_wi_N*cos_wi_N; sum += w; sum_sqr += w*w; @@ -108,10 +113,11 @@ main(int argc, char** argv) FOR_EACH(i, 0, NSTEPS) { double val; - R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &type, &pdf); CHECK(eq_eps(R, 0.7, 1.e-6), 1); val = ssf_bxdf_eval(brdf, wo, N, wi) * d3_dot(wi, N); CHECK(eq_eps(val, R * pdf, 1.e-6), 1); + CHECK(type, SSF_DIFFUSE|SSF_REFLECTION); } CHECK(ssf_bxdf_ref_put(brdf), RES_OK); diff --git a/src/test_ssf_microfacet_reflection.c b/src/test_ssf_microfacet_reflection.c @@ -57,7 +57,9 @@ main(int argc, char** argv) ssp_ran_hemisphere_cos(rng, N, wo); FOR_EACH(i, 0, NSTEPS) { double wi[3], pdf; - CHECK(ssf_bxdf_sample(bxdf, rng, wo, N, wi, &pdf), 1); + int type; + CHECK(ssf_bxdf_sample(bxdf, rng, wo, N, wi, &type, &pdf), 1); + CHECK(type, SSF_GLOSSY | SSF_REFLECTION); CHECK(d3_dot(wi, N) > 0, 1); } diff --git a/src/test_ssf_specular_reflection.c b/src/test_ssf_specular_reflection.c @@ -32,6 +32,7 @@ main(int argc, char** argv) double pdf; double R; /* Directional reflectance */ size_t i; + int type; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -50,40 +51,47 @@ main(int argc, char** argv) d3(N, 0.0, 1.0, 0.0); d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0)); - R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &type, &pdf); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, d3_dot(N, wi)), 1.e-6), 1); CHECK(IS_INF(pdf), 1); + CHECK(type, SSF_SPECULAR|SSF_REFLECTION); d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0)); CHECK(ssf_specular_reflection_setup(brdf, fresnel), RES_OK); - R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &type, &pdf); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, d3_dot(N, wi)), 1.e-6), 1); CHECK(IS_INF(pdf), 1); CHECK(d3_eq_eps(d3(wo, -wo[0], wo[1], 0.0), wi, 1.e-6), 1); + CHECK(type, SSF_SPECULAR|SSF_REFLECTION); CHECK(ssf_bxdf_eval(brdf, wo, N, wi), 0.0); CHECK(ssf_bxdf_pdf(brdf, wo, N, wi), 0.0); d3(wo, 0.0, 1.0, 0.0); - R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &type, &pdf); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, d3_dot(N, wi)), 1.e-6), 1); CHECK(IS_INF(pdf), 1); CHECK(d3_eq_eps(d3(wo, 0.0, 1.0, 0.0), wi, 1.e-6), 1); + CHECK(type, SSF_SPECULAR|SSF_REFLECTION); d3_normalize(wo, d3(wo, -1.0, 1.0, 0.0)); - R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &type, &pdf); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, d3_dot(N, wi)), 1.e-6), 1); CHECK(IS_INF(pdf), 1); CHECK(d3_eq_eps(d3(wo, -wo[0], wo[1], 0.0), wi, 1.e-6), 1); + CHECK(type, SSF_SPECULAR|SSF_REFLECTION); wo[0] = ssp_rng_uniform_double(rng, -1, 1); wo[1] = ssp_rng_uniform_double(rng, 0, 1); wo[2] = ssp_rng_uniform_double(rng, -1, 1); d3_normalize(wo, wo); - R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &type, &pdf); + CHECK(type, SSF_SPECULAR|SSF_REFLECTION); FOR_EACH(i, 0, NSTEPS) { - CHECK(eq_eps(ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf), R, 1.e-6), 1); + CHECK(eq_eps(ssf_bxdf_sample + (brdf, rng, wo, N, wi, &type, &pdf), R, 1.e-6), 1); + CHECK(type, SSF_SPECULAR|SSF_REFLECTION); } CHECK(ssf_bxdf_ref_put(brdf), RES_OK); diff --git a/src/test_ssf_specular_transmission.c b/src/test_ssf_specular_transmission.c @@ -31,6 +31,7 @@ main(int argc, char** argv) double N[3]; double pdf; double R; + int type; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -53,36 +54,42 @@ main(int argc, char** argv) d3(N, 0.0, 1.0, 0.0); d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0)); - R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &type, &pdf); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, fabs(d3_dot(N, wi))), 1.e-6), RES_OK); CHECK(d3_eq_eps(wi, d3_minus(tmp, wo), 1.e-6), 0); CHECK(wi[1] < 0, 1); CHECK(IS_INF(pdf), 1); + CHECK(type, SSF_SPECULAR|SSF_TRANSMISSION); CHECK(ssf_bxdf_eval(btdf, wo, N, wi), 0.0); CHECK(ssf_bxdf_pdf(btdf, wo, N, wi), 0.0); d3(wo, 0.0, 1.0, 0.0); - R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &type, &pdf); CHECK(eq_eps(R, ssf_fresnel_eval(fresnel, fabs(d3_dot(N, wi))), 1.e-6), RES_OK); CHECK(IS_INF(pdf), 1); CHECK(d3_eq_eps(wi, d3_minus(tmp, wo), 1.e-6), 1); + CHECK(type, SSF_SPECULAR|SSF_TRANSMISSION); d3_normalize(wo, d3(wo, -1.0, 1.0, 0.0)); - R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &type, &pdf); reflect(tmp, wi, N); + CHECK(type, SSF_SPECULAR|SSF_TRANSMISSION); d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0)); - R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &type, &pdf); CHECK(d3_eq_eps(wi, tmp, 1.e-6), 1); + CHECK(type, SSF_SPECULAR|SSF_TRANSMISSION); d3_normalize(wo, d3(wo, -1, 1.e-6, 0)); - R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &type, &pdf); CHECK(eq_eps(R, 0, 1.e-3), 1); + CHECK(type, SSF_SPECULAR|SSF_TRANSMISSION); /* Check total internal reflection */ CHECK(ssf_specular_transmission_setup(btdf, 1.5, 1.00027), RES_OK); - R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(btdf, rng, wo, N, wi, &type, &pdf); CHECK(eq_eps(R, 0, 1.e-3), 1); + CHECK(type, SSF_SPECULAR|SSF_REFLECTION); CHECK(ssf_fresnel_ref_put(fresnel), RES_OK); CHECK(ssf_bxdf_ref_put(btdf), RES_OK); diff --git a/src/test_ssf_thin_specular_dielectric.c b/src/test_ssf_thin_specular_dielectric.c @@ -34,6 +34,7 @@ main(int argc, char** argv) double pdf; double R; /* Directional reflectance */ size_t i; + int type; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -80,8 +81,9 @@ main(int argc, char** argv) d3(N, 0.0, 1.0, 0.0); d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0)); - R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &type, &pdf); NCHECK(R, 0); + NCHECK(type & SSF_SPECULAR, 0); CHECK(IS_INF(pdf), 1); CHECK(d3_eq_eps(wi, d3(tmp, -wo[0], wo[1], 0), 1.e-6) || d3_eq_eps(wi, d3(tmp, -wo[0], -wo[1], 0), 1.e-6), 1); @@ -90,24 +92,27 @@ main(int argc, char** argv) CHECK(ssf_bxdf_pdf(bsdf, wo, N, wi), 0.0); d3(wo, 0.0, 1.0, 0.0); - R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &type, &pdf); NCHECK(R, 0); CHECK(IS_INF(pdf), 1); CHECK(d3_eq_eps(wi, d3(tmp, -wo[0], -wo[1], 0), 1.e-6), 1); + CHECK(type, SSF_SPECULAR | SSF_TRANSMISSION); d3(wo, 1.0, 0.0, 0.0); - R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &type, &pdf); NCHECK(R, 0); CHECK(IS_INF(pdf), 1); CHECK(d3_eq_eps(wi, d3(tmp, -wo[0], wo[1], 0), 1.e-6), 1); + CHECK(type, SSF_SPECULAR | SSF_REFLECTION); /* Check total internal reflection, i.e. no transmission */ d3_normalize(wo, d3(wo, 1, 0.0000001, 0)); CHECK(ssf_thin_specular_dielectric_setup(bsdf, 0, 1.4, 1.0, 1), RES_OK); - R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &type, &pdf); NCHECK(R, 0); CHECK(IS_INF(pdf), 1); CHECK(d3_eq_eps(wi, d3(tmp, -wo[0], wo[1], 0), 1.e-6), 1); + CHECK(type, SSF_SPECULAR | SSF_REFLECTION); wo[0] = ssp_rng_uniform_double(rng, -1, 1); wo[1] = ssp_rng_uniform_double(rng, -1, 1); @@ -117,10 +122,16 @@ main(int argc, char** argv) d3_minus(refract, wo); FOR_EACH(i, 0, NSTEPS) { - R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &pdf); + R = ssf_bxdf_sample(bsdf, rng, wo, N, wi, &type, &pdf); NCHECK(R, 0); CHECK(IS_INF(pdf), 1); - CHECK(d3_eq_eps(wi, reflect, 1.e-6) || d3_eq_eps(wi, refract, 1e-6), 1); + if(d3_eq_eps(wi, reflect, 1.e-6)) { + CHECK(type, SSF_SPECULAR | SSF_REFLECTION); + } else if(d3_eq_eps(wi, refract, 1e-6), 1) { + CHECK(type, SSF_SPECULAR | SSF_TRANSMISSION); + } else { + FATAL("Unexpected value.\n"); + } } CHECK(ssp_rng_ref_put(rng), RES_OK); diff --git a/src/test_ssf_utils.h b/src/test_ssf_utils.h @@ -51,9 +51,10 @@ bxdf_dummy_sample const double w[3], const double N[3], double dir[3], + int* type, double* pdf) { - (void)bxdf, (void)rng, (void)w, (void)N, (void)dir, (void)pdf; + (void)bxdf, (void)rng, (void)w, (void)N, (void)dir, (void)type, (void)pdf; return 0.0; }