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