commit 4b0ba2ff258f5fcb7777963f5dcbd06072b7ccd0
parent 2eac75faa1ed84128e57b0a52d464bd3c8047a52
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Mon, 3 Oct 2016 10:49:12 +0200
Remove the Rho functions and rewrite the BSDF sampling procedure
Diffstat:
11 files changed, 23 insertions(+), 149 deletions(-)
diff --git a/src/ssf.h b/src/ssf.h
@@ -85,18 +85,10 @@ struct ssf_bxdf_type {
const double N[3], /* Normalized surface normal */
const double wi[3]);/* Normalized incoming direction */
- /* rho(wo) = \int_{2\pi} BxDF(wo,wi) |wi.N| dwi
- * rho(wo) P(wi,wo) = BxDF(wo,wi) |wi.N|; with \int_{2\pi} P(wo,wi) dwi = 1 */
- double
- (*rho)
- (void* bxdf,
- const double wo[3], /* Normalized outgoing direction */
- const double N[3]); /* Normalized surface normal */
-
size_t sizeof_bxdf; /* In Bytes */
size_t alignof_bxdf; /* In Bytes */
};
-#define SSF_BXDF_TYPE_NULL__ {NULL, NULL, NULL, NULL, NULL, NULL, 0, 1}
+#define SSF_BXDF_TYPE_NULL__ {NULL, NULL, NULL, NULL, NULL, 0, 1}
static const struct ssf_bxdf_type SSF_BXDF_TYPE_NULL = SSF_BXDF_TYPE_NULL__;
/* Generic Fresnel term descriptor */
@@ -237,12 +229,6 @@ ssf_bsdf_pdf
const double N[3], /* Normalized surface normal */
const double wi[3]); /* Normalized outgoing direction */
-SSF_API double /* \int_{2\pi} BSDF(wi, wo) |wi.N| dwi */
-ssf_bsdf_rho
- (struct ssf_bsdf* bsdf,
- const double wo[3],
- const double N[3]);
-
/*******************************************************************************
* BxDF API - Bidirectional <Reflectance|Transmittance> distribution function.
* Describes how the light is reflected|transmitted by a surface. Note that by
@@ -291,12 +277,6 @@ ssf_bxdf_pdf
const double N[3], /* Normalized surface normal */
const double wi[3]);/* Normalized incoming dir. Point outward the surface */
-SSF_API double /* \int_{2\pi} BxDF(wi, wo) |wi.N| dwi */
-ssf_bxdf_rho
- (struct ssf_bxdf* bxdf,
- const double wo[3],
- const double N[3]);
-
/* Retrieve the internal data of the BxDF. Usefull for user defined BxDFs on
* which the caller has to retrieve their data to setup their parameters */
SSF_API res_T
diff --git a/src/ssf_bsdf.c b/src/ssf_bsdf.c
@@ -149,13 +149,12 @@ ssf_bsdf_sample
double wi[3],
double* out_pdf)
{
- double probas[MAX_BxDFs];
double cumul[MAX_BxDFs];
- double reflectivity;
- double pdf;
- double rho;
+ double R_wi;
double r;
- size_t i, j;
+ double pdf;
+ double lower;
+ size_t i;
ASSERT(bsdf && u>=0 && u<1 && v>=0 && v<1 && wi && N && wo && out_pdf);
ASSERT(d3_is_normalized(wo) && d3_is_normalized(N));
@@ -166,51 +165,29 @@ ssf_bsdf_sample
if(bsdf->nbxdfs == 1) {
return ssf_bxdf_sample(bsdf->bxdfs[0], u, v, wo, N, wi, out_pdf);
}
+
bsdf_normalize_weights(bsdf);
- /* Compute the probabilities to sample each component as well as the
- * cumulative. For the i^th, component the proba is `Wi * rho_i(wo)/rho(wo)'
- * with Wi the component weight, rho_i(wo) its associated rho wrt to wo, and
- * rho the overall rho of the BSDF */
- rho = 0;
- FOR_EACH(i, 0, bsdf->nbxdfs) {
- probas[i] = bsdf->weights[i] * ssf_bxdf_rho(bsdf->bxdfs[i], wo, N);
- rho += probas[i];
- }
- cumul[0] = (probas[0] /= rho);
+ /* Compute the cumulative from the normalized weights of the BxDFs */
+ cumul[0] = bsdf->weights[0];
FOR_EACH(i, 1, bsdf->nbxdfs) {
- probas[i] /= rho;
- cumul[i] = probas[i] + cumul[i-1];
+ cumul[i] = bsdf->weights[i] + cumul[i-1];
}
/* Sample a component */
+ lower = 0;
FOR_EACH(i, 0, bsdf->nbxdfs-1) {
- if(u >= cumul[i]) break;
+ if(u <= cumul[i]) break;
+ lower = cumul[i];
}
/* Rescale the random number u in [0, 1) */
- r = (u - cumul[i]) / nextafter(cumul[i+1] - cumul[i], DBL_MAX);
+ r = (u - lower) / nextafter(cumul[i] - lower, DBL_MAX);
/* Sample a direction from the selected component */
- reflectivity = ssf_bxdf_sample(bsdf->bxdfs[i], r, v, wo, N, wi, &pdf);
-
- /* Compute the overall probabilities to sample this direction and the overall
- * reflectivity along this direction */
- pdf *= probas[i];
- reflectivity *= bsdf->weights[i];
- FOR_EACH(j, 0, bsdf->nbxdfs) {
- if(i == j) continue;
- pdf += probas[j] * ssf_bxdf_pdf(bsdf->bxdfs[j], wo, N, wi);
- reflectivity += bsdf->weights[j] * ssf_bxdf_eval(bsdf->bxdfs[j], wo, N, wi);
- }
- *out_pdf = pdf;
-#ifndef NDEBUG
- {
- const double R = rho * pdf / fabs(d3_dot(wi, N));
- ASSERT(eq_eps(R, reflectivity, 1.e-6));
- }
-#endif
- return reflectivity;
+ R_wi = ssf_bxdf_sample(bsdf->bxdfs[i], r, v, wo, N, wi, &pdf);
+ *out_pdf = pdf*bsdf->weights[i];
+ return R_wi;
}
double
@@ -221,16 +198,12 @@ ssf_bsdf_pdf
const double wi[3])
{
double pdf = 0;
- double rho = 0;
size_t i;
ASSERT(bsdf);
bsdf_normalize_weights(bsdf);
FOR_EACH(i, 0, bsdf->nbxdfs) {
- const double tmp = bsdf->weights[i] * ssf_bxdf_rho(bsdf->bxdfs[i], wo, N);
- pdf += ssf_bxdf_pdf(bsdf->bxdfs[i], wo, N, wi) * tmp;
- rho += tmp;
+ pdf += ssf_bxdf_pdf(bsdf->bxdfs[i], wo, N, wi) * bsdf->weights[i];
}
- pdf /= rho;
return pdf;
}
@@ -251,19 +224,3 @@ ssf_bsdf_eval
return R;
}
-double
-ssf_bsdf_rho
- (struct ssf_bsdf* bsdf,
- const double wo[3],
- const double N[3])
-{
- double rho = 0;
- size_t i;
- ASSERT(bsdf);
- bsdf_normalize_weights(bsdf);
- FOR_EACH(i, 0, bsdf->nbxdfs) {
- rho += bsdf->weights[i] * ssf_bxdf_rho(bsdf->bxdfs[i], wo, N);
- }
- return rho;
-}
-
diff --git a/src/ssf_bxdf.c b/src/ssf_bxdf.c
@@ -34,7 +34,6 @@ check_bxdf_type(const struct ssf_bxdf_type* type)
&& type->sample
&& type->eval
&& type->pdf
- && type->rho
&& IS_POW2(type->alignof_bxdf);
}
@@ -153,13 +152,6 @@ ssf_bxdf_pdf
return bxdf->type.pdf(bxdf->data, wo, N, wi);
}
-double
-ssf_bxdf_rho(struct ssf_bxdf* bxdf, const double wo[3], const double N[3])
-{
- ASSERT(bxdf && wo && d3_is_normalized(wo) && d3_is_normalized(N));
- return bxdf->type.rho(bxdf->data, wo, N);
-}
-
res_T
ssf_bxdf_get_data(struct ssf_bxdf* bxdf, void** data)
{
diff --git a/src/ssf_bxdf_c.h b/src/ssf_bxdf_c.h
@@ -36,7 +36,6 @@ struct ssf_bxdf {
&& (A)->sample == (B)->sample \
&& (A)->eval == (B)->eval \
&& (A)->pdf == (B)->pdf \
- && (A)->rho == (B)->rho \
&& (A)->sizeof_bxdf == (B)->sizeof_bxdf \
&& (A)->alignof_bxdf == (B)->alignof_bxdf)
diff --git a/src/ssf_lambertian_reflection.c b/src/ssf_lambertian_reflection.c
@@ -93,14 +93,6 @@ lambertian_reflection_pdf
return cos_wi_N <= 0.0 ? 0.0 : cos_wi_N / PI;
}
-static double
-lambertian_reflection_rho(void* data, const double wo[3], const double N[3])
-{
- ASSERT(data && wo && N);
- (void)wo, (void)N;
- return ((struct lambertian_reflection*)data)->reflectivity;
-}
-
/*******************************************************************************
* Exorted symbols
******************************************************************************/
@@ -110,7 +102,6 @@ const struct ssf_bxdf_type ssf_lambertian_reflection = {
lambertian_reflection_sample,
lambertian_reflection_eval,
lambertian_reflection_pdf,
- lambertian_reflection_rho,
sizeof(struct lambertian_reflection),
ALIGNOF(struct lambertian_reflection)
};
diff --git a/src/ssf_microfacet_reflection.c b/src/ssf_microfacet_reflection.c
@@ -194,13 +194,6 @@ microfacet2_reflection_pdf
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
******************************************************************************/
@@ -210,7 +203,6 @@ const struct ssf_bxdf_type ssf_microfacet_reflection = {
microfacet_reflection_sample,
microfacet_reflection_eval,
microfacet_reflection_pdf,
- microfacet_reflection_rho,
sizeof(struct microfacet_reflection),
ALIGNOF(struct microfacet_reflection)
};
@@ -221,7 +213,6 @@ const struct ssf_bxdf_type ssf_microfacet2_reflection = {
microfacet2_reflection_sample,
microfacet2_reflection_eval,
microfacet2_reflection_pdf,
- microfacet2_reflection_rho,
sizeof(struct microfacet_reflection),
ALIGNOF(struct microfacet_reflection)
};
diff --git a/src/ssf_specular_reflection.c b/src/ssf_specular_reflection.c
@@ -1,4 +1,4 @@
-/* Copyright (C) |Meso|Star> 2016 (contact@meso-star.com)
+/* Copyright (C) |Meso|Star> 2017 (contact@meso-star.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@ static res_T
specular_reflection_init(struct mem_allocator* allocator, void* bxdf)
{
ASSERT(bxdf);
- (void)allocator;
+ (void)allocator, (void)bxdf;
return RES_OK;
}
@@ -84,14 +84,6 @@ specular_reflection_pdf
return 0.0;
}
-static double
-specular_reflection_rho(void* data, const double wo[3], const double N[3])
-{
- struct specular_reflection* brdf = data;
- ASSERT(data && wo && N && d3_is_normalized(wo) && d3_is_normalized(N));
- return ssf_fresnel_eval(brdf->fresnel, d3_dot(wo, N));
-}
-
/*******************************************************************************
* Exported symbols
******************************************************************************/
@@ -101,7 +93,6 @@ const struct ssf_bxdf_type ssf_specular_reflection = {
specular_reflection_sample,
specular_reflection_eval,
specular_reflection_pdf,
- specular_reflection_rho,
sizeof(struct specular_reflection),
ALIGNOF(struct specular_reflection)
};
diff --git a/src/test_ssf_bsdf.c b/src/test_ssf_bsdf.c
@@ -28,7 +28,6 @@ main(int argc, char** argv)
struct ssf_bxdf* bxdf2;
struct ssf_fresnel* fresnel;
double wo[3], wi[3], pdf;
- double rho;
double N[3];
double E, V, SE, R;
double sum, sqr_sum;
@@ -76,15 +75,15 @@ main(int argc, char** argv)
CHECK(ssf_bsdf_add(bsdf, bxdf2, 1), RES_OK);
- /* Estimate the BSDF rho */
+ /* Estimate the BSDF rho. FIXME the following computation is certainly
+ * totally wrong */
sum = 0;
sqr_sum = 0;
- d3(wo, 0, 1, 0);
+ ran_hemisphere(N, wo, NULL);
FOR_EACH(i, 0, NSTEPS) {
const double u = rand_canonic();
const double v = rand_canonic();
double weight = ssf_bsdf_sample(bsdf, u, v, wo, N, wi, &pdf);
- weight *= d3_dot(N, wi) / pdf;
CHECK(ssf_bsdf_eval(bsdf, wo, N, wi), 0);
CHECK(ssf_bsdf_pdf(bsdf, wo, N, wi), 0);
sum += weight;
@@ -93,8 +92,7 @@ main(int argc, char** argv)
E = sum / (double)NSTEPS;
V = sqr_sum / (double)NSTEPS - E*E;
SE = sqrt(V / (double)NSTEPS);
- rho = ssf_bsdf_rho(bsdf, wo, N);
- CHECK(eq_eps(rho, E, SE), 1);
+ CHECK(eq_eps(1, E, SE), 1);
CHECK(ssf_bsdf_clear(NULL), RES_BAD_ARG);
CHECK(ssf_bsdf_clear(bsdf), RES_OK);
diff --git a/src/test_ssf_bxdf.c b/src/test_ssf_bxdf.c
@@ -107,16 +107,6 @@ bxdf_pdf
return BxDF->pdf;
}
-static double
-bxdf_rho(void* bxdf, const double wo[3], const double N[3])
-{
- struct bxdf* BxDF = bxdf;
- NCHECK(BxDF, NULL);
- CHECK(d3_eq(BxDF->wo, wo), 1);
- CHECK(d3_eq(BxDF->N, N), 1);
- return BxDF->rho;
-}
-
int
main(int argc, char** argv)
{
@@ -136,7 +126,6 @@ main(int argc, char** argv)
type.release = bxdf_release;
type.sample = bxdf_sample;
type.eval = bxdf_eval;
- type.rho = bxdf_rho;
type.pdf = bxdf_pdf;
type.sizeof_bxdf = sizeof(struct bxdf);
type.alignof_bxdf = ALIGNOF(struct bxdf);
@@ -214,9 +203,6 @@ main(int argc, char** argv)
data->pdf = 0.890;
CHECK(ssf_bxdf_pdf(bxdf, wo, N, wi), data->pdf);
- data->rho = 0.314;
- CHECK(ssf_bxdf_rho(bxdf, wo, N), data->rho);
-
CHECK(bxdf_is_init, 1);
CHECK(ssf_bxdf_ref_put(bxdf), RES_OK);
CHECK(bxdf_is_init, 0);
diff --git a/src/test_ssf_specular_reflection.c b/src/test_ssf_specular_reflection.c
@@ -29,7 +29,6 @@ main(int argc, char** argv)
double wo[3], wi[3];
double N[3];
double pdf;
- double rho;
double R;
size_t i;
(void)argc, (void)argv;
@@ -89,14 +88,12 @@ main(int argc, char** argv)
d3(wo, rand_canonic(), rand_canonic(), rand_canonic());
d3_normalize(wo, wo);
R = ssf_bxdf_sample(brdf, rand_canonic(), rand_canonic(), wo, N, wi, &pdf);
- rho = R;
FOR_EACH(i, 0, NSTEPS) {
const double u = rand_canonic();
const double v = rand_canonic();
CHECK(eq_eps(ssf_bxdf_sample(brdf, u, v, wo, N, wi, &pdf), R, 1.e-6), 1);
}
- CHECK(eq_eps(rho, ssf_bxdf_rho(brdf, wo, N), 1.e-6), 1);
CHECK(ssf_bxdf_ref_put(brdf), RES_OK);
CHECK(ssf_bxdf_ref_put(dummy), RES_OK);
diff --git a/src/test_ssf_utils.h b/src/test_ssf_utils.h
@@ -73,20 +73,12 @@ bxdf_dummy_pdf
return 0.0;
}
-static double
-bxdf_dummy_rho(void* bxdf, const double wo[3], const double N[3])
-{
- (void)bxdf, (void)wo, (void)N;
- 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,
- bxdf_dummy_rho,
0, 1
};