commit ef1442447e44956317b98aa4d1fb5df702c42edb
parent 941277a1bc97837d22befd804c6de6368f099cb8
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 28 Sep 2016 19:09:33 +0200
Add the Blinn Microfacet distribution
Diffstat:
3 files changed, 142 insertions(+), 1 deletion(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -52,6 +52,7 @@ set(SSF_FILES_INC
ssf_optics.h)
set(SSF_FILES_SRC
ssf_beckmann_distribution.c
+ ssf_blinn_distribution.c
ssf_bsdf.c
ssf_bxdf.c
ssf_fresnel.c
diff --git a/src/ssf.h b/src/ssf.h
@@ -162,8 +162,10 @@ SSF_API const struct ssf_fresnel_type ssf_fresnel_dielectric_dielectric;
/* Fresnel term between a dielectric and a conductor */
SSF_API const struct ssf_fresnel_type ssf_fresnel_dielectric_conductor;
-/* Beckmann microfacet distribution */
+/* Beckmann microfacet distribution TODO add comments */
SSF_API const struct ssf_microfacet_distribution_type ssf_beckmann_distribution;
+/* Blinn microfacet distribution TODO add comments */
+SSF_API const struct ssf_microfacet_distribution_type ssf_blinn_distribution;
/*******************************************************************************
* BSDF API - Bidirectionnal Scattering Distribution Function. Describes the
@@ -398,6 +400,11 @@ ssf_beckmann_distribution_setup
(struct ssf_microfacet_distribution* distrib,
const double roughness); /* Must be > 0 */
+SSF_API res_T
+ssf_blinn_distribution_setup
+ (struct ssf_microfacet_distribution* distrib,
+ const double exponent); /* in [0, 10000] */
+
END_DECLS
#endif /* SSF_H */
diff --git a/src/ssf_blinn_distribution.c b/src/ssf_blinn_distribution.c
@@ -0,0 +1,133 @@
+/* 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/double33.h>
+
+#define EXPONENT_MAX 10000
+
+struct blinn_distribution {
+ double exponent;
+};
+
+/*******************************************************************************
+ * Private functions
+ ******************************************************************************/
+static res_T
+blinn_distribution_init(struct mem_allocator* allocator, void* distrib)
+{
+ ASSERT(distrib);
+ (void)allocator;
+ ((struct blinn_distribution*)distrib)->exponent = 32.0;
+ return RES_OK;
+}
+
+static void
+blinn_distribution_release(void* distrib)
+{ (void)distrib; }
+
+static double
+blinn_distribution_eval
+ (void* distrib, const double wo[3], const double N[3], const double wh[3])
+{
+ struct blinn_distribution* blinn = distrib;
+ double cos_wh_N;
+ ASSERT(distrib && wo && N && wh);
+ ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh));
+ ASSERT(blinn->exponent >= 0.0 && blinn->exponent <= EXPONENT_MAX);
+ (void)wo;
+ cos_wh_N = d3_dot(wh, N);
+ return (blinn->exponent + 2) / (2*PI) * pow(cos_wh_N, blinn->exponent);
+}
+
+static void
+blinn_distribution_sample
+ (void* distrib,
+ const double u,
+ const double v,
+ const double wo[3],
+ const double N[3],
+ double wh[3],
+ double* pdf)
+{
+ struct blinn_distribution* blinn = distrib;
+ double basis[9];
+ double dir[3];
+ double cos_theta, sin_theta;
+ double cos_wh_wo;
+ double phi;
+ ASSERT(distrib && u>=0 && u<1 && v>=0 && v<1 && wo && N && wh && pdf);
+ ASSERT(d3_is_normalized(wo) && d3_is_normalized(N));
+
+ phi = v*2*PI;
+ cos_theta = pow(u, 1/(blinn->exponent+1));
+ sin_theta = sqrt(MMAX(0, 1-cos_theta*cos_theta));
+ dir[0] = cos(phi) * sin_theta;
+ dir[1] = sin(phi) * sin_theta;
+ dir[2] = cos_theta;
+
+ d33_muld3(dir, d33_basis(basis, N), dir);
+ cos_wh_wo = d3_dot(dir, wo);
+ *pdf = cos_wh_wo > 0
+ ? (blinn->exponent+1)*pow(cos_theta, blinn->exponent) / (2*PI*4*cos_wh_wo)
+ : 0;
+ d3_set(wh, dir);
+}
+
+static double
+blinn_distribution_pdf
+ (void* distrib, const double wo[3], const double N[3], const double wh[3])
+{
+ struct blinn_distribution* blinn = distrib;
+ double cos_wh_N, cos_wh_wo;
+ ASSERT(distrib && wo && N && wh);
+ ASSERT(d3_is_normalized(wo) && d3_is_normalized(N) && d3_is_normalized(wh));
+ cos_wh_wo = d3_dot(wo, wh);
+ if(cos_wh_wo <= 0) return 0.0;
+ cos_wh_N = fabs(d3_dot(wh, N));
+ return
+ ((blinn->exponent+1)*pow(cos_wh_N, blinn->exponent)) / (2*PI*4*cos_wh_wo);
+}
+
+/*******************************************************************************
+ * Exported symbols
+ ******************************************************************************/
+const struct ssf_microfacet_distribution_type ssf_blinn_distribution = {
+ blinn_distribution_init,
+ blinn_distribution_release,
+ blinn_distribution_sample,
+ blinn_distribution_eval,
+ blinn_distribution_pdf,
+ sizeof(struct blinn_distribution),
+ ALIGNOF(struct blinn_distribution)
+};
+
+res_T
+ssf_blinn_distribution_setup
+ (struct ssf_microfacet_distribution* distrib,
+ const double exponent)
+{
+ if(!distrib || exponent < 0 || exponent > EXPONENT_MAX)
+ return RES_BAD_ARG;
+ if(!MICROFACET_DISTRIBUTION_TYPE_EQ(&distrib->type, &ssf_blinn_distribution))
+ return RES_BAD_ARG;
+ ((struct blinn_distribution*)distrib->data)->exponent = exponent;
+ return RES_OK;
+}
+
+