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 ff511972d059f0fc13dc6890b6c185f264cd1309
parent 275d20daa4c14eb11b226d86878802a3b5a2c5b1
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 21 Sep 2016 16:45:21 +0200

Implement the ssf_microfacet_distribution API

Diffstat:
Mcmake/CMakeLists.txt | 4+++-
Msrc/ssf.h | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Msrc/ssf_lambertian_reflection.c | 2+-
Asrc/ssf_microfacet_distribution.c | 168+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/ssf_microfacet_distribution_c.h | 43+++++++++++++++++++++++++++++++++++++++++++
5 files changed, 343 insertions(+), 46 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -49,7 +49,8 @@ set(SSF_FILES_INC ssf_bsdf_c.h ssf_bsdf_view_c.h ssf_bxdf_c.h - ssf_fresnel_c.h) + ssf_fresnel_c.h + ssf_microfacet_distribution_c.h) set(SSF_FILES_SRC ssf_bsdf.c ssf_bsdf_view.c @@ -59,6 +60,7 @@ set(SSF_FILES_SRC ssf_fresnel_dielectric_dielectric.c ssf_fresnel_no_op.c ssf_lambertian_reflection.c + ssf_microfacet_distribution.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 @@ -43,6 +43,7 @@ struct ssf_bsdf; /* Bidirectional Scattering Distribution Function */ struct ssf_bsdf_view; /* Current state of the BSDF */ struct ssf_bxdf; /* Bidirectional <Reflec|Transmit>tance Distribution Function */ struct ssf_fresnel; /* Equation of the Fresnel term */ +struct ssf_microfacet_distribution; /* Generic BxDF type descriptor. Note that by convention the outgoing direction * `wo' and the incoming direction `wi' point outward the surface. */ @@ -89,12 +90,45 @@ struct ssf_fresnel_type { double (*eval) (void* fresnel, - const double cos_theta); /* Cosine between facet normal and outgoing dir */ + const double cos_wi_N); /* Cosine between facet normal and incoming dir */ size_t sizeof_fresnel; /* In Bytes */ size_t alignof_fresnel; /* In Bytes */ }; +/* Generic descriptor of a microfacet distribution */ +struct ssf_microfacet_distribution_type { + res_T (*init)(struct mem_allocator* allocator, void* distrib); + void (*release)(void* distrib); + + void + (*sample) + (void* distrib, + const double u, /* Canonical random number */ + const double v, /* Canonical random number */ + const double wo[3], /* Normalized outgoing direction */ + const double N[3], /* Normalized Z-direction of the distribution */ + double wh[3], /* Sampled normalized half vector */ + double* pdf); /* PDF to sample wh wrt to wo */ + + double + (*eval) + (void* distrib, + const double wo[3], /* Normalized outgoing direction */ + const double N[3], /* Normalized Z-direction of the distribution */ + const double wh[3]); /* Normalized half vector */ + + double + (*pdf) + (void* distrib, + const double wo[3], /* Normalized outgoing direction */ + const double N[3], /* Normalized Z-direction of the distribution */ + const double wh[3]); /* Normalized half vector */ + + size_t sizeof_distribution; /* In Bytes */ + size_t alignof_distribution; /* In Bytes */ +}; + BEGIN_DECLS /* Reflects the incoming direction with respect to the surface normal */ @@ -180,6 +214,67 @@ ssf_bsdf_view_pdf const double wi[3]); /* Normalized outgoing direction */ /******************************************************************************* + * BxDF API - Bidirectional <Reflectance|Transmittance> distribution function. + * Describes how the light is reflected|transmitted by a surface. Note that by + * convention the outgoing direction `wo' and the incoming direction `wi' point + * outward the surface. + ******************************************************************************/ +SSF_API res_T +ssf_bxdf_create + (struct mem_allocator* allocator, + const struct ssf_bxdf_type* type, + struct ssf_bxdf** bxdf); + +SSF_API res_T +ssf_bxdf_ref_get + (struct ssf_bxdf* bxdf); + +SSF_API res_T +ssf_bxdf_ref_put + (struct ssf_bxdf* bxdf); + +SSF_API double /* Value of the BRDF for the submitted wo and the sampled wi */ +ssf_bxdf_sample + (struct ssf_bxdf* bxdf, + const double u, /* Canonical random number */ + const double v, /* Canonical random number */ + const double wo[3], /* Normalized outgoing direction */ + const double N[3], /* Normalized surface normal */ + double wi[3], /* Sampled normalized incoming direction. */ + double* pdf); /* PDF of the sampled direction */ + +SSF_API double /* Reflectivity */ +ssf_bxdf_eval + (struct ssf_bxdf* bxdf, + const double wo[3], /* Normalized outgoing direction */ + const double N[3], /* Normalized surface normal */ + const double wi[3]);/* Normalized incoming direction */ + +SSF_API double /* Probability */ +ssf_bxdf_pdf + (struct ssf_bxdf* bxdf, + const double wo[3], /* Normalized outgoing direction */ + const double N[3], /* Normalized surface normal */ + const double wi[3]);/* Normalized incoming dir. Point outward the surface */ + +/* 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 +ssf_bxdf_get_data + (struct ssf_bxdf* bxdf, + void** data); + +SSF_API res_T +ssf_specular_reflection_setup + (struct ssf_bxdf* bxdf, + const double reflectivity); + +SSF_API res_T +ssf_lambertian_reflection_setup + (struct ssf_bxdf* bxdf, + const double reflectivity); + +/******************************************************************************* * Fresnel API - Define the equation of the fresnel term ******************************************************************************/ SSF_API res_T @@ -225,66 +320,55 @@ ssf_fresnel_dielectric_conductor_setup const double k_t); /* Imaginary part of the refraction id of the conductor */ /******************************************************************************* - * BxDF API - Bidirectional <Reflectance|Transmittance> distribution function. - * Describes how the light is reflected|transmitted by a surface. Note that by - * convention the outgoing direction `wo' and the incoming direction `wi' point - * outward the surface. + * Microfacet Distribution API - Note that by convention the outgoing direction + * `wo' and the half vector `wh' point outward the surface. ******************************************************************************/ SSF_API res_T -ssf_bxdf_create +ssf_microfacet_distribution_create (struct mem_allocator* allocator, - const struct ssf_bxdf_type* type, - struct ssf_bxdf** bxdf); + const struct ssf_microfacet_distribution_type* type, + struct ssf_microfacet_distribution** distrib); SSF_API res_T -ssf_bxdf_ref_get - (struct ssf_bxdf* bxdf); +ssf_microfacet_distribution_ref_get + (struct ssf_microfacet_distribution* distrib); SSF_API res_T -ssf_bxdf_ref_put - (struct ssf_bxdf* bxdf); +ssf_microfacet_distribution_ref_put + (struct ssf_microfacet_distribution* distrib); -SSF_API double /* Value of the BRDF for the submitted wo and the sampled wi */ -ssf_bxdf_sample - (struct ssf_bxdf* bxdf, +SSF_API double +ssf_microfacet_distribution_eval + (struct ssf_microfacet_distribution* distrib, + const double wo[3], /* Normalized outgoing direction */ + const double N[3], /* Normalized Z-direction of the distribution */ + const double wh[3]); /* Normalized half vector */ + +SSF_API void +ssf_microfacet_distribution_sample + (struct ssf_microfacet_distribution* distrib, const double u, /* Canonical random number */ const double v, /* Canonical random number */ const double wo[3], /* Normalized outgoing direction */ - const double N[3], /* Normalized surface normal */ - double wi[3], /* Sampled normalized incoming direction. */ - double* pdf); /* PDF of the sampled direction */ + const double N[3], /* Normalized Z-direction of the distribution */ + double wh[3], /* Normalized half vector */ + double* pdf); /* PDF of the sampled half vector */ -SSF_API double /* Reflectivity */ -ssf_bxdf_eval - (struct ssf_bxdf* bxdf, +SSF_API double +ssf_microfacet_distribution_pdf + (struct ssf_microfacet_distribution* distrib, const double wo[3], /* Normalized outgoing direction */ - const double N[3], /* Normalized surface normal */ - const double wi[3]);/* Normalized incoming direction */ - -SSF_API double /* Probability */ -ssf_bxdf_pdf - (struct ssf_bxdf* bxdf, - const double wo[3], /* Normalized incoming direction */ - const double N[3], /* Normalized surface normal */ - const double wi[3]);/* Normalized outgoing dir. Point outward the surface */ + const double N[3], /* Normalized Z-direction of the distribution */ + const double wh[3]); /* Normalized half vector */ -/* 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 */ +/* Retrieve the internal data of the microfacet distribution term. Usefull for + * user defined distributions on which the caller has to retrieve their data to + * setup their parameters */ SSF_API res_T -ssf_bxdf_get_data - (struct ssf_bxdf* bxdf, +ssf_microfacet_distribution_get_data + (struct ssf_microfacet_distribution* distrib, void** data); -SSF_API res_T -ssf_specular_reflection_setup - (struct ssf_bxdf* bxdf, - const double reflectivity); - -SSF_API res_T -ssf_lambertian_reflection_setup - (struct ssf_bxdf* bxdf, - const double reflectivity); - END_DECLS #endif /* SSF_H */ diff --git a/src/ssf_lambertian_reflection.c b/src/ssf_lambertian_reflection.c @@ -94,7 +94,7 @@ lambertian_reflection_pdf } /******************************************************************************* - * Exorted functions + * Exorted symbols ******************************************************************************/ const struct ssf_bxdf_type ssf_lambertian_reflection = { lambertian_reflection_init, diff --git a/src/ssf_microfacet_distribution.c b/src/ssf_microfacet_distribution.c @@ -0,0 +1,168 @@ +/* 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_microfacet_distribution_c.h" + +#include <rsys/double3.h> +#include <rsys/mem_allocator.h> +#include <rsys/ref_count.h> + +#include <string.h> + +/******************************************************************************* + * Helper functions + ******************************************************************************/ +static INLINE int +check_microfacet_distribution_type + (const struct ssf_microfacet_distribution_type* type) +{ + return type + && type->init + && type->release + && type->sample + && type->eval + && type->pdf + && IS_POW2(type->alignof_distribution); +} + +static void +microfacet_distribution_release(ref_T* ref) +{ + struct ssf_microfacet_distribution* distrib = + CONTAINER_OF(ref, struct ssf_microfacet_distribution, ref); + ASSERT(ref); + if(distrib->data) { + distrib->type.release(distrib->data); + MEM_RM(distrib->allocator, distrib->data); + } + MEM_RM(distrib->allocator, distrib); +} + +/******************************************************************************* + * Exported functions + ******************************************************************************/ +res_T +ssf_microfacet_distribution_create + (struct mem_allocator* allocator, + const struct ssf_microfacet_distribution_type* type, + struct ssf_microfacet_distribution** out_distrib) +{ + struct mem_allocator* mem_allocator = NULL; + struct ssf_microfacet_distribution* distrib = NULL; + res_T res = RES_OK; + + if(!out_distrib || !check_microfacet_distribution_type(type)) { + res = RES_BAD_ARG; + goto error; + } + mem_allocator = allocator ? allocator : &mem_default_allocator; + distrib = MEM_CALLOC + (mem_allocator, 1, sizeof(struct ssf_microfacet_distribution)); + if(!distrib) { + res = RES_MEM_ERR; + goto error; + } + ref_init(&distrib->ref); + distrib->allocator = mem_allocator; + distrib->type = *type; + + distrib->data = MEM_ALLOC_ALIGNED + (distrib->allocator, + distrib->type.sizeof_distribution, + distrib->type.alignof_distribution); + if(!distrib->data) { + res = RES_MEM_ERR; + goto error; + } + memset(distrib->data, 0, distrib->type.sizeof_distribution); + res = distrib->type.init(mem_allocator, distrib->data); + if(res != RES_OK) goto error; + +exit: + if(out_distrib) *out_distrib = distrib; + return res; +error: + if(distrib) { + SSF(microfacet_distribution_ref_put(distrib)); + distrib = NULL; + } + goto exit; +} + +res_T +ssf_microfacet_distribution_ref_get(struct ssf_microfacet_distribution* distrib) +{ + if(!distrib) return RES_BAD_ARG; + ref_get(&distrib->ref); + return RES_OK; +} + +res_T +ssf_microfacet_distribution_ref_put(struct ssf_microfacet_distribution* distrib) +{ + if(!distrib) return RES_BAD_ARG; + ref_put(&distrib->ref, microfacet_distribution_release); + return RES_OK; +} + +void +ssf_microfacet_distribution_sample + (struct ssf_microfacet_distribution* distrib, + const double u, + const double v, + const double wo[3], + const double N[3], + double wh[3], + double* pdf) +{ + ASSERT(distrib && u>=0 && u<1 && v>=0 && v<1 && wo && N && wh && pdf); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(N)); + distrib->type.sample(distrib->data, u, v, wo, N, wh, pdf); +} + +double +ssf_microfacet_distribution_eval + (struct ssf_microfacet_distribution* distrib, + const double wo[3], + const double N[3], + const double wh[3]) +{ + ASSERT(distrib && wo && N && wh); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh)); + return distrib->type.eval(distrib->data, wo, N, wh); +} + +double +ssf_microfacet_distribution_pdf + (struct ssf_microfacet_distribution* distrib, + const double wo[3], + const double N[3], + const double wh[3]) +{ + ASSERT(distrib && wh && wo); + ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh)); + return distrib->type.pdf(distrib->data, wo, N, wh); +} + +res_T +ssf_microfacet_distribution_get_data + (struct ssf_microfacet_distribution* distrib, void** data) +{ + if(!distrib || !data) return RES_BAD_ARG; + *data = distrib->data; + return RES_OK; +} + diff --git a/src/ssf_microfacet_distribution_c.h b/src/ssf_microfacet_distribution_c.h @@ -0,0 +1,43 @@ +/* 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_MICROFACET_DISTRIBUTION_C_H +#define SSF_MICROFACET_DISTRIBUTION_C_H + +#include "ssf.h" +#include <rsys/ref_count.h> + +struct mem_allocator; + +struct ssf_microfacet_distribution { + struct ssf_microfacet_distribution_type type; + void* data; /* Specific internal data of the distribution */ + + /* Private data */ + ref_T ref; + struct mem_allocator* allocator; +}; + +#define MICROFACET_DISTRIBUTION_TYPE_EQ(A, B) \ + ( (A)->init == (B)->init \ + && (A)->release == (B)->release \ + && (A)->sample == (B)->sample \ + && (A)->eval == (B)->eval \ + && (A)->pdf == (B)->pdf \ + && (A)->sizeof_distribution == (B)->sizeof_distribution \ + && (A)->alignof_distribution == (B)->alignof_distribution) + +#endif /* SSF_MICROFACET_DISTRIBUTION_C_H */ +