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 400afff2a9e06aab7cf7ff554c4317ee8382f77e
parent b01aea4e75394c4a4ec7b7123a76a1b98ce50638
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 22 Mar 2017 09:53:28 +0100

Check that `wo' and `N' points on the same side

Assert if the submitted outgoing direction `wo' does not point on the
same side of `N' on BxDF sampling/evaluation. For BRDF, assert if the
incoming direction `wi' does not point on the same hemisphere of N. For
BTDF, assert if `wi' does not point on the opposite side of N.

Diffstat:
Msrc/ssf.h | 10++++++++--
Msrc/ssf_fresnel_dielectric_conductor.c | 2+-
Msrc/ssf_fresnel_dielectric_dielectric.c | 2+-
Msrc/ssf_lambertian_reflection.c | 9++++-----
Msrc/ssf_microfacet_reflection.c | 15+++++++--------
Msrc/ssf_specular_reflection.c | 6+++---
Msrc/test_ssf_lambertian_reflection.c | 9---------
Msrc/test_ssf_specular_reflection.c | 13+------------
Msrc/test_ssf_specular_transmission.c | 1-
9 files changed, 25 insertions(+), 42 deletions(-)

diff --git a/src/ssf.h b/src/ssf.h @@ -50,7 +50,10 @@ struct ssf_fresnel; /* Equation of the Fresnel term */ struct ssf_microfacet_distribution; /* Generic BxDF type descriptor. Note that by convention the outgoing direction - * `wo' and the incoming direction `wi' point outward the surface. */ + * `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 + * consequence the reflected or refracted direction `wi' must point on the same + * side or on the opposite side of `N', respectively. */ struct ssf_bxdf_type { res_T (*init)(struct mem_allocator* allocator, void* bxdf); void (*release)(void* bxdf); @@ -246,7 +249,10 @@ SSF_API const struct ssf_microfacet_distribution_type ssf_blinn_distribution; * BSDF API - Bidirectional Scattering Distribution Function. Describes the * 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. + * `wi' point outward the surface. Furthermore, `wo' and the normal `N' must + * point on the same side of the surface. As a consequence the reflected or + * refracted direction `wi' must point on the same side or on the opposite side + * of `N', respectively. ******************************************************************************/ SSF_API res_T ssf_bsdf_create diff --git a/src/ssf_fresnel_dielectric_conductor.c b/src/ssf_fresnel_dielectric_conductor.c @@ -59,7 +59,7 @@ fresnel_dielectric_conductor_eval(void* fresnel, const double cos_theta_i) double a; double a2_add_b2; double Rp, Rs; - ASSERT(fresnel && cos_theta_i >= 0); + ASSERT(fresnel && cos_theta_i >= 0 && fc->eta_i > 0); cos_theta_i2 = cos_theta_i * cos_theta_i; sin_theta_i2 = 1.0 - cos_theta_i2; diff --git a/src/ssf_fresnel_dielectric_dielectric.c b/src/ssf_fresnel_dielectric_dielectric.c @@ -53,7 +53,7 @@ fresnel_dielectric_dielectric_eval(void* fresnel, const double cos_theta_i) double cos_theta_t; double Rp; /* Parallel */ double Rs; /* Orthogonal */ - ASSERT(fresnel && cos_theta_i >= 0); + ASSERT(fresnel && cos_theta_i >= 0 && fd->eta_t > 0 && fd->eta_i > 0); /* Use Snell's low to retrieve cos_theta_t: * eta_i * sin_theta_i = eta_t * sin_theta_t */ diff --git a/src/ssf_lambertian_reflection.c b/src/ssf_lambertian_reflection.c @@ -46,12 +46,11 @@ lambertian_reflection_eval (void* data, const double wo[3], const double N[3], const double wi[3]) { struct lambertian_reflection* brdf = data; - 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; + ASSERT(d3_dot(wi, N) > 0 && d3_dot(wo, N) > 0); + (void)wo, (void)N, (void)wi; + return brdf->reflectivity / PI; } static double @@ -65,7 +64,7 @@ lambertian_reflection_sample { double sample[4]; ASSERT(data && rng && wo && N && wi); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(wo, N) > 0); (void)wo; ssp_ran_hemisphere_cos(rng, N, sample); diff --git a/src/ssf_microfacet_reflection.c b/src/ssf_microfacet_reflection.c @@ -60,9 +60,11 @@ microfacet_reflection_eval ASSERT(bxdf && bxdf->fresnel && bxdf->distrib); ASSERT(wo && N && wi); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wi)); + ASSERT(d3_dot(wo, N) > 0 && d3_dot(wi, N) > 0); + + cos_wi_N = d3_dot(wi, N); + cos_wo_N = d3_dot(wo, N); - if((cos_wo_N = d3_dot(wo, N)) <= 0) return 0.0; - if((cos_wi_N = d3_dot(wi, N)) <= 0) return 0.0; d3_normalize(wh, d3_add(wh, wo, wi)); cos_wh_N = d3_dot(wh, N); cos_wh_wi = d3_dot(wh, wi); @@ -92,11 +94,9 @@ microfacet_reflection_sample double pdf_wh; double R; ASSERT(data && wo && N && wi); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(wo, N) > 0); ASSERT(bxdf->distrib && bxdf->fresnel); - if(d3_dot(wo, N) <= 0.0) return 0.0; - 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))); @@ -114,6 +114,7 @@ microfacet_reflection_pdf double pdf_wh; ASSERT(data && wo && N && wi); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wi)); + ASSERT(d3_dot(wo, N) > 0 && d3_dot(wi, N) > 0); ASSERT(bxdf->distrib); d3_normalize(wh, d3_add(wh, wi, wo)); pdf_wh = ssf_microfacet_distribution_pdf(bxdf->distrib, wo, N, wh); @@ -138,11 +139,9 @@ microfacet2_reflection_sample double p; double troughput = 1; ASSERT(data && wo && N && wi); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(N, wo) > 0.0); ASSERT(bxdf->distrib); - if(d3_dot(wo, N) <= 0.0) return 0.0; - do { /* Sample a micro facet that front faces 'wo' */ ssf_microfacet_distribution_sample(bxdf->distrib, rng, wo, N, wh, &p); } while(d3_dot(wo, wh) <= 0); diff --git a/src/ssf_specular_reflection.c b/src/ssf_specular_reflection.c @@ -54,8 +54,8 @@ specular_reflection_sample struct specular_reflection* brdf = data; double cos_wo_N; double cos_wi_N; - ASSERT(rng && wi && N && wo); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); + ASSERT(rng && wi && N && wo && 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 */ @@ -63,7 +63,7 @@ specular_reflection_sample *pdf = INF; cos_wi_N = cos_wo_N = d3_dot(wo, N); - return cos_wo_N > 0 ? ssf_fresnel_eval(brdf->fresnel, cos_wi_N) : 0; + return ssf_fresnel_eval(brdf->fresnel, cos_wi_N); } static double diff --git a/src/test_ssf_lambertian_reflection.c b/src/test_ssf_lambertian_reflection.c @@ -63,15 +63,6 @@ main(int argc, char** argv) CHECK(eq_eps(R, 0.7, 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, rng, wo, N, wi, &pdf); - CHECK(R, 0.7); - - d3_normalize(wo, d3(wo, 1.0, 1.0, 0.0)); - R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); - CHECK(eq_eps(R, 0.7, 1.e-6), 1); - CHECK(eq_eps(R, ssf_bxdf_eval(brdf, wo, N, wi)*PI, 1.e-6), 1); - d3_normalize(wo, d3(wo, 1.0, 0.0, 1.0)); N[0] = ssp_rng_uniform_double(rng, -1, 1); N[1] = ssp_rng_uniform_double(rng, -1, 1); diff --git a/src/test_ssf_specular_reflection.c b/src/test_ssf_specular_reflection.c @@ -76,19 +76,8 @@ main(int argc, char** argv) CHECK(IS_INF(pdf), 1); CHECK(d3_eq_eps(d3(wo, -wo[0], wo[1], 0.0), wi, 1.e-6), 1); - d3(wo, 0.0, -1.0, 0.0); - R = ssf_bxdf_sample(brdf, rng, wo, N, wi, &pdf); - CHECK(eq_eps(R, 0, 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); - - d3(wo, 1.0, 0.0, 0.0); - R = ssf_bxdf_sample(brdf, rng, 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); - wo[0] = ssp_rng_uniform_double(rng, -1, 1); - wo[1] = 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); diff --git a/src/test_ssf_specular_transmission.c b/src/test_ssf_specular_transmission.c @@ -22,7 +22,6 @@ int main(int argc, char** argv) { - const size_t NSTEPS = 100000; struct mem_allocator allocator; struct ssp_rng* rng; struct ssf_bxdf* btdf;