commit 0ca3fa94134299c2a3ab5dae27c3ac1c1f8210ef
parent e2517cae8e52cefc810118f775d4d2e03ad30f85
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Fri, 9 Sep 2016 10:13:44 +0200
Implement the fresnel term for dielectric surfaces
Diffstat:
3 files changed, 114 insertions(+), 0 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -52,6 +52,7 @@ set(SSF_FILES_SRC
ssf_bsdf.c
ssf_bxdf.c
ssf_fresnel.c
+ ssf_fresnel_dielectric.c
ssf_fresnel_no_op.c
ssf_specular_reflection.c)
rcmake_prepend_path(SSF_FILES_SRC ${SSF_SOURCE_DIR})
diff --git a/src/ssf_fresnel_c.h b/src/ssf_fresnel_c.h
@@ -30,5 +30,12 @@ struct ssf_fresnel {
struct mem_allocator* allocator;
};
+#define FRESNEL_TYPE_EQ(A, B) \
+ ( (A)->init == (B)->init \
+ && (A)->release == (B)->release \
+ && (A)->eval == (B)->eval \
+ && (A)->sizeof_fresnel == (B)->sizeof_fresnel \
+ && (A)->alignof_fresnel == (B)->alignof_fresnel)
+
#endif /* SSF_FRESNEL_C_H */
diff --git a/src/ssf_fresnel_dielectric.c b/src/ssf_fresnel_dielectric.c
@@ -0,0 +1,106 @@
+/* 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_fresnel_c.h"
+#include <rsys/math.h>
+#include <math.h>
+
+struct fresnel_dielectric {
+ double lambda_i;
+ double lambda_t;
+};
+
+/*******************************************************************************
+ * Private functions
+ ******************************************************************************/
+static res_T
+fresnel_dielectric_init(struct mem_allocator* allocator, void* fresnel)
+{
+ struct fresnel_dielectric* fd = fresnel;
+ (void)allocator;
+ ASSERT(fresnel);
+ fd->lambda_i = 0.0;
+ fd->lambda_t = 0.0;
+ return RES_OK;
+}
+
+static void
+fresnel_dielectric_release(void* fresnel)
+{
+ (void)fresnel;
+}
+
+static double
+fresnel_dielectric_eval(void* fresnel, const double cos_theta_i)
+{
+ const struct fresnel_dielectric* fd = fresnel;
+ double sin_theta_i;
+ double sin_theta_t;
+ double cos_theta_t;
+ double R_par;
+ double R_per;
+ ASSERT(fresnel && cos_theta_i >= 0);
+
+ /* Use Snell's low to retrieve cos_theta_t:
+ * lambda_i * sin_theta_i = lambda_t * sin_theta_t */
+ sin_theta_i = sqrt(MMAX(0.0, 1.0 - cos_theta_i*cos_theta_i));
+ sin_theta_t = fd->lambda_i * sin_theta_i / fd->lambda_t;
+ if(sin_theta_t >= 1) return 1.0; /* Full reflection */
+ cos_theta_t = sqrt(1.0 - sin_theta_t*sin_theta_t);
+
+ /* Compute the reflectance for the light polarized with its electric field
+ * parallel to the plane of incidence */
+ R_par = (fd->lambda_i*cos_theta_t - fd->lambda_t*cos_theta_i)
+ / (fd->lambda_i*cos_theta_t + fd->lambda_t*cos_theta_i);
+ R_par = fabs(R_par);
+ R_par = R_par * R_par;
+
+ /* Compute the reflectance for the light polarized with its electric field
+ * perpendicular to the plane of incidence */
+ R_per = (fd->lambda_i*cos_theta_i - fd->lambda_t*cos_theta_t)
+ / (fd->lambda_i*cos_theta_i + fd->lambda_t*cos_theta_t);
+ R_per = fabs(R_per);
+ R_per = R_per * R_per;
+
+ return 0.5 * (R_par + R_per);
+}
+
+/*******************************************************************************
+ * Exported symbols
+ ******************************************************************************/
+const struct ssf_fresnel_type ssf_fresnel_dielectric = {
+ fresnel_dielectric_init,
+ fresnel_dielectric_release,
+ fresnel_dielectric_eval,
+ sizeof(struct fresnel_dielectric),
+ ALIGNOF(struct fresnel_dielectric)
+};
+
+res_T
+ssf_fresnel_dielectric_setup
+ (struct ssf_fresnel* fresnel, const double lambda_i, const double lambda_t)
+{
+ struct fresnel_dielectric* fd;
+
+ if(!fresnel) return RES_BAD_ARG;
+ if(!FRESNEL_TYPE_EQ(&fresnel->type, &ssf_fresnel_dielectric))
+ return RES_BAD_ARG;
+ fd = fresnel->data;
+ fd->lambda_i = lambda_i;
+ fd->lambda_t = lambda_t;
+ return RES_OK;
+}
+