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:
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|*/;
}