mrumtl

Describe materials that vary spectrally
git clone git://git.meso-star.fr/mrumtl.git
Log | Files | Refs | README | LICENSE

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:
Msrc/mrumtl.c | 52++++++++++++++++++++++++++++++++++++++++++++--------
Msrc/mrumtl.h | 28++++++++++++++++++++++++++++
Msrc/test_mrumtl_band.c | 17+++++++++++++++++
Msrc/test_mrumtl_wlen.c | 27++++++++++++++++++++++++++-
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); }