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 9a86fd81ba0a61fbb65e0bf0e757913fc7bc1b85
parent 5b1c996b2ff3ed94cf48041b0f6f34d7020b3057
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 14 Sep 2016 16:15:59 +0200

Rewrite the ssf_bsdf_sample function

Diffstat:
Msrc/ssf_bsdf.c | 101+++++++++++++++++++++++++++++++++++++++++--------------------------------------
1 file changed, 52 insertions(+), 49 deletions(-)

diff --git a/src/ssf_bsdf.c b/src/ssf_bsdf.c @@ -21,12 +21,12 @@ #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> -#define MAX_BxDFs 8 +#define MAX_COMPONENTS 8 struct ssf_bsdf { - struct ssf_bxdf* bxdfs[MAX_BxDFs]; - double weights[MAX_BxDFs]; - size_t nbxdfs; + struct ssf_bxdf* components[MAX_COMPONENTS]; + double weights[MAX_COMPONENTS]; + size_t ncomponents; ref_T ref; struct mem_allocator* allocator; @@ -99,11 +99,12 @@ res_T ssf_bsdf_add(struct ssf_bsdf* bsdf, struct ssf_bxdf* bxdf, const double weight) { if(!bsdf || !bxdf || weight < 0) return RES_BAD_ARG; - if(bsdf->nbxdfs >= MAX_BxDFs) return RES_MEM_ERR; + if(bsdf->ncomponents >= MAX_COMPONENTS) return RES_MEM_ERR; + if(weight == 0) return RES_OK; SSF(bxdf_ref_get(bxdf)); - bsdf->bxdfs[bsdf->nbxdfs] = bxdf; - bsdf->weights[bsdf->nbxdfs] = weight; - ++bsdf->nbxdfs; + bsdf->components[bsdf->ncomponents] = bxdf; + bsdf->weights[bsdf->ncomponents] = weight; + ++bsdf->ncomponents; return RES_OK; } @@ -113,16 +114,13 @@ ssf_bsdf_clear(struct ssf_bsdf* bsdf) { size_t i; if(!bsdf) return RES_BAD_ARG; - FOR_EACH(i, 0, bsdf->nbxdfs) { - SSF(bxdf_ref_put(bsdf->bxdfs[i])); + FOR_EACH(i, 0, bsdf->ncomponents) { + SSF(bxdf_ref_put(bsdf->components[i])); } - bsdf->nbxdfs = 0; + bsdf->ncomponents = 0; return RES_OK; } -/* TODO fix the use of the u & v canonical random number. Currently u is used 2 - * times - * TODO fix the sampling that is actually totally wrong */ double ssf_bsdf_sample (struct ssf_bsdf* bsdf, @@ -132,48 +130,53 @@ ssf_bsdf_sample const double N[3], double wo[4]) { - const size_t PDF = 3; - double reflectivities[MAX_BxDFs]; - double dirs[MAX_BxDFs][4]; - double probas[MAX_BxDFs]; - double cumul[MAX_BxDFs]; + double probas[MAX_COMPONENTS]; + double cumul[MAX_COMPONENTS]; double probas_sum; - size_t i, n; - - 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; - probas_sum = 0.0f; - FOR_EACH(i, 0, bsdf->nbxdfs) { - struct ssf_bxdf* bxdf = bsdf->bxdfs[i]; - - reflectivities[n] = ssf_bxdf_sample(bxdf, u, v, wi, N, dirs[n]); - if(reflectivities[n] <= 0 || dirs[n][PDF] <= 0) - continue; /* Discard BxDF */ + double reflectivity; + double w; + double pdf; + size_t i, icomponent; + + if(!bsdf->ncomponents) return 0; + if(bsdf->ncomponents == 1) { + return ssf_bxdf_sample(bsdf->components[0], u, v, wi, N, wo); + } - probas[n] = reflectivities[n] / dirs[n][PDF]; - probas_sum += probas[n]; - ++n; + /* Compute the normalization factor of the BxDF weights */ + probas_sum = 0; + FOR_EACH(icomponent, 0, bsdf->ncomponents) { + probas_sum += bsdf->weights[icomponent]; } - if(!n) { /* No valid BxDF to sample */ - d4_splat(wo, 0.0); - return 0.0; + /* Compute the components probabilities and the cumulative */ + cumul[0] = probas[0] = bsdf->weights[0] / probas_sum; + FOR_EACH(icomponent, 0, bsdf->ncomponents) { + probas[icomponent] = bsdf->weights[icomponent] / probas_sum; + cumul[icomponent] = cumul[icomponent-1] + probas[icomponent]; } + /* Sample a component */ + FOR_EACH(icomponent, 0, bsdf->ncomponents-1) { + if(u >= cumul[icomponent]) break; + } + + /* Rescale the random number to reuse it (NOTE why?) */ + w = (u - cumul[icomponent] ) / (cumul[icomponent+1] - cumul[icomponent]); - /* Normalize the probability distribution */ - FOR_EACH(i, 0, n) probas[i] /= probas_sum; + /* Sample the component */ + reflectivity = ssf_bxdf_sample(bsdf->components[icomponent], w, v, wi, N, wo); + if(reflectivity == 0) return 0; - /* Compute the cumulative */ - cumul[0] = probas[0]; - cumul[n-1] = 1.f; - FOR_EACH(i, 1, n-1) cumul[i] = cumul[i-1] + probas[i]; + pdf = wo[3] * probas[icomponent]; + reflectivity *= pdf; - /* Finally sample the distribution */ - FOR_EACH(i, 0, n-1) if(u <= cumul[i]) break; - d4_set(wo, dirs[i]); - return reflectivities[i]; + /* Add the contribution of the others components */ + FOR_EACH(i, 0, bsdf->ncomponents) { + if(i == icomponent) continue; + pdf += ssf_bxdf_pdf(bsdf->components[i], wi, wo) * probas[i]; + reflectivity += ssf_bxdf_eval(bsdf->components[i], wi, wo) * probas[i]; + } + wo[3] = pdf; + return reflectivity / pdf; }