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 41fe49d5b9a46a9a9027ade386e9f8496f4b6fe7
parent 20b90a457c28bc2d3fd7958ecc824e70d074552f
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu,  8 Sep 2016 11:03:11 +0200

Major update of the ssf_bxdf API

The caller can defines its own BxDF through the public ssf_bxdf_type
interface. The built-in BxDFs are an exported instances of the
ssf_bxdf_type.

Diffstat:
Msrc/ssf.h | 42+++++++++++++++++++++++++++++++++++-------
Msrc/ssf_bsdf.c | 2+-
Msrc/ssf_bxdf.c | 80+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/ssf_bxdf_c.h | 18++----------------
Msrc/ssf_specular_reflection.c | 49++++++++++++++++++++-----------------------------
Msrc/test_ssf_bsdf.c | 2+-
Msrc/test_ssf_specular_reflection.c | 29++++++++++++++---------------
7 files changed, 125 insertions(+), 97 deletions(-)

diff --git a/src/ssf.h b/src/ssf.h @@ -42,8 +42,29 @@ struct mem_allocator; struct ssf_bsdf; /* Bidirectional Scattering Distribution Function */ struct ssf_bxdf; /* Bidirectional <Reflec|Transmit>tance Distribution Function */ +/* Generic BxDF type descriptor */ +struct ssf_bxdf_type { + res_T (*init)(struct mem_allocator* allocator, void* bxdf); + void (*release)(void* bxdf); + + double /* Sampled radiance */ + (*sample) + (void* bxdf, + const double u, /* Canonical random number */ + const double v, /* Canonical random number */ + const double w[3], /* Normalized direction. Point inward the surface */ + const double N[3], /* Normalized normal */ + double dir[4]); /* Sampled direction. The PDF is stored in dir[3] */ + + size_t sizeof_bxdf; /* In bytes */ + size_t alignof_bxdf; /* In Bytes */ +}; + BEGIN_DECLS +/* Reflects the incoming direction with respect to the surface normal */ +SSF_API const struct ssf_bxdf_type ssf_specular_reflection; + /******************************************************************************* * BSDF API - Bidirectionnal Scattering Distribution Function. Describes the * way the light is scattered by a surface with a combination of BxDFs. @@ -85,6 +106,12 @@ ssf_bsdf_sample * Describes how the light is reflected|transmitted by a 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); @@ -92,14 +119,15 @@ SSF_API res_T ssf_bxdf_ref_put (struct ssf_bxdf* bxdf); -/******************************************************************************* - * Specular Reflection API - BRDF that reflects the incoming direction with - * respect to the surface normal. - ******************************************************************************/ SSF_API res_T -ssf_specular_reflection_create - (struct mem_allocator* allocator, - struct ssf_bxdf** bxdf); +ssf_bxdf_sample + (struct ssf_bxdf* bxdf, + const double u, /* Canonical random number */ + const double v, /* Canonical random number */ + const double w[3], /* Normalized direction. Point inward the surface */ + const double N[3], /* Normalized normal */ + double dir[4], /* Sampled direction. The PDF is stored in dir[3] */ + double* radiance); /* Sampled radiance */ SSF_API res_T ssf_specular_reflection_setup diff --git a/src/ssf_bsdf.c b/src/ssf_bsdf.c @@ -154,7 +154,7 @@ ssf_bsdf_sample 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]); + SSF(bxdf_sample(bxdf, u, v, w, N, dirs[n], radiances+n)); if(radiances[n] <= 0 || dirs[n][PDF] <= 0) continue; /* Discard BxDF */ diff --git a/src/ssf_bxdf.c b/src/ssf_bxdf.c @@ -16,6 +16,7 @@ #include "ssf.h" #include "ssf_bxdf_c.h" +#include <rsys/double3.h> #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> @@ -29,7 +30,10 @@ bxdf_release(ref_T* ref) { struct ssf_bxdf* bxdf = CONTAINER_OF(ref, struct ssf_bxdf, ref); ASSERT(ref); - if(bxdf->data) MEM_RM(bxdf->allocator, bxdf->data); + if(bxdf->data) { + bxdf->type.release(bxdf->data); + MEM_RM(bxdf->allocator, bxdf->data); + } MEM_RM(bxdf->allocator, bxdf); } @@ -37,36 +41,19 @@ bxdf_release(ref_T* ref) * Exported functions ******************************************************************************/ res_T -ssf_bxdf_ref_get(struct ssf_bxdf* bxdf) -{ - if(!bxdf) return RES_BAD_ARG; - ref_get(&bxdf->ref); - return RES_OK; -} - -res_T -ssf_bxdf_ref_put(struct ssf_bxdf* bxdf) -{ - if(!bxdf) return RES_BAD_ARG; - ref_put(&bxdf->ref, bxdf_release); - return RES_OK; -} - -/******************************************************************************* - * Local functions - ******************************************************************************/ -res_T -bxdf_create +ssf_bxdf_create (struct mem_allocator* allocator, - const size_t sizeof_data, - const size_t alignof_data, + const struct ssf_bxdf_type* type, struct ssf_bxdf** out_bxdf) { struct mem_allocator* mem_allocator = NULL; struct ssf_bxdf* bxdf = NULL; res_T res = RES_OK; - ASSERT(out_bxdf); + if(!out_bxdf || !type) { + res = RES_BAD_ARG; + goto error; + } mem_allocator = allocator ? allocator : &mem_default_allocator; bxdf = MEM_CALLOC(mem_allocator, 1, sizeof(struct ssf_bxdf)); if(!bxdf) { @@ -75,17 +62,20 @@ bxdf_create } ref_init(&bxdf->ref); bxdf->allocator = mem_allocator; - if(!sizeof_data) goto exit; + bxdf->type = *type; - bxdf->data = MEM_ALLOC_ALIGNED(bxdf->allocator, sizeof_data, alignof_data); + bxdf->data = MEM_ALLOC_ALIGNED + (bxdf->allocator, bxdf->type.sizeof_bxdf, bxdf->type.alignof_bxdf); if(!bxdf->data) { res = RES_MEM_ERR; goto error; } - memset(bxdf->data, 0, sizeof_data); + memset(bxdf->data, 0, bxdf->type.sizeof_bxdf); + res = bxdf->type.init(mem_allocator, bxdf->data); + if(res != RES_OK) goto exit; exit: - *out_bxdf = bxdf; + if(out_bxdf) *out_bxdf = bxdf; return res; error: if(bxdf) { @@ -95,3 +85,37 @@ error: goto exit; } +res_T +ssf_bxdf_ref_get(struct ssf_bxdf* bxdf) +{ + if(!bxdf) return RES_BAD_ARG; + ref_get(&bxdf->ref); + return RES_OK; +} + +res_T +ssf_bxdf_ref_put(struct ssf_bxdf* bxdf) +{ + if(!bxdf) return RES_BAD_ARG; + ref_put(&bxdf->ref, bxdf_release); + return RES_OK; +} + +res_T +ssf_bxdf_sample + (struct ssf_bxdf* bxdf, + const double u, + const double v, + const double w[3], + const double N[3], + double dir[4], + double* radiance) +{ + if(!bxdf || u<0 || u>=1 || v<0 || v>=1 || !w || !dir || !radiance) + return RES_BAD_ARG; + if(!d3_is_normalized(w) || !d3_is_normalized(N)) + return RES_BAD_ARG; + *radiance = bxdf->type.sample(bxdf->data, u, v, w, N, dir); + return RES_OK; +} + diff --git a/src/ssf_bxdf_c.h b/src/ssf_bxdf_c.h @@ -16,22 +16,14 @@ #ifndef SSF_BXDF_C_H #define SSF_BXDF_C_H +#include "ssf.h" #include <rsys/ref_count.h> struct mem_allocator; -typedef double /* Sampled radiance */ -(*bxdf_sample_func_T) - (void* data, /* BxDF internal data */ - const double u, /* Canonical random number */ - const double v, /* Canonical random number */ - const double w[3], /* Incoming direction. Point inward the surface */ - const double N[3], /* Normalized normal */ - double dir[4]); /* Sampled direction. The PDF is stored in dir[3] */ - /* Generic Bidirectional <Reflec|Transmit>tance Distirbution Function */ struct ssf_bxdf { - bxdf_sample_func_T sample; + struct ssf_bxdf_type type; void* data; /* Specific internal data of the BxDF */ /* Private data */ @@ -39,12 +31,6 @@ struct ssf_bxdf { struct mem_allocator* allocator; }; -extern LOCAL_SYM res_T -bxdf_create - (struct mem_allocator* allocator, /* May be NULL <=> Use default allocator */ - const size_t sizeof_data, - const size_t alignof_data, - struct ssf_bxdf** bxdf); #endif /* SSF_BXDF_C_H */ diff --git a/src/ssf_specular_reflection.c b/src/ssf_specular_reflection.c @@ -25,6 +25,19 @@ struct specular_reflection { /******************************************************************************* * Helper functions ******************************************************************************/ +static res_T +specular_reflection_init(struct mem_allocator* allocator, void* bxdf) +{ + ASSERT(allocator && bxdf); + (void)allocator; + ((struct specular_reflection*)bxdf)->reflectivity = 0.0; + return RES_OK; +} + +static void +specular_reflection_release(void* bxdf) +{ (void)bxdf; } + static double specular_reflection_sample (void* data, @@ -50,35 +63,13 @@ specular_reflection_sample /******************************************************************************* * Exported functions ******************************************************************************/ -res_T -ssf_specular_reflection_create - (struct mem_allocator* allocator, struct ssf_bxdf** out_bxdf) -{ - struct ssf_bxdf* bxdf = NULL; - res_T res = RES_OK; - - if(!out_bxdf) { - res = RES_BAD_ARG; - goto error; - } - - res = bxdf_create(allocator, sizeof(struct specular_reflection), - ALIGNOF(struct specular_reflection), &bxdf); - if(res != RES_OK) goto error; - - bxdf->sample = specular_reflection_sample; - ((struct specular_reflection*)bxdf->data)->reflectivity = 1.0; - -exit: - if(out_bxdf) *out_bxdf = bxdf; - return res; -error: - if(bxdf) { - SSF(bxdf_ref_put(bxdf)); - bxdf = NULL; - } - goto exit; -} +const struct ssf_bxdf_type ssf_specular_reflection = { + specular_reflection_init, + specular_reflection_release, + specular_reflection_sample, + sizeof(struct specular_reflection), + ALIGNOF(struct specular_reflection) +}; res_T ssf_specular_reflection_setup(struct ssf_bxdf* bxdf, const double reflectivity) diff --git a/src/test_ssf_bsdf.c b/src/test_ssf_bsdf.c @@ -43,7 +43,7 @@ main(int argc, char** argv) CHECK(ssf_bsdf_ref_put(bsdf), RES_OK); CHECK(ssf_bsdf_create(&allocator, &bsdf), RES_OK); - CHECK(ssf_specular_reflection_create(&allocator, &bxdf), RES_OK); + CHECK(ssf_bxdf_create(&allocator, &ssf_specular_reflection, &bxdf), RES_OK); CHECK(ssf_specular_reflection_setup(bxdf, 2.0), RES_OK); CHECK(ssf_bsdf_add(NULL, NULL), RES_BAD_ARG); diff --git a/src/test_ssf_specular_reflection.c b/src/test_ssf_specular_reflection.c @@ -22,7 +22,6 @@ int main(int argc, char** argv) { struct mem_allocator allocator; - struct ssf_bsdf* bsdf; struct ssf_bxdf* brdf; double w[3]; double N[3]; @@ -32,9 +31,13 @@ main(int argc, char** argv) mem_init_proxy_allocator(&allocator, &mem_default_allocator); - CHECK(ssf_specular_reflection_create(NULL, NULL), RES_BAD_ARG); - CHECK(ssf_specular_reflection_create(&allocator, NULL), RES_BAD_ARG); - CHECK(ssf_specular_reflection_create(NULL, &brdf), RES_OK); + CHECK(ssf_bxdf_create(NULL, NULL, NULL), RES_BAD_ARG); + CHECK(ssf_bxdf_create(&allocator, NULL, NULL), RES_BAD_ARG); + CHECK(ssf_bxdf_create(NULL, &ssf_specular_reflection, NULL), RES_BAD_ARG); + CHECK(ssf_bxdf_create(&allocator, &ssf_specular_reflection, NULL), RES_BAD_ARG); + CHECK(ssf_bxdf_create(NULL, NULL, &brdf), RES_BAD_ARG); + CHECK(ssf_bxdf_create(&allocator, NULL, &brdf), RES_BAD_ARG); + CHECK(ssf_bxdf_create(NULL, &ssf_specular_reflection, &brdf), RES_OK); CHECK(ssf_bxdf_ref_get(NULL), RES_BAD_ARG); CHECK(ssf_bxdf_ref_get(brdf), RES_OK); @@ -42,7 +45,7 @@ main(int argc, char** argv) CHECK(ssf_bxdf_ref_put(brdf), RES_OK); CHECK(ssf_bxdf_ref_put(brdf), RES_OK); - CHECK(ssf_specular_reflection_create(&allocator, &brdf), RES_OK); + CHECK(ssf_bxdf_create(&allocator, &ssf_specular_reflection, &brdf), RES_OK); CHECK(ssf_specular_reflection_setup(NULL, -1.0), RES_BAD_ARG); CHECK(ssf_specular_reflection_setup(brdf, -1.0), RES_BAD_ARG); @@ -50,43 +53,39 @@ main(int argc, char** argv) CHECK(ssf_specular_reflection_setup(brdf, 1.0), RES_OK); CHECK(ssf_specular_reflection_setup(brdf, 0.0), RES_OK); - CHECK(ssf_bsdf_create(&allocator, &bsdf), RES_OK); - CHECK(ssf_bsdf_add(bsdf, brdf), RES_OK); - d3(N, 0.0, 1.0, 0.0); d3_normalize(w, d3(w, -1.0, -1.0, 0.0)); - CHECK(ssf_bsdf_sample(bsdf, 0, 0, w, N, dir, &rad), RES_OK); + CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir, &rad), RES_OK); CHECK(rad, 0.0); d3_normalize(w, d3(w, -1.0, -1.0, 0.0)); CHECK(ssf_specular_reflection_setup(brdf, 1.23), RES_OK); - CHECK(ssf_bsdf_sample(bsdf, 0, 0, w, N, dir, &rad), RES_OK); + CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir, &rad), RES_OK); CHECK(rad, 1.23); CHECK(d3_eq_eps(d3(w, w[0], -w[1], 0.0), dir, 1.e-6), 1); d3(w, 0.0, -1.0, 0.0); - CHECK(ssf_bsdf_sample(bsdf, 0, 0, w, N, dir, &rad), RES_OK); + CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir, &rad), RES_OK); CHECK(rad, 1.23); CHECK(d3_eq_eps(d3(w, 0.0, 1.0, 0.0), dir, 1.e-6), 1); d3_normalize(w, d3(w, -1.0, 1.0, 0.0)); - CHECK(ssf_bsdf_sample(bsdf, 0, 0, w, N, dir, &rad), RES_OK); + CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir, &rad), RES_OK); CHECK(rad, 1.23); CHECK(d3_eq_eps(d3(w, w[0], -w[1], 0.0), dir, 1.e-6), 1); d3(w, 0.0, 1.0, 0.0); - CHECK(ssf_bsdf_sample(bsdf, 0, 0, w, N, dir, &rad), RES_OK); + CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir, &rad), RES_OK); CHECK(rad, 1.23); CHECK(d3_eq_eps(d3(w, 0.0, -1.0, 0.0), dir, 1.e-6), 1); d3(w, -1.0, 0.0, 0.0); - CHECK(ssf_bsdf_sample(bsdf, 0, 0, w, N, dir, &rad), RES_OK); + CHECK(ssf_bxdf_sample(brdf, 0, 0, w, N, dir, &rad), RES_OK); CHECK(rad, 1.23); CHECK(d3_eq_eps(w, dir, 1.e-6), 1); CHECK(ssf_bxdf_ref_put(brdf), RES_OK); - CHECK(ssf_bsdf_ref_put(bsdf), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator);