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 be1dcfd4054ae0060e8e10268ae274a90dc65f77
parent 03d119e65f2a5e4eed65374bffe1066b45abba19
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  7 Sep 2016 11:47:32 +0200

Implement the ssf_bsdf API

Diffstat:
Mcmake/CMakeLists.txt | 1+
Msrc/ssf.h | 3++-
Asrc/ssf_bsdf.c | 185+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 188 insertions(+), 1 deletion(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -47,6 +47,7 @@ set(SSF_FILES_DOC COPYING README.md) set(SSF_FILES_INC_API ssf.h) set(SSF_FILES_INC ssf_bxdf_c.h) set(SSF_FILES_SRC + ssf_bsdf.c ssf_bxdf.c ssf_specular_reflection.c) rcmake_prepend_path(SSF_FILES_SRC ${SSF_SOURCE_DIR}) diff --git a/src/ssf.h b/src/ssf.h @@ -77,7 +77,8 @@ ssf_bsdf_sample const double v, /* Canonical number */ const double w[3], /* Incoming direction */ const double N[3], /* Normalized normal */ - double dir[4]); /* Sampled direction. The PDF is stored in dir[3] */ + double dir[4], /* Sampled direction. The PDF is stored in dir[3] */ + double* radiance); /* Sampled radiance */ /******************************************************************************* * BxDF API - Bidirecitonal <Reflectance|Transmittance> distribution function. diff --git a/src/ssf_bsdf.c b/src/ssf_bsdf.c @@ -0,0 +1,185 @@ +/* Copyright (C) |Meso|Star> 2016 (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 + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "ssf.h" +#include "ssf_bxdf_c.h" + +#include <rsys/double4.h> +#include <rsys/mem_allocator.h> +#include <rsys/ref_count.h> + +#define MAX_BxDFs 8 + +struct ssf_bsdf { + struct ssf_bxdf* bxdfs[MAX_BxDFs]; + size_t nbxdfs; + + ref_T ref; + struct mem_allocator* allocator; +}; + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static void +bsdf_release(ref_T* ref) +{ + struct ssf_bsdf* bsdf = CONTAINER_OF(ref, struct ssf_bsdf, ref); + ASSERT(ref); + SSF(bsdf_clear(bsdf)); + MEM_RM(bsdf->allocator, bsdf); +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +ssf_bsdf_create(struct mem_allocator* allocator, struct ssf_bsdf** out_bsdf) +{ + struct mem_allocator* mem_allocator = NULL; + struct ssf_bsdf* bsdf = NULL; + res_T res = RES_OK; + + if(!out_bsdf) { + res = RES_BAD_ARG; + goto error; + } + + mem_allocator = allocator ? allocator : &mem_default_allocator; + bsdf = MEM_CALLOC(mem_allocator, 1, sizeof(struct ssf_bsdf)); + if(!bsdf) { + res = RES_MEM_ERR; + goto error; + } + bsdf->allocator = mem_allocator; + ref_init(&bsdf->ref); + +exit: + if(out_bsdf) *out_bsdf = bsdf; + return res; +error: + if(bsdf) { + SSF(bsdf_ref_put(bsdf)); + bsdf = NULL; + } + goto exit; +} + +res_T +ssf_bsdf_ref_get(struct ssf_bsdf* bsdf) +{ + if(!bsdf) return RES_BAD_ARG; + ref_get(&bsdf->ref); + return RES_OK; +} + +res_T +ssf_bsdf_ref_put(struct ssf_bsdf* bsdf) +{ + if(!bsdf) return RES_BAD_ARG; + ref_put(&bsdf->ref, bsdf_release); + return RES_OK; +} + +res_T +ssf_bsdf_add(struct ssf_bsdf* bsdf, struct ssf_bxdf* bxdf) +{ + if(!bsdf || !bxdf) return RES_BAD_ARG; + if(bsdf->nbxdfs >= MAX_BxDFs) return RES_MEM_ERR; + SSF(bxdf_ref_get(bxdf)); + bsdf->bxdfs[bsdf->nbxdfs] = bxdf; + ++bsdf->nbxdfs; + return RES_OK; +} + + +res_T +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])); + } + bsdf->nbxdfs = 0; + return RES_OK; +} + +res_T +ssf_bsdf_sample + (struct ssf_bsdf* bsdf, + const double u, + const double v, + const double w[3], + const double N[3], + double dir[4], + double* radiance) +{ + const size_t PDF = 3; + double radiances[MAX_BxDFs]; + double dirs[MAX_BxDFs][4]; + double probas[MAX_BxDFs]; + 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 || !radiance) { + res = RES_BAD_ARG; + goto error; + } + + /* 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]; + + radiances[n] = bxdf->sample(bxdf->data, u, v, w, N, dirs[n]); + if(radiances[n] <= 0 || dirs[n][PDF] <= 0) + continue; /* Discard BxDF */ + + probas[n] = radiances[n] / dirs[n][PDF]; + probas_sum += probas[n]; + ++n; + } + + if(!n) { /* No valid BxDF to sample */ + d4_splat(dir, 0); + *radiance = 0; + goto exit; + } + + /* Normalize the probability distribution */ + FOR_EACH(i, 0, n) probas[i] /= probas_sum; + + /* 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]; + + /* Finally sample the distribution */ + FOR_EACH(i, 0, n-1) if(u <= cumul[i]) break; + d4_set(dir, dirs[i]); + *radiance = radiances[i]; + +exit: + return res; +error: + d4_splat(dir, -DBL_MAX); + *radiance = -DBL_MAX; + goto exit; +} +