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:
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;