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 8cb11ef86de32190de430a0337b5d4304383b386
parent 632fda2019338e3f0eb05624ab46c1b60fb377d7
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Tue, 21 Nov 2017 09:41:47 +0100

Upd the microfacet distribution API and fix the Blinn distribution

Remove the useless 'wo' parameter, i.e. the outgoing direction, from the
microfacet distribution API.

Diffstat:
Msrc/ssf.h | 8+-------
Msrc/ssf_beckmann_distribution.c | 18+++++++-----------
Msrc/ssf_blinn_distribution.c | 33+++++++++++----------------------
Msrc/ssf_microfacet_distribution.c | 21+++++++++------------
Msrc/ssf_microfacet_reflection.c | 14+++++++-------
Msrc/test_ssf_microfacet_distribution.c | 22+++++-----------------
Msrc/test_ssf_utils.h | 27+++++++--------------------
7 files changed, 47 insertions(+), 96 deletions(-)

diff --git a/src/ssf.h b/src/ssf.h @@ -124,22 +124,19 @@ struct ssf_microfacet_distribution_type { (*sample) (void* distrib, struct ssp_rng* rng, /* Random number generator */ - const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized Z-direction of the distribution */ double wh[3], /* Sampled normalized half vector */ - double* pdf); /* PDF to sample wh wrt to wo */ + double* pdf); /* PDF to sample wh */ double (*eval) (void* distrib, - const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized Z-direction of the distribution */ const double wh[3]); /* Normalized half vector */ double (*pdf) (void* distrib, - const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized Z-direction of the distribution */ const double wh[3]); /* Normalized half vector */ @@ -413,7 +410,6 @@ ssf_microfacet_distribution_ref_put SSF_API double ssf_microfacet_distribution_eval (struct ssf_microfacet_distribution* distrib, - const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized Z-direction of the distribution */ const double wh[3]); /* Normalized half vector */ @@ -421,7 +417,6 @@ SSF_API void ssf_microfacet_distribution_sample (struct ssf_microfacet_distribution* distrib, struct ssp_rng* rng, /* Random number generator */ - const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized Z-direction of the distribution */ double wh[3], /* Normalized half vector */ double* pdf); /* PDF of the sampled half vector */ @@ -429,7 +424,6 @@ ssf_microfacet_distribution_sample SSF_API double ssf_microfacet_distribution_pdf (struct ssf_microfacet_distribution* distrib, - const double wo[3], /* Normalized outgoing direction */ const double N[3], /* Normalized Z-direction of the distribution */ const double wh[3]); /* Normalized half vector */ diff --git a/src/ssf_beckmann_distribution.c b/src/ssf_beckmann_distribution.c @@ -43,15 +43,14 @@ beckmann_distribution_release(void* distrib) static double beckmann_distribution_eval - (void* distrib, const double wo[3], const double N[3], const double wh[3]) + (void* distrib, const double N[3], const double wh[3]) { struct beckmann_distribution* beckmann = distrib; double cos_wh_N, cos2_wh_N, sin2_wh_N, cos4_wh_N; double m2; - ASSERT(distrib && wo && N && wh); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh)); + ASSERT(distrib && N && wh); + ASSERT(d3_is_normalized(N) && d3_is_normalized(wh)); ASSERT(beckmann->roughness > 0); - (void)wo; m2 = beckmann->roughness * beckmann->roughness; cos_wh_N = d3_dot(wh, N); cos2_wh_N = cos_wh_N * cos_wh_N; @@ -64,7 +63,6 @@ static void beckmann_distribution_sample (void* distrib, struct ssp_rng* rng, - const double wo[3], const double N[3], double wh[3], double* pdf) @@ -79,9 +77,8 @@ beckmann_distribution_sample double cos_theta, sin_theta; double cos2_theta, sin2_theta; double u, v; - ASSERT(rng && wh && N && wo); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); - (void)wo; + ASSERT(rng && wh && N); + ASSERT(d3_is_normalized(N)); u = ssp_rng_canonical(rng); v = ssp_rng_canonical(rng); @@ -104,14 +101,13 @@ beckmann_distribution_sample static double beckmann_distribution_pdf - (void* distrib, const double wo[3], const double N[3], const double wh[3]) + (void* distrib, const double N[3], const double wh[3]) { struct beckmann_distribution* beckmann = distrib; double cos_wh_N, cos2_wh_N, sin2_wh_N; double m2; - ASSERT(distrib && wo && N && wh); + ASSERT(distrib && N && wh); ASSERT(d3_is_normalized(wh) && d3_is_normalized(N)); - (void)wo; cos_wh_N = d3_dot(wh, N); if(cos_wh_N < 0.0) return 0.0; m2 = beckmann->roughness * beckmann->roughness; diff --git a/src/ssf_blinn_distribution.c b/src/ssf_blinn_distribution.c @@ -42,16 +42,14 @@ blinn_distribution_release(void* distrib) { (void)distrib; } static double -blinn_distribution_eval - (void* distrib, const double wo[3], const double N[3], const double wh[3]) +blinn_distribution_eval(void* distrib, const double N[3], const double wh[3]) { struct blinn_distribution* blinn = distrib; double cos_wh_N; - ASSERT(distrib && wo && N && wh); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh)); + ASSERT(distrib && N && wh); + ASSERT(d3_is_normalized(N) && d3_is_normalized(wh)); ASSERT(blinn->exponent >= 0.0); ASSERT(blinn->exponent <= SSF_BLINN_DISTRIBUTION_MAX_EXPONENT); - (void)wo; cos_wh_N = d3_dot(wh, N); return (blinn->exponent + 2) / (2*PI) * pow(cos_wh_N, blinn->exponent); } @@ -60,7 +58,6 @@ static void blinn_distribution_sample (void* distrib, struct ssp_rng* rng, - const double wo[3], const double N[3], double wh[3], double* pdf) @@ -69,11 +66,10 @@ blinn_distribution_sample double basis[9]; double dir[3]; double cos_theta, sin_theta; - double cos_wh_wo; double phi; double u, v; - ASSERT(distrib && rng && wo && N && wh && pdf); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); + ASSERT(distrib && rng && N && wh && pdf); + ASSERT(d3_is_normalized(N)); u = ssp_rng_canonical(rng); v = ssp_rng_canonical(rng); @@ -86,26 +82,19 @@ blinn_distribution_sample dir[2] = cos_theta; d33_muld3(dir, d33_basis(basis, N), dir); - cos_wh_wo = d3_dot(dir, wo); - *pdf = cos_wh_wo > 0 - ? (blinn->exponent+1)*pow(cos_theta, blinn->exponent) / (2*PI*4*cos_wh_wo) - : 0; + *pdf = (blinn->exponent+2)/(2*PI)*pow(cos_theta, blinn->exponent+1); d3_set(wh, dir); } static double -blinn_distribution_pdf - (void* distrib, const double wo[3], const double N[3], const double wh[3]) +blinn_distribution_pdf(void* distrib, const double N[3], const double wh[3]) { struct blinn_distribution* blinn = distrib; - double cos_wh_N, cos_wh_wo; - ASSERT(distrib && wo && N && wh); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh)); - cos_wh_wo = d3_dot(wo, wh); - if(cos_wh_wo <= 0) return 0.0; + double cos_wh_N; + ASSERT(distrib && N && wh); + ASSERT(d3_is_normalized(N) && d3_is_normalized(wh)); cos_wh_N = fabs(d3_dot(wh, N)); - return - ((blinn->exponent+1)*pow(cos_wh_N, blinn->exponent)) / (2*PI*4*cos_wh_wo); + return (blinn->exponent+2)/(2*PI)*pow(cos_wh_N, blinn->exponent+1); } /******************************************************************************* diff --git a/src/ssf_microfacet_distribution.c b/src/ssf_microfacet_distribution.c @@ -122,38 +122,35 @@ void ssf_microfacet_distribution_sample (struct ssf_microfacet_distribution* distrib, struct ssp_rng* rng, - const double wo[3], const double N[3], double wh[3], double* pdf) { - ASSERT(distrib && rng && wo && N && wh && pdf); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); - distrib->type.sample(distrib->data, rng, wo, N, wh, pdf); + ASSERT(distrib && rng && N && wh && pdf); + ASSERT(d3_is_normalized(N)); + distrib->type.sample(distrib->data, rng, N, wh, pdf); } double ssf_microfacet_distribution_eval (struct ssf_microfacet_distribution* distrib, - const double wo[3], const double N[3], const double wh[3]) { - ASSERT(distrib && wo && N && wh); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh)); - return distrib->type.eval(distrib->data, wo, N, wh); + ASSERT(distrib && N && wh); + ASSERT(d3_is_normalized(N) && d3_is_normalized(wh)); + return distrib->type.eval(distrib->data, N, wh); } double ssf_microfacet_distribution_pdf (struct ssf_microfacet_distribution* distrib, - const double wo[3], const double N[3], const double wh[3]) { - ASSERT(distrib && wh && wo); - ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh)); - return distrib->type.pdf(distrib->data, wo, N, wh); + ASSERT(distrib && wh ); + ASSERT(d3_is_normalized(N) && d3_is_normalized(wh)); + return distrib->type.pdf(distrib->data, N, wh); } res_T diff --git a/src/ssf_microfacet_reflection.c b/src/ssf_microfacet_reflection.c @@ -71,7 +71,7 @@ microfacet_reflection_eval cos_wh_wo = cos_wh_wi; F = ssf_fresnel_eval(bsdf->fresnel, cos_wh_wi); - D = ssf_microfacet_distribution_eval(bsdf->distrib, wo, N, wh); + D = ssf_microfacet_distribution_eval(bsdf->distrib, N, wh); /* Cook Torrance geometry term */ G = MMIN((2*cos_wh_N*cos_wo_N)/cos_wh_wo, (2*cos_wh_N*cos_wi_N)/cos_wh_wo); G = MMIN(1, G); @@ -98,9 +98,9 @@ microfacet_reflection_sample ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_dot(wo, N) > 0); ASSERT(bsdf->distrib && bsdf->fresnel); - ssf_microfacet_distribution_sample(bsdf->distrib, rng, wo, N, wh, &pdf_wh); + ssf_microfacet_distribution_sample(bsdf->distrib, rng, N, wh, &pdf_wh); reflect(dir, wo, wh); - *pdf = pdf_wh / (4.0*fabs(d3_dot(wo, wh))); + *pdf = pdf_wh / (4.0*fabs(d3_dot(wo, N))); *type = SSF_REFLECTION | SSF_GLOSSY; R = d3_dot(dir, N) > 0 ? ssf_fresnel_eval(bsdf->fresnel, d3_dot(dir, wh)) : 0; d3_set(wi, dir); @@ -119,8 +119,8 @@ microfacet_reflection_pdf ASSERT(d3_dot(wo, N) > 0 && d3_dot(wi, N) > 0); ASSERT(bsdf->distrib); d3_normalize(wh, d3_add(wh, wi, wo)); - pdf_wh = ssf_microfacet_distribution_pdf(bsdf->distrib, wo, N, wh); - return pdf_wh / (4.0*fabs(d3_dot(wo, wh))); + pdf_wh = ssf_microfacet_distribution_pdf(bsdf->distrib, N, wh); + return pdf_wh / (4.0*fabs(d3_dot(wo, N))); } /******************************************************************************* @@ -146,7 +146,7 @@ microfacet2_reflection_sample ASSERT(bsdf->distrib); do { /* Sample a micro facet that front faces 'wo' */ - ssf_microfacet_distribution_sample(bsdf->distrib, rng, wo, N, wh, &p); + ssf_microfacet_distribution_sample(bsdf->distrib, rng, N, wh, &p); } while(d3_dot(wo, wh) <= 0); reflect(dir, wo, wh); @@ -160,7 +160,7 @@ microfacet2_reflection_sample /* Handle directions that point toward the macro surface has * inter-reflections */ do { /* Sample a microfacet that front faces 'wi' */ - ssf_microfacet_distribution_sample(bsdf->distrib, rng, dir, N, wh, &p); + ssf_microfacet_distribution_sample(bsdf->distrib, rng, N, wh, &p); } while(d3_dot(dir, wh) <= 0); reflect(dir, dir, wh); } diff --git a/src/test_ssf_microfacet_distribution.c b/src/test_ssf_microfacet_distribution.c @@ -24,7 +24,6 @@ struct ALIGN(64) ufacet { uint32_t id; struct ssp_rng* rng; double wh[3]; - double wo[3]; double N[3]; double pdf; double value; @@ -53,19 +52,16 @@ static void ufacet_sample (void* distrib, struct ssp_rng* rng, - const double wo[3], const double N[3], double wh[3], double* pdf) { struct ufacet* ufacet = distrib; NCHECK(ufacet, NULL); - NCHECK(wo, NULL); NCHECK(N, NULL); NCHECK(wh, NULL); NCHECK(pdf, NULL); CHECK(ufacet->rng, rng); - CHECK(d3_eq(ufacet->wo, wo), 1); CHECK(d3_eq(ufacet->N, N), 1); d3_normalize(wh, d3(wh, 1.0, 2.0, 3.0)); *pdf = ufacet->pdf; @@ -74,16 +70,13 @@ ufacet_sample static double ufacet_eval (void* distrib, - const double wo[3], const double N[3], const double wh[3]) { struct ufacet* ufacet = distrib; NCHECK(distrib, NULL); - NCHECK(wo, NULL); NCHECK(N, NULL); NCHECK(wh, NULL); - CHECK(d3_eq(ufacet->wo, wo), 1); CHECK(d3_eq(ufacet->wh, wh), 1); CHECK(d3_eq(ufacet->N, N), 1); return ufacet->value; @@ -92,15 +85,12 @@ ufacet_eval static double ufacet_pdf (void* distrib, - const double wo[3], const double N[3], const double wh[3]) { struct ufacet* ufacet = distrib; - NCHECK(wo, NULL); NCHECK(N, NULL); NCHECK(wh, NULL); - CHECK(d3_eq(ufacet->wo, wo), 1); CHECK(d3_eq(ufacet->wh, wh), 1); CHECK(d3_eq(ufacet->N, N), 1); return ufacet->pdf; @@ -115,7 +105,7 @@ main(int argc, char** argv) SSF_MICROFACET_DISTRIBUTION_TYPE_NULL; struct ssf_microfacet_distribution* distrib; struct ssp_rng* rng; - double wo[3], N[3], wh[3], pdf; + double N[3], wh[3], pdf; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -182,24 +172,22 @@ main(int argc, char** argv) CHECK(ssf_microfacet_distribution_get_data(distrib, (void**)&data), RES_OK); CHECK(data->id, 0xDECAFBAD); - d3_normalize(wo, d3(wo, -1, -1, 0)); d3(N, 0.0, 1.0, 0.0); - d3_set(data->wo, wo); d3_set(data->N, N); d3_normalize(data->wh, d3(data->wh, 1, 2, 3)); data->rng = rng; data->pdf = 0.1234; data->value = 0.43; - ssf_microfacet_distribution_sample(distrib, rng, wo, N, wh, &pdf); + ssf_microfacet_distribution_sample(distrib, rng, N, wh, &pdf); CHECK(d3_eq(wh, data->wh), 1); CHECK(pdf, data->pdf); - ssf_microfacet_distribution_sample(distrib, rng, wo, N, wh, &pdf); + ssf_microfacet_distribution_sample(distrib, rng, N, wh, &pdf); CHECK(d3_eq(wh, data->wh), 1); CHECK(pdf, data->pdf); - CHECK(ssf_microfacet_distribution_eval(distrib, wo, N, wh), data->value); - CHECK(ssf_microfacet_distribution_pdf(distrib, wo, N, wh), data->pdf); + CHECK(ssf_microfacet_distribution_eval(distrib, N, wh), data->value); + CHECK(ssf_microfacet_distribution_pdf(distrib, N, wh), data->pdf); CHECK(ssf_microfacet_distribution_ref_put(distrib), RES_OK); CHECK(ufacet_is_init, 0); diff --git a/src/test_ssf_utils.h b/src/test_ssf_utils.h @@ -141,33 +141,30 @@ static void microfacet_dummy_sample (void* distrib, struct ssp_rng* rng, - const double w[3], const double N[3], double dir[3], double* pdf) { - (void)distrib, (void)rng, (void)w, (void)N, (void)dir, (void)pdf; + (void)distrib, (void)rng, (void)N, (void)dir, (void)pdf; } static double microfacet_dummy_eval (void* distrib, - const double wo[3], const double N[3], const double wi[3]) { - (void)distrib, (void)wo, (void)N, (void)wi; + (void)distrib, (void)N, (void)wi; return 0.0; } static double microfacet_dummy_pdf (void* distrib, - const double wo[3], const double N[3], const double wi[3]) { - (void)distrib, (void)wo, (void)N, (void)wi; + (void)distrib, (void)N, (void)wi; return 0.0; } @@ -192,7 +189,6 @@ check_microfacet_distribution const size_t NSTEPS = 10000; size_t i; size_t n; - double wo[3]; double sample[4]; double E, V, SE; double sum, sum2; @@ -202,9 +198,6 @@ check_microfacet_distribution N[2] = ssp_rng_uniform_double(rng, -1, 1); d3_normalize(N, N); - ssp_ran_hemisphere_uniform(rng, N, sample); - d3_set(wo, sample); - /* Check that D(wh) is normalized wrt \int_{2PI} D(wh) |wh.n| dwh */ sum = sum2 = 0; n = 0; @@ -214,7 +207,7 @@ check_microfacet_distribution ssp_ran_hemisphere_cos(rng, N, sample); d3_set(wh, sample); pdf = sample[3]; - D = ssf_microfacet_distribution_eval(distrib, wo, N, wh); + D = ssf_microfacet_distribution_eval(distrib, N, wh); weight = D * d3_dot(wh, N) / pdf; sum += weight; sum2 += weight*weight; @@ -230,17 +223,11 @@ check_microfacet_distribution FOR_EACH(i, 0, NSTEPS) { double wh[3], pdf, D, weight; - ssf_microfacet_distribution_sample(distrib, rng, wo, N, wh, &pdf); - D = ssf_microfacet_distribution_eval(distrib, wo, N, wh); + ssf_microfacet_distribution_sample(distrib, rng, N, wh, &pdf); + D = ssf_microfacet_distribution_eval(distrib, N, wh); weight = D * d3_dot(wh, N) / pdf; - sum += weight; - sum2 += weight*weight; + CHECK(eq_eps(weight, 1.0, 1.e-6), 1); } - n += NSTEPS; - E = sum / (double)n; - V = MMAX(sum2 / (double)n - E*E, 0); - SE = sqrt(V/(double)n); - CHECK(eq_eps(E, 1.0, 3*SE), 1); } static INLINE void