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 e5495a3b45c2da69df4101938b7b1b390fc84a6c
parent fb82549566225f9cb229afaea2fbf577b808e9de
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 21 Sep 2016 18:07:51 +0200

Implement the ssf_microfacet_reflection BRDF

Diffstat:
Mcmake/CMakeLists.txt | 4+++-
Msrc/ssf.h | 9++++++++-
Asrc/ssf_microfacet_reflection.c | 161+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ssf_optics.h | 36++++++++++++++++++++++++++++++++++++
Msrc/ssf_specular_reflection.c | 11+++++------
5 files changed, 213 insertions(+), 8 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -50,7 +50,8 @@ set(SSF_FILES_INC ssf_bsdf_view_c.h ssf_bxdf_c.h ssf_fresnel_c.h - ssf_microfacet_distribution_c.h) + ssf_microfacet_distribution_c.h + ssf_optics.h) set(SSF_FILES_SRC ssf_beckmann_distribution.c ssf_bsdf.c @@ -62,6 +63,7 @@ set(SSF_FILES_SRC ssf_fresnel_no_op.c ssf_lambertian_reflection.c ssf_microfacet_distribution.c + ssf_microfacet_reflection.c ssf_specular_reflection.c) rcmake_prepend_path(SSF_FILES_SRC ${SSF_SOURCE_DIR}) rcmake_prepend_path(SSF_FILES_INC ${SSF_SOURCE_DIR}) diff --git a/src/ssf.h b/src/ssf.h @@ -277,6 +277,13 @@ ssf_lambertian_reflection_setup (struct ssf_bxdf* bxdf, const double reflectivity); +res_T +ssf_microfacet_reflection_setup + (struct ssf_bxdf* data, + const double reflectivity, + struct ssf_fresnel* fresnel, + struct ssf_microfacet_distribution* distrib); + /******************************************************************************* * Fresnel API - Define the equation of the fresnel term ******************************************************************************/ @@ -297,7 +304,7 @@ ssf_fresnel_ref_put SSF_API double ssf_fresnel_eval (struct ssf_fresnel* fresnel, - const double cos_theta); /* Cos between facet normal and outgoing dir */ + const double cos_theta); /* Cos between facet normal and incoming dir */ /* Retrieve the internal data of the Fresnel term. Usefull for user defined * Fresnel terms on which the caller has to retrieve their data to setup the diff --git a/src/ssf_microfacet_reflection.c b/src/ssf_microfacet_reflection.c @@ -0,0 +1,161 @@ +/* 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 "ssf_optics.h" + +#include <rsys/double3.h> + +struct microfacet_reflection { + double reflectivity; + struct ssf_fresnel* fresnel; + struct ssf_microfacet_distribution* distrib; +}; + +/******************************************************************************* + * Private functions + ******************************************************************************/ +static res_T +microfacet_reflection_init(struct mem_allocator* allocator, void* data) +{ + struct microfacet_reflection* bxdf = data; + ASSERT(bxdf); + (void)allocator; + bxdf->reflectivity = 0.0; + bxdf->fresnel = NULL; + bxdf->distrib = NULL; + return RES_OK; +} + +static void +microfacet_reflection_release(void* data) +{ + struct microfacet_reflection* bxdf = data; + ASSERT(bxdf); + if(bxdf->fresnel) + SSF(fresnel_ref_put(bxdf->fresnel)); + if(bxdf->distrib) + SSF(microfacet_distribution_ref_put(bxdf->distrib)); +} + +static FINLINE double +microfacet_reflection_eval + (void* data, const double wo[3], const double N[3], const double wi[3]) +{ + struct microfacet_reflection* bxdf = data; + double wh[3]; + double cos_wo_N, cos_wi_N, cos_wh_N, cos_wh_wo, cos_wh_wi; + double F, D, G; + ASSERT(bxdf && bxdf->fresnel && bxdf->distrib); + ASSERT(wo && N && wi); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wi)); + + if((cos_wo_N = d3_dot(wo, N)) <= 0) return 0.0; + if((cos_wi_N = d3_dot(wi, N)) <= 0) return 0.0; + d3_normalize(wh, d3_add(wh, wo, wi)); + cos_wh_N = d3_dot(wh, N); + cos_wh_wi = d3_dot(wh, wi); + cos_wh_wo = cos_wh_wi; + + F = ssf_fresnel_eval(bxdf->fresnel, cos_wh_wi); + D = ssf_microfacet_distribution_eval(bxdf->distrib, wo, N, wh); + /* Cook Torrance geometry term */ + G = MMIN((2*cos_wh_N*cos_wo_N)/cos_wh_wo, (2*cos_wh_N*cos_wi_N)/cos_wh_wo); + G = MMIN(1, G); + + return bxdf->reflectivity * F*D*G/(4*cos_wi_N*cos_wo_N); +} + +static FINLINE double +microfacet_reflection_sample + (void* data, + const double u, + const double v, + const double wo[3], + const double N[3], + double wi[3], + double* pdf) +{ + struct microfacet_reflection* bxdf = data; + double dir[3]; + double wh[3]; + double pdf_wh; + double R; + ASSERT(data && u>=0 && u<1 && v>=0 && v<1 && wo && N && wi); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); + ASSERT(bxdf->distrib); + + if(d3_dot(wo, N) <= 0.0) return 0.0; + + ssf_microfacet_distribution_sample(bxdf->distrib, u, v, wo, N, wh, &pdf_wh); + reflect(dir, wo, wh); + *pdf = pdf_wh / (4.0*fabs(d3_dot(wo, wh))); /* TODO check this */ + if(d3_dot(dir, N) <= 0.0) return 0.0; + R = microfacet_reflection_eval(bxdf, wo, N, dir); + d3_set(wi, dir); + return R; +} + +static FINLINE double +microfacet_reflection_pdf + (void* data, const double wo[3], const double N[3], const double wi[3]) +{ + struct microfacet_reflection* bxdf = data; + double wh[3]; + double pdf_wh; + ASSERT(data && wo && N && wi); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wi)); + ASSERT(bxdf->distrib); + d3_normalize(wh, d3_add(wh, wi, wo)); + pdf_wh = ssf_microfacet_distribution_pdf(bxdf->distrib, wo, N, wh); + return pdf_wh / (4.0*fabs(d3_dot(wo, wh))); /* TODO check this */ +} + +/******************************************************************************* + * Exported symbols + ******************************************************************************/ +const struct ssf_bxdf_type ssf_microfacet_reflection = { + microfacet_reflection_init, + microfacet_reflection_release, + microfacet_reflection_sample, + microfacet_reflection_eval, + microfacet_reflection_pdf, + sizeof(struct microfacet_reflection), + ALIGNOF(struct microfacet_reflection) +}; + +res_T +ssf_microfacet_reflection_setup + (struct ssf_bxdf* bxdf, + const double reflectivity, + struct ssf_fresnel* fresnel, + struct ssf_microfacet_distribution* distrib) +{ + struct microfacet_reflection* microfacet; + if(!bxdf || reflectivity < 0 || reflectivity > 1 || !fresnel || !distrib) + return RES_BAD_ARG; + if(!BXDF_TYPE_EQ(&bxdf->type, &ssf_microfacet_reflection)) + return RES_BAD_ARG; + + SSF(fresnel_ref_get(fresnel)); + SSF(microfacet_distribution_ref_get(distrib)); + microfacet = bxdf->data; + microfacet->reflectivity = reflectivity; + microfacet->fresnel = fresnel; + microfacet->distrib = distrib; + return RES_OK; +} + diff --git a/src/ssf_optics.h b/src/ssf_optics.h @@ -0,0 +1,36 @@ +/* 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/>. */ + +#ifndef SSF_OPTICS_H +#define SSF_OPTICS_H + +#include <rsys/double3.h> + +/* Reflect the vector V wrt to the normal N */ +static INLINE double* +reflect(double res[3], const double V[3], const double N[3]) +{ + double tmp[3]; + double cos_V_N; + ASSERT(res && V && N); + ASSERT(d3_is_normalized(V) && d3_is_normalized(N)); + cos_V_N = d3_dot(V, N); + d3_muld(tmp, N, 2*cos_V_N); + d3_sub(res, tmp, V); + return res; +} + +#endif /* SSF_OPTICS_H */ + diff --git a/src/ssf_specular_reflection.c b/src/ssf_specular_reflection.c @@ -15,6 +15,7 @@ #include "ssf.h" #include "ssf_bxdf_c.h" +#include "ssf_optics.h" #include <rsys/double3.h> @@ -50,17 +51,15 @@ specular_reflection_sample { struct specular_reflection* brdf = data; double cos_wo_N; - double dir[3]; ASSERT(u >= 0 && u < 1 && v >= 0 && v < 1 && wi && N && wo); ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); (void)u, (void)v; - /* Reflect the outgoing direction wo with respect to the surface normal */ - cos_wo_N = d3_dot(wo, N); - d3_muld(dir, N, 2*cos_wo_N); - d3_sub(dir, dir, wo); - d3_set(wi, dir); + /* Reflect the outgoing direction wo with respect to the surface normal N */ + reflect(wi, wo, N); *pdf = 1.0; /* pdf */ + + cos_wo_N = d3_dot(wo, N); /* TODO check this */ return cos_wo_N <= 0 ? 0 : brdf->reflectivity / cos_wo_N/*|wi.N|*/; }