commit 66eef3367eb6299863fe70b3dcaeefc3a74c71fd
parent 72c41a83a2219dfd1610cbdc8a804148149bce19
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 7 Apr 2020 15:40:09 +0200
Add and test the mrumtl_fetch_brdf2 function
Fetch the BRDF according to a canonical number. This function can be
used in a Monte Carlo integration to "linearly" interpolate the BRDF.
Diffstat:
4 files changed, 115 insertions(+), 9 deletions(-)
diff --git a/src/mrumtl.c b/src/mrumtl.c
@@ -753,6 +753,7 @@ fetch_brdf_wlen
(const struct mrumtl* mrumtl,
const char* func_name,
const double wavelength,
+ const double sample, /* < 0 <=> no sample */
const struct mrumtl_brdf** out_brdf)
{
const struct brdf_wlen* brdf_wlen = NULL;
@@ -760,6 +761,7 @@ fetch_brdf_wlen
size_t nbrdf_wlens = 0;
res_T res = RES_OK;
ASSERT(mrumtl && func_name && out_brdf);
+ ASSERT(sample < 0 || sample < 1);
brdf_wlens = darray_brdf_wlen_cdata_get(&mrumtl->brdf_wlens);
nbrdf_wlens = darray_brdf_wlen_size_get(&mrumtl->brdf_wlens);
@@ -784,11 +786,14 @@ fetch_brdf_wlen
* [brdf_wlen[-1].wlen, brdf_wlen[0].wlen[. Select the right BRDF wrt the
* distance from the submitted `wavelengths' and the wavelength of the
* found BRDF and the one of the previous BRDF. */
- const double dst0 = wavelength - brdf_wlen[-1].wlen;
- const double dst1 = brdf_wlen[0].wlen - wavelength;
- ASSERT(dst0 > 0 && dst1 >= 0);
- if(dst0 < dst1) {
- brdf_wlen = brdf_wlen - 1;
+ const double u =
+ (brdf_wlen[0].wlen - wavelength)
+ / (brdf_wlen[0].wlen - brdf_wlen[-1].wlen);
+
+ if(sample >= 0) {
+ if(sample < u) brdf_wlen = brdf_wlen - 1;
+ } else {
+ if(u > 0.5) brdf_wlen = brdf_wlen - 1;
}
}
@@ -953,7 +958,7 @@ error:
res_T
mrumtl_fetch_brdf
(const struct mrumtl* mrumtl,
- const double wavelength, /* In nanometers */
+ const double wlen, /* In nanometers */
const struct mrumtl_brdf** out_brdf)
{
res_T res = RES_OK;
@@ -965,10 +970,41 @@ mrumtl_fetch_brdf
switch(mrumtl->brdf_list_type) {
case BRDF_LIST_BAND:
- res = fetch_brdf_band(mrumtl, FUNC_NAME, wavelength, out_brdf);
+ res = fetch_brdf_band(mrumtl, FUNC_NAME, wlen, out_brdf);
break;
case BRDF_LIST_WLEN:
- res = fetch_brdf_wlen(mrumtl, FUNC_NAME, wavelength, out_brdf);
+ res = fetch_brdf_wlen(mrumtl, FUNC_NAME, wlen, -1, out_brdf);
+ break;
+ default: FATAL("Unreachable code.\n"); break;
+ }
+ if(res != RES_OK) goto error;
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+res_T
+mrumtl_fetch_brdf2
+ (const struct mrumtl* mrumtl,
+ const double wlen, /* In nanometers */
+ const double sample, /* in [0, 1) */
+ const struct mrumtl_brdf** out_brdf)
+{
+ res_T res = RES_OK;
+
+ if(!mrumtl || !out_brdf || sample < 0 || sample >= 1) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ switch(mrumtl->brdf_list_type) {
+ case BRDF_LIST_BAND:
+ res = fetch_brdf_band(mrumtl, FUNC_NAME, wlen, out_brdf);
+ break;
+ case BRDF_LIST_WLEN:
+ res = fetch_brdf_wlen(mrumtl, FUNC_NAME, wlen, sample, out_brdf);
break;
default: FATAL("Unreachable code.\n"); break;
}
diff --git a/src/mrumtl.h b/src/mrumtl.h
@@ -81,12 +81,40 @@ mrumtl_load_stream
FILE* stream,
const char* stream_name); /* May be NULL */
+/* Return the material BRDF for the submitted wavelength. If the material is
+ * defined per spectral band, the function returned the BRDF associated to the
+ * band into which the submitted wavelength lies. If no spectral band includes
+ * this wavelength, the returned BRDF is the one of the nearest spectral band.
+ * For per wavelength material, the function returns the BRDF associated to the
+ * nearest wavelength regarding the submitted wavelength. */
MRUMTL_API res_T
mrumtl_fetch_brdf
(const struct mrumtl* mrumtl,
const double wavelength, /* In nanometers */
const struct mrumtl_brdf** brdf);
+/* For materials defined per spectral band, the sample function has the same
+ * comportment of the fetch function. For per wavelength material, the BRDF to
+ * return is selected according to the coefficient `alpha' in [0, 1] defined as
+ * bellow:
+ *
+ * alpha = (lambda1 - wavelength) / (lambda1 - lambda0)
+ *
+ * with lambda0 < lambda1, the wavelengths of the BRDFs surrounding the
+ * submitted wavelength. The returned BRDF is either the BRDF corresponding to
+ * lambda0 or lambda1 whether `sample' is less than or greater than `alpha',
+ * respectively.
+ *
+ * If `wavelength' lies outside the material domain, the returned BRDF is
+ * either the first or the last one whether `wavelength' is below or above the
+ * wavelength material domain, respectively. */
+MRUMTL_API res_T
+mrumtl_fetch_brdf2
+ (const struct mrumtl* mrumtl,
+ const double wavelength, /* In nanometers */
+ const double sample, /* In [0, 1[. Ignored with nearest filtering */
+ const struct mrumtl_brdf** brdf);
+
MRUMTL_API enum mrumtl_brdf_type
mrumtl_brdf_get_type
(const struct mrumtl_brdf* brdf);
diff --git a/src/test_mrumtl_band.c b/src/test_mrumtl_band.c
@@ -192,6 +192,15 @@ check_fetch(struct mrumtl* mrumtl)
CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN);
CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314);
+ CHK(mrumtl_fetch_brdf2(NULL, 200, 0, &brdf) == RES_BAD_ARG);
+ CHK(mrumtl_fetch_brdf2(mrumtl, 200, nextafter(0,-1), &brdf) == RES_BAD_ARG);
+ CHK(mrumtl_fetch_brdf2(mrumtl, 200, 1, &brdf) == RES_BAD_ARG);
+ CHK(mrumtl_fetch_brdf2(mrumtl, 200, 0, NULL) == RES_BAD_ARG);
+
+ CHK(mrumtl_fetch_brdf2(mrumtl, 200, 0, &brdf) == RES_OK);
+ CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN);
+ CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314);
+
CHK(mrumtl_fetch_brdf(mrumtl, 0, &brdf) == RES_OK);
CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN);
CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314);
@@ -212,6 +221,14 @@ check_fetch(struct mrumtl* mrumtl)
rewind(fp);
CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK);
+ CHK(mrumtl_fetch_brdf2(mrumtl, 200.1, 0, &brdf) == RES_OK);
+ CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN);
+ CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314);
+
+ CHK(mrumtl_fetch_brdf2(mrumtl, 200.1, 0.9, &brdf) == RES_OK);
+ CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN);
+ CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314);
+
CHK(mrumtl_fetch_brdf(mrumtl, 200.1, &brdf) == RES_OK);
CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN);
CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.314);
diff --git a/src/test_mrumtl_wlen.c b/src/test_mrumtl_wlen.c
@@ -147,7 +147,7 @@ check_fetch(struct mrumtl* mrumtl)
CHK(mrumtl_load_stream(mrumtl, fp, filename) == RES_OK);
CHK(mrumtl_fetch_brdf(mrumtl, 2.9, &brdf) == RES_BAD_ARG);
- CHK(fp = fopen(filename, "w+"));
+ CHK(fp = freopen(filename, "w+", fp));
fprintf(fp, "wavelengths 1\n");
fprintf(fp, "280 lambertian 0.3");
rewind(fp);
@@ -217,6 +217,31 @@ check_fetch(struct mrumtl* mrumtl)
CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN);
CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.3);
+ CHK(mrumtl_fetch_brdf2(NULL, 0, 0, &brdf) == RES_BAD_ARG);
+ CHK(mrumtl_fetch_brdf2(mrumtl, 0, nextafter(0, -1), &brdf) == RES_BAD_ARG);
+ CHK(mrumtl_fetch_brdf2(mrumtl, 0, 1, &brdf) == RES_BAD_ARG);
+ CHK(mrumtl_fetch_brdf2(mrumtl, 0, 0, NULL) == RES_BAD_ARG);
+
+ CHK(mrumtl_fetch_brdf2(mrumtl, 0.15, 0.6, &brdf) == RES_OK);
+ CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR);
+ CHK(mrumtl_brdf_specular_get_reflectivity(brdf) == 0.2);
+
+ CHK(mrumtl_fetch_brdf2(mrumtl, 0.15, 0.4, &brdf) == RES_OK);
+ CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN);
+ CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.1);
+
+ CHK(mrumtl_fetch_brdf2(mrumtl, 4.4, 0, &brdf) == RES_OK);
+ CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN);
+ CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.4);
+
+ CHK(mrumtl_fetch_brdf2(mrumtl, 4.4, 0.24, &brdf) == RES_OK);
+ CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN);
+ CHK(mrumtl_brdf_lambertian_get_reflectivity(brdf) == 0.4);
+
+ CHK(mrumtl_fetch_brdf2(mrumtl, 4.4, 0.26, &brdf) == RES_OK);
+ CHK(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR);
+ CHK(mrumtl_brdf_specular_get_reflectivity(brdf) == 0.5);
+
fclose(fp);
}