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:
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 */
+