commit de2657db1d32d637bad0edea9e9a1b8242a492d6
parent b3d12c3a4c54dd0d288544831078bbc5f0c8f88b
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 13 Jul 2016 11:41:55 +0200
Add the brdf composite internal data structure
Diffstat:
3 files changed, 234 insertions(+), 0 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -50,6 +50,7 @@ set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
set(SSOL_FILES_SRC
ssol_brdf.c
+ ssol_brdf_composite.c
ssol_brdf_reflection.c
ssol_device.c
ssol_image.c
@@ -68,6 +69,7 @@ set(SSOL_FILES_INC_API
set(SSOL_FILES_INC
ssol_brdf.h
+ ssol_brdf_composite.h
ssol_brdf_reflection.h
ssol_device_c.h
ssol_image_c.h
diff --git a/src/ssol_brdf_composite.c b/src/ssol_brdf_composite.c
@@ -0,0 +1,173 @@
+/* Copyright (C) CNRS 2016
+ *
+ * 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 "ssol.h"
+#include "ssol_brdf.h"
+#include "ssol_brdf_composite.h"
+#include "ssol_device_c.h"
+
+#include <rsys/dynamic_array.h>
+#include <rsys/float4.h>
+#include <rsys/ref_count.h>
+
+#include <star/ssp.h>
+
+#define MAX_COMPONENTS 8
+
+struct brdf_composite {
+ struct brdf* components[MAX_COMPONENTS];
+ size_t ncomponents;
+
+ ref_T ref;
+ struct ssol_device* dev;
+};
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static void
+brdf_composite_release(ref_T* ref)
+{
+ struct ssol_device* dev;
+ struct brdf_composite* brdfs = CONTAINER_OF(ref, struct brdf_composite, ref);
+ ASSERT(ref);
+
+ brdf_composite_clear(brdfs);
+ dev = brdfs->dev;
+ MEM_RM(dev->allocator, brdfs);
+ SSOL(device_ref_put(dev));
+}
+
+/*******************************************************************************
+ * Local functions
+ ******************************************************************************/
+res_T
+brdf_composite_create
+ (struct ssol_device* dev, struct brdf_composite** out_brdfs)
+{
+ struct brdf_composite* brdfs = NULL;
+ res_T res = RES_OK;
+ ASSERT(dev && out_brdfs);
+
+ brdfs = MEM_CALLOC(dev->allocator, 1, sizeof(struct brdf_composite));
+ if(!brdfs) {
+ res = RES_MEM_ERR;
+ goto error;
+ }
+
+ ref_init(&brdfs->ref);
+ SSOL(device_ref_get(dev));
+ brdfs->dev = dev;
+
+error:
+ *out_brdfs = brdfs;
+ return res;
+exit:
+ if(brdfs) {
+ brdf_composite_ref_put(brdfs);
+ brdfs = NULL;
+ }
+ goto exit;
+}
+
+void
+brdf_composite_ref_get(struct brdf_composite* brdfs)
+{
+ ASSERT(brdfs);
+ ref_get(&brdfs->ref);
+}
+
+void
+brdf_composite_ref_put(struct brdf_composite* brdfs)
+{
+ ASSERT(brdfs);
+ ref_put(&brdfs->ref, brdf_composite_release);
+}
+
+res_T
+brdf_composite_add(struct brdf_composite* brdfs, struct brdf* brdf)
+{
+ ASSERT(brdfs && brdf);
+ if(brdfs->ncomponents >= MAX_COMPONENTS) return RES_MEM_ERR;
+ brdf_ref_get(brdf);
+ brdfs->components[brdfs->ncomponents] = brdf;
+ ++brdfs->ncomponents;
+ return RES_OK;
+}
+
+void
+brdf_composite_clear(struct brdf_composite* brdfs)
+{
+ size_t i;
+ ASSERT(brdfs);
+ FOR_EACH(i, 0, brdfs->ncomponents) {
+ brdf_ref_put(brdfs->components[i]);
+ }
+ brdfs->ncomponents = 0;
+}
+
+double
+brdf_composite_sample
+ (struct brdf_composite* brdfs,
+ struct ssp_rng* rng,
+ const float w[3],
+ const float N[3],
+ float dir[4])
+{
+ const size_t PDF = 3;
+ double radiances[MAX_COMPONENTS];
+ float dirs[MAX_COMPONENTS][4];
+ double probas[MAX_COMPONENTS];
+ double cumul[MAX_COMPONENTS];
+ double probas_sum;
+ double r;
+ size_t i, n;
+ ASSERT(brdfs && rng && w && N && dir);
+
+ /* Build the probability distribution by sampling each BRDF */
+ n = 0;
+ probas_sum = 0.0f;
+ FOR_EACH(i, 0, brdfs->ncomponents) {
+ struct brdf* brdf = brdfs->components[i];
+
+ radiances[n] = brdf->sample(brdf->data, rng, w, N, dirs[n]);
+ if(radiances[n] <= 0 || dirs[n][PDF] <= 0)
+ continue; /* Discard component */
+
+ probas[n] = radiances[n] / dirs[n][PDF];
+ probas_sum += probas[n];
+ ++n;
+ }
+
+ if(!n) { /* No valid component to sample */
+ f4_splat(dir, 0.f);
+ return 0;
+ }
+
+ /* Normalize the probability distribution */
+ FOR_EACH(i, 0, n) probas[i] /= probas_sum;
+
+ /* Compute the cumulative */
+ cumul[0] = probas[0];
+ cumul[n-1] = 1.f;
+ FOR_EACH(i, 1, n-1) cumul[i] = cumul[i-1] + probas[i];
+
+ /* Finally sample the distribution */
+ r = ssp_rng_canonical(rng);
+ FOR_EACH(i, 0, n-1) if(r <= cumul[i]) break;
+ f4_set(dir, dirs[i]);
+ return radiances[i];
+}
+
diff --git a/src/ssol_brdf_composite.h b/src/ssol_brdf_composite.h
@@ -0,0 +1,59 @@
+/* Copyright (C) CNRS 2016
+ *
+ * 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 SSOL_BRDF_COMPOSITE_H
+#define SSOL_BRDF_COMPOSITE_H
+
+#include <rsys/rsys.h>
+
+struct brdf;
+struct ssol_device;
+struct ssp_rng;
+
+/* Container of BRDFs */
+struct brdf_composite;
+
+extern LOCAL_SYM res_T
+brdf_composite_create
+ (struct ssol_device* dev,
+ struct brdf_composite** brdfs);
+
+extern LOCAL_SYM void
+brdf_composite_ref_get
+ (struct brdf_composite* brdfs);
+
+extern LOCAL_SYM void
+brdf_composite_ref_put
+ (struct brdf_composite* brdfs);
+
+extern LOCAL_SYM res_T
+brdf_composite_add
+ (struct brdf_composite* brdfs,
+ struct brdf* brdf);
+
+extern LOCAL_SYM void
+brdf_composite_clear
+ (struct brdf_composite* brdfs);
+
+extern LOCAL_SYM double
+brdf_composite_sample
+ (struct brdf_composite* brdfs,
+ struct ssp_rng* rng,
+ const float w[3], /* Incoming direction */
+ const float N[3], /* Normalized normal */
+ float dir[4]); /* Sampled direction. The PDF is stored in dir[3] */
+
+#endif /* SSOL_BRDF_COMPOSITE_H */
+