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 12122fa4af59f17cd039be2ce4e68d86bb3e0ea4
parent 74d2016369d88d761fb28270b05921c6d08109fa
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 30 Sep 2016 16:35:24 +0200

Add the Microfacet2 BRDF

Ensure the energy conservation property without requiring the
normalization of the BRDF.

Diffstat:
Msrc/ssf.h | 6++++++
Msrc/ssf_microfacet_reflection.c | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/test_ssf_microfacet_reflection.c | 8+-------
3 files changed, 92 insertions(+), 9 deletions(-)

diff --git a/src/ssf.h b/src/ssf.h @@ -163,6 +163,12 @@ SSF_API const struct ssf_bxdf_type ssf_specular_reflection; SSF_API const struct ssf_bxdf_type ssf_lambertian_reflection; /* Glossy reflections with respect to a microfacet distribution */ SSF_API const struct ssf_bxdf_type ssf_microfacet_reflection; +/* Glossy reflections with respect to a microfacet distribution. In contrast to + * the common microfacet model, this BRDF ensures, by construction, the energy + * conservation property without requiring the normalization of the BRDF. As a + * conterpart, it only provides the sample function. The others functions + * return invalid results */ +SSF_API const struct ssf_bxdf_type ssf_microfacet2_reflection; /* Fresnel term for perfect reflection */ SSF_API const struct ssf_fresnel_type ssf_fresnel_no_op; diff --git a/src/ssf_microfacet_reflection.c b/src/ssf_microfacet_reflection.c @@ -25,7 +25,7 @@ struct microfacet_reflection { }; /******************************************************************************* - * Private functions + * Microfacet functions ******************************************************************************/ static res_T microfacet_reflection_init(struct mem_allocator* allocator, void* data) @@ -94,7 +94,7 @@ microfacet_reflection_sample double R; ASSERT(data && u>=0 && u<1 && v>=0 && v<1 && wo && N && wi); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); - ASSERT(bxdf->distrib); + ASSERT(bxdf->distrib && bxdf->fresnel); if(d3_dot(wo, N) <= 0.0) return 0.0; @@ -130,6 +130,78 @@ microfacet_reflection_rho(void* data, const double wo[3], const double N[3]) } /******************************************************************************* + * Microfacet 2 functions + ******************************************************************************/ +static FINLINE double +microfacet2_reflection_sample + (void* data, + const double u, + const double v, + const double wo[3], + const double N[3], + double wi[3], + double* pdf) +{ + struct microfacet_reflection* bxdf = data; + double dir[3]; + double wh[3]; + double p; + double troughput = 1; + ASSERT(data && u>=0 && u<1 && v>=0 && v<1 && wo && N && wi); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); + 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, u, v, wo, N, wh, &p); + } while(d3_dot(wo, wh) <= 0); + + reflect(dir, wo, wh); + for(;;) { + troughput *= ssf_fresnel_eval(bxdf->fresnel, d3_dot(wh, dir)); + + /* Do not take care of inter-reflections for sampled directions that point + * outward the macro surface, i.e. simply stop the "random walk". */ + if(d3_dot(dir, N) > 0) break; + + /* Handle directions that point toward the macro surface has + * inter-reflections */ + do { /* Sample a microfacet that front faces 'wi' */ + ssf_microfacet_distribution_sample(bxdf->distrib, u, v, dir, N, wh, &p); + } while(d3_dot(dir, wh) <= 0); + reflect(dir, dir, wh); + } + + *pdf = NaN; + d3_set(wi, dir); + return troughput; +} + +static FINLINE double +microfacet2_reflection_eval + (void* data, const double wo[3], const double N[3], const double wi[3]) +{ + (void)data, (void)wo, (void)N, (void)wi; + return NaN; +} + +static FINLINE double +microfacet2_reflection_pdf + (void* data, const double wo[3], const double N[3], const double wi[3]) +{ + (void)data, (void)wo, (void)N, (void)wi; + return NaN; +} + +static FINLINE double +microfacet2_reflection_rho(void* data, const double wo[3], const double N[3]) +{ + (void)data, (void)wo, (void)N; + return NaN; +} + +/******************************************************************************* * Exported symbols ******************************************************************************/ const struct ssf_bxdf_type ssf_microfacet_reflection = { @@ -143,6 +215,17 @@ const struct ssf_bxdf_type ssf_microfacet_reflection = { ALIGNOF(struct microfacet_reflection) }; +const struct ssf_bxdf_type ssf_microfacet2_reflection = { + microfacet_reflection_init, + microfacet_reflection_release, + microfacet2_reflection_sample, + microfacet2_reflection_eval, + microfacet2_reflection_pdf, + microfacet2_reflection_rho, + sizeof(struct microfacet_reflection), + ALIGNOF(struct microfacet_reflection) +}; + res_T ssf_microfacet_reflection_setup (struct ssf_bxdf* bxdf, diff --git a/src/test_ssf_microfacet_reflection.c b/src/test_ssf_microfacet_reflection.c @@ -21,18 +21,11 @@ int main(int argc, char** argv) { - const size_t NSTEPS = 100000; struct mem_allocator allocator; struct ssf_bxdf* bxdf; struct ssf_bxdf* dummy; struct ssf_fresnel* F; struct ssf_microfacet_distribution* D; - double wo[3], wi[3]; - double N[3]; - double pdf; - double sum, sum_sqr; - double E, V, SE; - size_t i; (void)argc, (void)argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -54,6 +47,7 @@ main(int argc, char** argv) CHECK(ssf_microfacet_reflection_setup(bxdf, F, D), RES_OK); /* Numerically evaluate rho */ + /* TODO */ #if 0 d3(N, 0, 1, 0); sum = sum_sqr = 0;