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:
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);