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 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:
Msrc/ssf.h | 22+---------------------
Msrc/ssf_bsdf.c | 75++++++++++++++++-----------------------------------------------------------
Msrc/ssf_bxdf.c | 8--------
Msrc/ssf_bxdf_c.h | 1-
Msrc/ssf_lambertian_reflection.c | 9---------
Msrc/ssf_microfacet_reflection.c | 9---------
Msrc/ssf_specular_reflection.c | 13++-----------
Msrc/test_ssf_bsdf.c | 10++++------
Msrc/test_ssf_bxdf.c | 14--------------
Msrc/test_ssf_specular_reflection.c | 3---
Msrc/test_ssf_utils.h | 8--------
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 };