commit cfb45d5b8e83d37ffd27f14b1ab24ac6413e6d44
parent 408e9bc133b2de5581f1bc37a28414e84f69c8ed
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Sat, 10 Sep 2016 18:23:41 +0200
Update of the BxDF and BSDF API
Diffstat:
8 files changed, 144 insertions(+), 122 deletions(-)
diff --git a/src/ssf.h b/src/ssf.h
@@ -48,14 +48,28 @@ struct ssf_bxdf_type {
res_T (*init)(struct mem_allocator* allocator, void* bxdf);
void (*release)(void* bxdf);
- double /* Sampled reflectivity */
+ /* Sample an outgoing direction `wo' with respect to the ingoing direction
+ * `wi' and return the BxDF reflectivity along the sampled direction */
+ double
(*sample)
(void* bxdf,
const double u, /* Canonical random number */
const double v, /* Canonical random number */
- const double w[3], /* Normalized direction. Point inward the surface */
+ const double wi[3], /* Normalized incoming dir. Point inward the surface */
const double N[3], /* Normalized normal */
- double dir[4]); /* Sampled direction. The PDF is stored in dir[3] */
+ double wo[4]); /* Sampled direction. The PDF is stored in wo[3] */
+
+ double /* Reflectivity */
+ (*eval)
+ (void* bxdf,
+ const double wi[3], /* Normalized incoming dir. Point inward the surface */
+ const double wo[3]);/* Normalized outgoing dir. Point outward the surface */
+
+ double
+ (*pdf)
+ (void* bxdf,
+ const double wi[3], /* Normalized incoming dir. Point inward the surface */
+ const double wo[3]);/* Normalized outgoing dir. Point outward the surface */
size_t sizeof_bxdf; /* In Bytes */
size_t alignof_bxdf; /* In Bytes */
@@ -79,6 +93,8 @@ BEGIN_DECLS
/* Reflects the incoming direction with respect to the surface normal */
SSF_API const struct ssf_bxdf_type ssf_specular_reflection;
+/* Glossy reflections with respect to a microfacet distribution */
+SSF_API const struct ssf_bxdf_type ssf_microfacet_reflection;
/* Fresnel term for perfect reflection */
SSF_API const struct ssf_fresnel_type ssf_fresnel_no_op;
@@ -107,21 +123,21 @@ ssf_bsdf_ref_put
SSF_API res_T
ssf_bsdf_add
(struct ssf_bsdf* bsdf,
- struct ssf_bxdf* bxdf);
+ struct ssf_bxdf* bxdf,
+ const double weight);
SSF_API res_T
ssf_bsdf_clear
(struct ssf_bsdf* bsdf);
-SSF_API res_T
+SSF_API double
ssf_bsdf_sample
(struct ssf_bsdf* bsdf,
const double u, /* Canonical number */
const double v, /* Canonical number */
- const double w[3], /* Normalized incoming direction */
+ const double wi[3], /* Normalized incoming direction */
const double N[3], /* Normalized normal */
- double dir[4], /* Sampled direction. The PDF is stored in dir[3] */
- double* reflectivity); /* Sampled reflectivity */
+ double wo[4]); /* Sampled direction. The PDF is stored in dir[3] */
/*******************************************************************************
* Fresnel API - Define the equation of the fresnel term
@@ -170,7 +186,7 @@ ssf_fresnel_dielectric_conductor_setup
const double k_t); /* Imaginary part of the refraction id of the conductor */
/*******************************************************************************
- * BxDF API - Bidirecitonal <Reflectance|Transmittance> distribution function.
+ * BxDF API - Bidirectional <Reflectance|Transmittance> distribution function.
* Describes how the light is reflected|transmitted by a surface.
******************************************************************************/
SSF_API res_T
@@ -187,18 +203,29 @@ SSF_API res_T
ssf_bxdf_ref_put
(struct ssf_bxdf* bxdf);
-SSF_API res_T
+SSF_API double /* Reflectivity */
ssf_bxdf_sample
(struct ssf_bxdf* bxdf,
const double u, /* Canonical random number */
const double v, /* Canonical random number */
- const double w[3], /* Normalized direction. Point inward the surface */
+ const double wi[3], /* Normalized incoming dir. Point inward the surface */
const double N[3], /* Normalized normal */
- double dir[4], /* Sampled direction. The PDF is stored in dir[3] */
- double* reflectivity); /* Sampled reflectivity */
+ double wo[4]); /* Sampled direction. The PDF is stored in dir[3] */
+
+SSF_API double /* Reflectivity */
+ssf_bxdf_eval
+ (struct ssf_bxdf* bxdf,
+ const double wi[3], /* Normalized incoming dir. Point inward the surface */
+ const double wo[3]);/* Normalized outgoing dir. Point outward the surface */
+
+SSF_API double /* Probability */
+ssf_bxdf_pdf
+ (struct ssf_bxdf* bxdf,
+ const double wi[3], /* Normalized incoming dir. Point inward the surface */
+ const double wo[3]);/* Normalized outgoing dir. Point outward the surface */
/* Retrieve the internal data of the BxDF. Usefull for user defined BxDFs on
- * which the caller has to retrieve their data to setup the their parameters */
+ * which the caller has to retrieve their data to setup their parameters */
SSF_API res_T
ssf_bxdf_get_data
(struct ssf_bxdf* bxdf,
diff --git a/src/ssf_bsdf.c b/src/ssf_bsdf.c
@@ -25,6 +25,7 @@
struct ssf_bsdf {
struct ssf_bxdf* bxdfs[MAX_BxDFs];
+ double weights[MAX_BxDFs];
size_t nbxdfs;
ref_T ref;
@@ -95,12 +96,13 @@ ssf_bsdf_ref_put(struct ssf_bsdf* bsdf)
}
res_T
-ssf_bsdf_add(struct ssf_bsdf* bsdf, struct ssf_bxdf* bxdf)
+ssf_bsdf_add(struct ssf_bsdf* bsdf, struct ssf_bxdf* bxdf, const double weight)
{
- if(!bsdf || !bxdf) return RES_BAD_ARG;
+ if(!bsdf || !bxdf || weight < 0) return RES_BAD_ARG;
if(bsdf->nbxdfs >= MAX_BxDFs) return RES_MEM_ERR;
SSF(bxdf_ref_get(bxdf));
bsdf->bxdfs[bsdf->nbxdfs] = bxdf;
+ bsdf->weights[bsdf->nbxdfs] = weight;
++bsdf->nbxdfs;
return RES_OK;
}
@@ -119,16 +121,16 @@ ssf_bsdf_clear(struct ssf_bsdf* bsdf)
}
/* TODO fix the use of the u & v canonical random number. Currently u is used 2
- * times */
-res_T
+ * times
+ * TODO fix the sampling that is actually totally wrong */
+double
ssf_bsdf_sample
(struct ssf_bsdf* bsdf,
const double u,
const double v,
- const double w[3],
+ const double wi[3],
const double N[3],
- double dir[4],
- double* reflectivity)
+ double wo[4])
{
const size_t PDF = 3;
double reflectivities[MAX_BxDFs];
@@ -137,16 +139,9 @@ ssf_bsdf_sample
double cumul[MAX_BxDFs];
double probas_sum;
size_t i, n;
- res_T res = RES_OK;
- if(!bsdf || u<0 || u>=1 || v<0 || v>=1 || !w || !N || !dir || !reflectivity) {
- res = RES_BAD_ARG;
- goto error;
- }
- if(!d3_is_normalized(w) || !d3_is_normalized(N)) {
- res = RES_BAD_ARG;
- goto error;
- }
+ ASSERT(bsdf && u>=0 && u<1 && v>=0 && v<1 && wi && N && wo);
+ ASSERT(d3_is_normalized(wi) && d3_is_normalized(N));
/* Build the probability distribution by sampling each BRDF */
n = 0;
@@ -154,7 +149,7 @@ ssf_bsdf_sample
FOR_EACH(i, 0, bsdf->nbxdfs) {
struct ssf_bxdf* bxdf = bsdf->bxdfs[i];
- SSF(bxdf_sample(bxdf, u, v, w, N, dirs[n], reflectivities+n));
+ reflectivities[n] = ssf_bxdf_sample(bxdf, u, v, wi, N, dirs[n]);
if(reflectivities[n] <= 0 || dirs[n][PDF] <= 0)
continue; /* Discard BxDF */
@@ -164,9 +159,8 @@ ssf_bsdf_sample
}
if(!n) { /* No valid BxDF to sample */
- d4_splat(dir, 0);
- *reflectivity = 0;
- goto exit;
+ d4_splat(wo, 0.0);
+ return 0.0;
}
/* Normalize the probability distribution */
@@ -179,14 +173,7 @@ ssf_bsdf_sample
/* Finally sample the distribution */
FOR_EACH(i, 0, n-1) if(u <= cumul[i]) break;
- d4_set(dir, dirs[i]);
- *reflectivity = reflectivities[i];
-
-exit:
- return res;
-error:
- if(dir) d4_splat(dir, -DBL_MAX);
- if(reflectivity) *reflectivity = -DBL_MAX;
- goto exit;
+ d4_set(wo, dirs[i]);
+ return reflectivities[i];
}
diff --git a/src/ssf_bxdf.c b/src/ssf_bxdf.c
@@ -32,6 +32,8 @@ check_bxdf_type(const struct ssf_bxdf_type* type)
&& type->init
&& type->release
&& type->sample
+ && type->eval
+ && type->pdf
&& IS_POW2(type->alignof_bxdf);
}
@@ -111,22 +113,34 @@ ssf_bxdf_ref_put(struct ssf_bxdf* bxdf)
return RES_OK;
}
-res_T
+double
ssf_bxdf_sample
(struct ssf_bxdf* bxdf,
const double u,
const double v,
- const double w[3],
+ const double wi[3],
const double N[3],
- double dir[4],
- double* reflectivity)
+ double wo[4])
{
- if(!bxdf || u<0 || u>=1 || v<0 || v>=1 || !w || !N || !dir || !reflectivity)
- return RES_BAD_ARG;
- if(!d3_is_normalized(w) || !d3_is_normalized(N))
- return RES_BAD_ARG;
- *reflectivity = bxdf->type.sample(bxdf->data, u, v, w, N, dir);
- return RES_OK;
+ ASSERT(bxdf && u>=0 && u<1 && v>=0 && v<1 && wi && N && wo);
+ ASSERT(d3_is_normalized(wi) && d3_is_normalized(N));
+ return bxdf->type.sample(bxdf->data, u, v, wi, N, wo);
+}
+
+double
+ssf_bxdf_eval(struct ssf_bxdf* bxdf, const double wi[3], const double wo[3])
+{
+ ASSERT(bxdf && wi && wo);
+ ASSERT(d3_is_normalized(wi) && d3_is_normalized(wo));
+ return bxdf->type.eval(bxdf->data, wi, wo);
+}
+
+double
+ssf_bxdf_pdf(struct ssf_bxdf* bxdf, const double wi[3], const double wo[3])
+{
+ ASSERT(bxdf && wi && wo);
+ ASSERT(d3_is_normalized(wi) && d3_is_normalized(wo));
+ return bxdf->type.pdf(bxdf->data, wi, wo);
}
res_T
diff --git a/src/ssf_specular_reflection.c b/src/ssf_specular_reflection.c
@@ -43,23 +43,37 @@ specular_reflection_sample
(void* data,
const double u,
const double v,
- const double w[3],
+ const double wi[3],
const double N[3],
- double dir[4])
+ double wo[4])
{
struct specular_reflection* brdf = data;
double cosi;
- ASSERT(u >= 0 && u < 1 && v >= 0 && v < 1 && w && N && dir);
+ ASSERT(u >= 0 && u < 1 && v >= 0 && v < 1 && wi && N && wo);
(void)u, (void)v;
/* Reflection the incoming direction w[3] with respect to the normal */
- cosi = -d3_dot(w, N);
- d3_muld(dir, N, 2*cosi);
- d3_add(dir, dir, w);
- dir[3] = 1; /* pdf */
+ cosi = -d3_dot(wi, N);
+ d3_muld(wo, N, 2*cosi);
+ d3_add(wo, wo, wi);
+ wo[3] = 1.0; /* pdf */
return brdf->reflectivity;
}
+static double
+specular_reflection_eval(void* data, const double wi[3], const double wo[3])
+{
+ (void)data, (void)wi, (void)wo;
+ return 0.0;
+}
+
+static double
+specular_reflection_pdf(void* data, const double wi[3], const double wo[3])
+{
+ (void)data, (void)wi, (void)wo;
+ return 0.0;
+}
+
/*******************************************************************************
* Exported symbols
******************************************************************************/
@@ -67,6 +81,8 @@ const struct ssf_bxdf_type ssf_specular_reflection = {
specular_reflection_init,
specular_reflection_release,
specular_reflection_sample,
+ specular_reflection_eval,
+ specular_reflection_pdf,
sizeof(struct specular_reflection),
ALIGNOF(struct specular_reflection)
};
diff --git a/src/test_ssf_bsdf.c b/src/test_ssf_bsdf.c
@@ -27,7 +27,6 @@ main(int argc, char** argv)
double w[3];
double N[3];
double dir[4];
- double refl;
(void)argc, (void)argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
@@ -46,37 +45,23 @@ main(int argc, char** argv)
CHECK(ssf_bxdf_create(&allocator, &ssf_specular_reflection, &bxdf), RES_OK);
CHECK(ssf_specular_reflection_setup(bxdf, 2.0), RES_OK);
- CHECK(ssf_bsdf_add(NULL, NULL), RES_BAD_ARG);
- CHECK(ssf_bsdf_add(bsdf, NULL), RES_BAD_ARG);
- CHECK(ssf_bsdf_add(NULL, bxdf), RES_BAD_ARG);
- CHECK(ssf_bsdf_add(bsdf, bxdf), RES_OK);
+ CHECK(ssf_bsdf_add(NULL, NULL, -1.0), RES_BAD_ARG);
+ CHECK(ssf_bsdf_add(bsdf, NULL, -1.0), RES_BAD_ARG);
+ CHECK(ssf_bsdf_add(NULL, bxdf, -1.0), RES_BAD_ARG);
+ CHECK(ssf_bsdf_add(bsdf, bxdf, -1.0), RES_BAD_ARG);
+ CHECK(ssf_bsdf_add(NULL, NULL, 1.0), RES_BAD_ARG);
+ CHECK(ssf_bsdf_add(bsdf, NULL, 1.0), RES_BAD_ARG);
+ CHECK(ssf_bsdf_add(NULL, bxdf, 1.0), RES_BAD_ARG);
+ CHECK(ssf_bsdf_add(bsdf, bxdf, 1.0), RES_OK);
d3_normalize(w, d3(w, -1, -1, 0));
d3(N, 0.0, 1.0, 0.0);
- CHECK(ssf_bsdf_sample(NULL, 0, 0, w, N, dir, &refl), RES_BAD_ARG);
- CHECK(ssf_bsdf_sample(bsdf, 0, -1, w, N, dir, &refl), RES_BAD_ARG);
- CHECK(ssf_bsdf_sample(bsdf, 1, 0, w, N, dir, &refl), RES_BAD_ARG);
- CHECK(ssf_bsdf_sample(bsdf, 0, 0, NULL, N, dir, &refl), RES_BAD_ARG);
- CHECK(ssf_bsdf_sample(bsdf, 0, 0, w, NULL, dir, &refl), RES_BAD_ARG);
- CHECK(ssf_bsdf_sample(bsdf, 0, 0, w, N, NULL, &refl), RES_BAD_ARG);
- CHECK(ssf_bsdf_sample(bsdf, 0, 0, w, N, dir, NULL), RES_BAD_ARG);
- CHECK(ssf_bsdf_sample(bsdf, 0, 0, w, N, dir, &refl), RES_OK);
- CHECK(refl, 2.0);
- CHECK(ssf_bsdf_sample(bsdf, 0.5, 0.5, w, N, dir, &refl), RES_OK);
- CHECK(refl, 2.0);
+ CHECK(ssf_bsdf_sample(bsdf, 0, 0, w, N, dir), 2.0);
+ CHECK(ssf_bsdf_sample(bsdf, 0.5, 0.5, w, N, dir), 2.0);
CHECK(ssf_bsdf_clear(NULL), RES_BAD_ARG);
CHECK(ssf_bsdf_clear(bsdf), RES_OK);
- CHECK(ssf_bsdf_sample(bsdf, 0, 0, w, N, dir, &refl), RES_OK);
- CHECK(refl, 0.0);
-
- d3(w, -1, -1, 0);
- CHECK(ssf_bsdf_sample(bsdf, 0.5, 0.5, w, N, dir, &refl), RES_BAD_ARG);
- d3_normalize(w, w);
- d3(N, 0.0, 2.0, 1.0);
- CHECK(ssf_bsdf_sample(bsdf, 0.5, 0.5, w, N, dir, &refl), RES_BAD_ARG);
- d3_normalize(N, N);
- CHECK(ssf_bsdf_sample(bsdf, 0.5, 0.5, w, N, dir, &refl), RES_OK);
+ CHECK(ssf_bsdf_sample(bsdf, 0, 0, w, N, dir), 0.0);
CHECK(ssf_bsdf_ref_put(bsdf), RES_OK);
CHECK(ssf_bxdf_ref_put(bxdf), RES_OK);
diff --git a/src/test_ssf_bxdf.c b/src/test_ssf_bxdf.c
@@ -78,7 +78,6 @@ main(int argc, char** argv)
double w[3];
double N[3];
double dir[4];
- double rad;
(void)argc, (void)argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
@@ -147,31 +146,13 @@ main(int argc, char** argv)
data->v = 0.0;
data->reflectivity = 1.234;
- CHECK(ssf_bxdf_sample(NULL, 0, 0, w, N, dir, &rad), RES_BAD_ARG);
- CHECK(ssf_bxdf_sample(bxdf, 0, -1, w, N, dir, &rad), RES_BAD_ARG);
- CHECK(ssf_bxdf_sample(bxdf, 1, 0, w, N, dir, &rad), RES_BAD_ARG);
- CHECK(ssf_bxdf_sample(bxdf, 0, 0, NULL, N, dir, &rad), RES_BAD_ARG);
- CHECK(ssf_bxdf_sample(bxdf, 0, 0, w, NULL, dir, &rad), RES_BAD_ARG);
- CHECK(ssf_bxdf_sample(bxdf, 0, 0, w, N, NULL, &rad), RES_BAD_ARG);
- CHECK(ssf_bxdf_sample(bxdf, 0, 0, w, N, dir, NULL), RES_BAD_ARG);
- CHECK(ssf_bxdf_sample(bxdf, 0, 0, w, N, dir, &rad), RES_OK);
- CHECK(rad, 1.234);
+ CHECK(ssf_bxdf_sample(bxdf, 0, 0, w, N, dir), 1.234);
data->u = 0.5;
data->v = 0.5;
- CHECK(ssf_bxdf_sample(bxdf, 0.5, 0.5, w, N, dir, &rad), RES_OK);
- CHECK(rad, 1.234);
-
- d3(w, -1, -1, 0);
- CHECK(ssf_bxdf_sample(bxdf, 0.5, 0.5, w, N, dir, &rad), RES_BAD_ARG);
- d3_normalize(w, w);
- d3(N, 0.0, 2.0, 1.0);
- CHECK(ssf_bxdf_sample(bxdf, 0.5, 0.5, w, N, dir, &rad), RES_BAD_ARG);
- d3_normalize(N, N);
- d3_set(data->w, w);
- d3_set(data->N, N);
+ CHECK(ssf_bxdf_sample(bxdf, 0.5, 0.5, w, N, dir), 1.234);
+
data->reflectivity = 3.14;
- CHECK(ssf_bxdf_sample(bxdf, 0.5, 0.5, w, N, dir, &rad), RES_OK);
- CHECK(rad, 3.14);
+ CHECK(ssf_bxdf_sample(bxdf, 0.5, 0.5, w, N, dir), 3.14);
CHECK(bxdf_is_init, 1);
CHECK(ssf_bxdf_ref_put(bxdf), RES_OK);
diff --git a/src/test_ssf_specular_reflection.c b/src/test_ssf_specular_reflection.c
@@ -27,7 +27,6 @@ main(int argc, char** argv)
double w[3];
double N[3];
double dir[4];
- double refl;
(void)argc, (void)argv;
mem_init_proxy_allocator(&allocator, &mem_default_allocator);
@@ -44,33 +43,30 @@ main(int argc, char** argv)
d3(N, 0.0, 1.0, 0.0);
d3_normalize(w, d3(w, -1.0, -1.0, 0.0));
- CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir, &refl), RES_OK);
- CHECK(refl, 0.0);
+ CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir), 0.0);
d3_normalize(w, d3(w, -1.0, -1.0, 0.0));
CHECK(ssf_specular_reflection_setup(brdf, 1.23), RES_OK);
- CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir, &refl), RES_OK);
- CHECK(refl, 1.23);
+ CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir), 1.23);
CHECK(d3_eq_eps(d3(w, w[0], -w[1], 0.0), dir, 1.e-6), 1);
+ CHECK(ssf_bxdf_eval(brdf, w, dir), 0.0);
+ CHECK(ssf_bxdf_pdf(brdf, w, dir), 0.0);
+
d3(w, 0.0, -1.0, 0.0);
- CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir, &refl), RES_OK);
- CHECK(refl, 1.23);
+ CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir), 1.23);
CHECK(d3_eq_eps(d3(w, 0.0, 1.0, 0.0), dir, 1.e-6), 1);
d3_normalize(w, d3(w, -1.0, 1.0, 0.0));
- CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir, &refl), RES_OK);
- CHECK(refl, 1.23);
+ CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir), 1.23);
CHECK(d3_eq_eps(d3(w, w[0], -w[1], 0.0), dir, 1.e-6), 1);
d3(w, 0.0, 1.0, 0.0);
- CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir, &refl), RES_OK);
- CHECK(refl, 1.23);
+ CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir), 1.23);
CHECK(d3_eq_eps(d3(w, 0.0, -1.0, 0.0), dir, 1.e-6), 1);
d3(w, -1.0, 0.0, 0.0);
- CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir, &refl), RES_OK);
- CHECK(refl, 1.23);
+ CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir), 1.23);
CHECK(d3_eq_eps(w, dir, 1.e-6), 1);
CHECK(ssf_bxdf_ref_put(brdf), RES_OK);
diff --git a/src/test_ssf_utils.h b/src/test_ssf_utils.h
@@ -48,10 +48,26 @@ bxdf_dummy_sample
return 0.0;
}
+static double
+bxdf_dummy_eval(void* bxdf, const double wi[3], const double wo[3])
+{
+ (void)bxdf, (void)wi, (void)wo;
+ return 0.0;
+}
+
+static double
+bxdf_dummy_pdf(void* bxdf, const double wi[3], const double wo[3])
+{
+ (void)bxdf, (void)wi, (void)wo;
+ return 0.0;
+}
+
static const struct ssf_bxdf_type bxdf_dummy = {
bxdf_dummy_init,
bxdf_dummy_release,
bxdf_dummy_sample,
+ bxdf_dummy_eval,
+ bxdf_dummy_pdf,
0, 1
};