htrdr

Solving radiative transfer in heterogeneous media
git clone git://git.meso-star.fr/htrdr.git
Log | Files | Refs | README | LICENSE

commit 0861bc16a4cba9471856d02e86b71cf2679572f4
parent bac2794a8a10708c74ca758dc7ee2a4ab8cd17dc
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu,  5 Nov 2020 09:36:32 +0100

Upd the htrdr_interface API

Add the htrdr_interface_fetch_hit_mtl function. Replace the
htrdr_interface_create_bsdf function by the htrdr_mtl_create_bsdf one
and remove the htrdr_interface_fetch_temperature function.

Diffstat:
Mcmake/CMakeLists.txt | 1-
Msrc/htrdr_compute_radiance_lw.c | 27+++++++--------------------
Msrc/htrdr_compute_radiance_sw.c | 7++++---
Dsrc/htrdr_interface.c | 228-------------------------------------------------------------------------------
Msrc/htrdr_interface.h | 64+++++++++++++++++++++++++++++++++++++++++++++-------------------
Msrc/htrdr_materials.c | 122+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/htrdr_materials.h | 13+++++++++++++
7 files changed, 191 insertions(+), 271 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -102,7 +102,6 @@ set(HTRDR_FILES_SRC htrdr_draw_map.c htrdr_grid.c htrdr_ground.c - htrdr_interface.c htrdr_main.c htrdr_materials.c htrdr_ran_wlen.c diff --git a/src/htrdr_compute_radiance_lw.c b/src/htrdr_compute_radiance_lw.c @@ -228,6 +228,7 @@ htrdr_compute_radiance_lw /* Scattering at a surface */ } else { struct htrdr_interface interf = HTRDR_INTERFACE_NULL; + const struct htrdr_mtl* mtl = NULL; struct ssf_bsdf* bsdf = NULL; double bounce_reflectivity = 0; double N[3]; @@ -235,10 +236,10 @@ htrdr_compute_radiance_lw ASSERT(ctx.event_type == EVENT_NONE); ASSERT(!S3D_HIT_NONE(&s3d_hit)); - /* Fetch the hit interface and build its BSDF */ + /* Fetch the hit interface materal and build its BSDF */ htrdr_ground_get_interface(htrdr->ground, &s3d_hit, &interf); - HTRDR(interface_create_bsdf - (htrdr, &interf, ithread, wlen, pos_next, dir, rng, &s3d_hit, &bsdf)); + mtl = htrdr_interface_fetch_hit_mtl(&interf, dir, &s3d_hit); + HTRDR(mtl_create_bsdf(htrdr, mtl, ithread, wlen, rng, &bsdf)); d3_normalize(N, d3_set_f3(N, s3d_hit.normal)); if(d3_dot(N, wo) < 0) d3_minus(N, N); @@ -253,25 +254,11 @@ htrdr_compute_radiance_lw SSF(bsdf_ref_put(bsdf)); if(ssp_rng_canonical(rng) >= bounce_reflectivity) { /* Absorbed at boundary */ -#if 0 - /* Retrieve the temperature of the interface. Anyway, since we do not - * have this data yet, we use the temperature of the sky at the current - * position as the temperature of the surface. */ - temperature = htsky_fetch_temperature(htrdr->sky, pos_next); -#else - /* Retrieve the temperature of the interface. */ - temperature = htrdr_interface_fetch_temperature - (htrdr, &interf, dir, &s3d_hit); -#endif - if(temperature <= 0) { - w = 0; - } else { - /* weight is planck integrated over the spectral sub-interval */ - w = planck_monochromatic(wlen_m, temperature); - } + temperature = mtl->temperature; /* Fetch mtl temperature */ + /* Weight is planck integrated over the spectral sub-interval */ + w = temperature > 0 ? planck_monochromatic(wlen_m, temperature) : 0; break; } - s3d_hit_prev = s3d_hit; } d3_set(pos, pos_next); diff --git a/src/htrdr_compute_radiance_sw.c b/src/htrdr_compute_radiance_sw.c @@ -383,11 +383,12 @@ htrdr_compute_radiance_sw /* Sample the scattering direction */ if(surface_scattering) { /* Scattering at a surface */ struct htrdr_interface interf = HTRDR_INTERFACE_NULL; + const struct htrdr_mtl* mtl = NULL; - /* Fetch the hit interface and build its BSDF */ + /* Fetch the hit interface materal and build its BSDF */ htrdr_ground_get_interface(htrdr->ground, &s3d_hit, &interf); - HTRDR(interface_create_bsdf - (htrdr, &interf, ithread, wlen, pos_next, dir, rng, &s3d_hit, &bsdf)); + mtl = htrdr_interface_fetch_hit_mtl(&interf, dir, &s3d_hit); + HTRDR(mtl_create_bsdf(htrdr, mtl, ithread, wlen, rng, &bsdf)); /* Revert the normal if necessary to match the SSF convention */ d3_normalize(N, d3_set_f3(N, s3d_hit.normal)); diff --git a/src/htrdr_interface.c b/src/htrdr_interface.c @@ -1,228 +0,0 @@ -/* Copyright (C) 2018, 2019 CNRS, Université Paul Sabatier - * Copyright (C) 2018, 2019, 2020 |Meso|Star> (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 "htrdr.h" -#include "htrdr_interface.h" - -#include <modradurb/mrumtl.h> - -#include <star/s3d.h> -#include <star/ssf.h> -#include <star/ssp.h> - -#include <rsys/cstr.h> -#include <rsys/double3.h> - -/******************************************************************************* - * Helper functions - ******************************************************************************/ -static res_T -create_bsdf_diffuse - (struct htrdr* htrdr, - const struct mrumtl_brdf* brdf, - const size_t ithread, - struct ssf_bsdf** out_bsdf) -{ - struct ssf_bsdf* bsdf = NULL; - double reflectivity = 0; - res_T res = RES_OK; - ASSERT(htrdr && brdf && out_bsdf); - ASSERT(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); - ASSERT(ithread < htrdr->nthreads); - - res = ssf_bsdf_create - (&htrdr->lifo_allocators[ithread], &ssf_lambertian_reflection, &bsdf); - if(res != RES_OK) goto error; - - reflectivity = mrumtl_brdf_lambertian_get_reflectivity(brdf); - res = ssf_lambertian_reflection_setup(bsdf, reflectivity); - if(res != RES_OK) goto error; - -exit: - *out_bsdf = bsdf; - return res; -error: - if(bsdf) { SSF(bsdf_ref_put(bsdf)); bsdf = NULL; } - goto exit; -} - -static res_T -create_bsdf_specular - (struct htrdr* htrdr, - const struct mrumtl_brdf* brdf, - const size_t ithread, - struct ssf_bsdf** out_bsdf) -{ - struct ssf_bsdf* bsdf = NULL; - struct ssf_fresnel* fresnel = NULL; - double reflectivity = 0; - res_T res = RES_OK; - ASSERT(htrdr && brdf && out_bsdf); - ASSERT(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); - ASSERT(ithread < htrdr->nthreads); - - res = ssf_bsdf_create - (&htrdr->lifo_allocators[ithread], &ssf_specular_reflection, &bsdf); - if(res != RES_OK) goto error; - - res = ssf_fresnel_create - (&htrdr->lifo_allocators[ithread], &ssf_fresnel_constant, &fresnel); - if(res != RES_OK) goto error; - - reflectivity = mrumtl_brdf_specular_get_reflectivity(brdf); - res = ssf_fresnel_constant_setup(fresnel, reflectivity); - if(res != RES_OK) goto error; - - res = ssf_specular_reflection_setup(bsdf, fresnel); - if(res != RES_OK) goto error; - -exit: - if(fresnel) SSF(fresnel_ref_put(fresnel)); - *out_bsdf = bsdf; - return res; -error: - if(bsdf) { SSF(bsdf_ref_put(bsdf)); bsdf = NULL; } - goto exit; -} - -static const struct htrdr_mtl* -interface_fetch_mtl - (const struct htrdr_interface* interf, - const double dir[3], - struct s3d_hit* hit) -{ - const struct htrdr_mtl* mtl = NULL; - enum { FRONT, BACK }; - ASSERT(interf && dir && hit && !S3D_HIT_NONE(hit)); - - if(interf->mtl_thin.mrumtl) { - mtl = &interf->mtl_thin; - } else { - double N[3]; - int hit_side; - d3_normalize(N, d3_set_f3(N, hit->normal)); - hit_side = d3_dot(N, dir) < 0 ? FRONT : BACK; - - /* Retrieve the brdf of the material on the other side of the hit side */ - switch(hit_side) { - case BACK: mtl = &interf->mtl_front; break; - case FRONT: mtl = &interf->mtl_back; break; - default: FATAL("Unreachable code.\n"); break; - } - - /* Due to numerical issue the hit side might be wrong and thus the fetched - * material might be undefined (e.g. semi-transparent materials). Handle this - * issue by fetching the other material. */ - if(!mtl->mrumtl) { - switch(hit_side) { - case BACK: mtl = &interf->mtl_back; break; - case FRONT: mtl = &interf->mtl_front; break; - default: FATAL("Unreachable code.\n"); break; - } - } - ASSERT(mtl->mrumtl); - } - - return mtl; -} - -/******************************************************************************* - * Local functions - ******************************************************************************/ -res_T -htrdr_interface_create_bsdf - (struct htrdr* htrdr, - const struct htrdr_interface* interf, - const size_t ithread, - const double wavelength, - const double pos[3], - const double dir[3], - struct ssp_rng* rng, - struct s3d_hit* hit, - struct ssf_bsdf** out_bsdf) -{ - struct ssf_bsdf* bsdf = NULL; - const struct mrumtl_brdf* brdf = NULL; - const struct htrdr_mtl* mtl = NULL; - double r; - res_T res = RES_OK; - (void)pos; - ASSERT(interf && - ( interf->mtl_front.mrumtl - || interf->mtl_back.mrumtl - || interf->mtl_thin.mrumtl)); - ASSERT(htrdr && interf && pos && dir && hit && out_bsdf); - ASSERT(d3_is_normalized(dir) && !S3D_HIT_NONE(hit)); - - mtl = interface_fetch_mtl(interf, dir, hit); - ASSERT(mtl != NULL); - - r = ssp_rng_canonical(rng); - - res = mrumtl_fetch_brdf2(mtl->mrumtl, wavelength, r, &brdf); - if(res != RES_OK) { - htrdr_log_err(htrdr, - "%s: error retrieving the MruMtl BRDF for the wavelength %g.\n", - FUNC_NAME, wavelength); - res = RES_BAD_ARG; - goto error; - } - - switch(mrumtl_brdf_get_type(brdf)) { - case MRUMTL_BRDF_LAMBERTIAN: - res = create_bsdf_diffuse(htrdr, brdf, ithread, &bsdf); - break; - case MRUMTL_BRDF_SPECULAR: - res = create_bsdf_specular(htrdr, brdf, ithread, &bsdf); - break; - default: FATAL("Unreachable code.\n"); break; - } - if(res != RES_OK) { - htrdr_log_err(htrdr, "%s: could not create the BSDF -- %s.\n", - FUNC_NAME, res_to_cstr(res)); - goto error; - } - -exit: - *out_bsdf = bsdf; - return res; -error: - if(bsdf) { SSF(bsdf_ref_put(bsdf)); bsdf = NULL; } - goto exit; -} - -double -htrdr_interface_fetch_temperature - (struct htrdr* htrdr, - const struct htrdr_interface* interf, - const double dir[3], - struct s3d_hit* hit) -{ - const struct htrdr_mtl* mtl = NULL; - - ASSERT(interf && - ( interf->mtl_front.mrumtl - || interf->mtl_back.mrumtl - || interf->mtl_thin.mrumtl)); - ASSERT(htrdr && interf && dir && hit); - ASSERT(d3_is_normalized(dir) && !S3D_HIT_NONE(hit)); - - mtl = interface_fetch_mtl(interf, dir, hit); - ASSERT(mtl != NULL); - - return mtl->temperature; -} - diff --git a/src/htrdr_interface.h b/src/htrdr_interface.h @@ -18,7 +18,8 @@ #define HTRDR_INTERFACE_H #include "htrdr_materials.h" -#include <star/ssf.h> +#include <star/s3d.h> +#include <rsys/double3.h> /* Forward declaration of external data type */ struct mrumtl; @@ -33,24 +34,49 @@ struct htrdr_interface { }; static const struct htrdr_interface HTRDR_INTERFACE_NULL; -extern LOCAL_SYM res_T -htrdr_interface_create_bsdf - (struct htrdr* htrdr, - const struct htrdr_interface* interf, - const size_t ithread, - const double wavelength, - const double pos[3], - const double dir[3], /* Normalized incoming direction */ - struct ssp_rng* rng, - struct s3d_hit* hit, - struct ssf_bsdf** bsdf); - -extern LOCAL_SYM double -htrdr_interface_fetch_temperature - (struct htrdr* htrdr, - const struct htrdr_interface* interf, - const double dir[3], /* Normalized incoming direction */ - struct s3d_hit* hit); +static INLINE const struct htrdr_mtl* +htrdr_interface_fetch_hit_mtl + (const struct htrdr_interface* interf, + const double dir[3], /* Incoming ray */ + struct s3d_hit* hit) +{ + const struct htrdr_mtl* mtl = NULL; + enum { FRONT, BACK }; + ASSERT(interf && dir && d3_is_normalized(dir) && hit && !S3D_HIT_NONE(hit)); + ASSERT(interf->mtl_front.mrumtl + || interf->mtl_back.mrumtl + || interf->mtl_thin.mrumtl); + + if(interf->mtl_thin.mrumtl) { + mtl = &interf->mtl_thin; + } else { + double N[3]; + int hit_side; + d3_normalize(N, d3_set_f3(N, hit->normal)); + hit_side = d3_dot(N, dir) < 0 ? FRONT : BACK; + + /* Retrieve the brdf of the material on the *other side* of the hit side */ + switch(hit_side) { + case BACK: mtl = &interf->mtl_front; break; + case FRONT: mtl = &interf->mtl_back; break; + default: FATAL("Unreachable code.\n"); break; + } + + /* Due to numerical issue the hit side might be wrong and thus the fetched + * material might be undefined (e.g. semi-transparent materials). Handle this + * issue by fetching the other material. */ + if(!mtl->mrumtl) { + switch(hit_side) { + case BACK: mtl = &interf->mtl_back; break; + case FRONT: mtl = &interf->mtl_front; break; + default: FATAL("Unreachable code.\n"); break; + } + } + ASSERT(mtl->mrumtl); + } + + return mtl; +} #endif /* HTRDR_INTERFACE_H */ diff --git a/src/htrdr_materials.c b/src/htrdr_materials.c @@ -20,8 +20,11 @@ #include "htrdr_materials.h" #include <modradurb/mrumtl.h> +#include <star/ssf.h> +#include <star/ssp.h> #include <rsys/cstr.h> +#include <rsys/double3.h> #include <rsys/hash_table.h> #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> @@ -240,6 +243,75 @@ materials_release(ref_T* ref) MEM_RM(mats->htrdr->allocator, mats); } +static res_T +create_bsdf_diffuse + (struct htrdr* htrdr, + const struct mrumtl_brdf* brdf, + const size_t ithread, + struct ssf_bsdf** out_bsdf) +{ + struct ssf_bsdf* bsdf = NULL; + double reflectivity = 0; + res_T res = RES_OK; + ASSERT(htrdr && brdf && out_bsdf); + ASSERT(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_LAMBERTIAN); + ASSERT(ithread < htrdr->nthreads); + + res = ssf_bsdf_create + (&htrdr->lifo_allocators[ithread], &ssf_lambertian_reflection, &bsdf); + if(res != RES_OK) goto error; + + reflectivity = mrumtl_brdf_lambertian_get_reflectivity(brdf); + res = ssf_lambertian_reflection_setup(bsdf, reflectivity); + if(res != RES_OK) goto error; + +exit: + *out_bsdf = bsdf; + return res; +error: + if(bsdf) { SSF(bsdf_ref_put(bsdf)); bsdf = NULL; } + goto exit; +} + +static res_T +create_bsdf_specular + (struct htrdr* htrdr, + const struct mrumtl_brdf* brdf, + const size_t ithread, + struct ssf_bsdf** out_bsdf) +{ + struct ssf_bsdf* bsdf = NULL; + struct ssf_fresnel* fresnel = NULL; + double reflectivity = 0; + res_T res = RES_OK; + ASSERT(htrdr && brdf && out_bsdf); + ASSERT(mrumtl_brdf_get_type(brdf) == MRUMTL_BRDF_SPECULAR); + ASSERT(ithread < htrdr->nthreads); + + res = ssf_bsdf_create + (&htrdr->lifo_allocators[ithread], &ssf_specular_reflection, &bsdf); + if(res != RES_OK) goto error; + + res = ssf_fresnel_create + (&htrdr->lifo_allocators[ithread], &ssf_fresnel_constant, &fresnel); + if(res != RES_OK) goto error; + + reflectivity = mrumtl_brdf_specular_get_reflectivity(brdf); + res = ssf_fresnel_constant_setup(fresnel, reflectivity); + if(res != RES_OK) goto error; + + res = ssf_specular_reflection_setup(bsdf, fresnel); + if(res != RES_OK) goto error; + +exit: + if(fresnel) SSF(fresnel_ref_put(fresnel)); + *out_bsdf = bsdf; + return res; +error: + if(bsdf) { SSF(bsdf_ref_put(bsdf)); bsdf = NULL; } + goto exit; +} + /******************************************************************************* * Local symbol ******************************************************************************/ @@ -325,3 +397,53 @@ htrdr_materials_find_mtl return found; } +res_T +htrdr_mtl_create_bsdf + (struct htrdr* htrdr, + const struct htrdr_mtl* mtl, + const size_t ithread, + const double wavelength, + struct ssp_rng* rng, + struct ssf_bsdf** out_bsdf) +{ + struct ssf_bsdf* bsdf = NULL; + const struct mrumtl_brdf* brdf = NULL; + double r; + res_T res = RES_OK; + ASSERT(htrdr && mtl && wavelength && rng && out_bsdf); + ASSERT(ithread < htrdr->nthreads); + + r = ssp_rng_canonical(rng); + + res = mrumtl_fetch_brdf2(mtl->mrumtl, wavelength, r, &brdf); + if(res != RES_OK) { + htrdr_log_err(htrdr, + "%s: error retrieving the MruMtl BRDF for the wavelength %g.\n", + FUNC_NAME, wavelength); + res = RES_BAD_ARG; + goto error; + } + + switch(mrumtl_brdf_get_type(brdf)) { + case MRUMTL_BRDF_LAMBERTIAN: + res = create_bsdf_diffuse(htrdr, brdf, ithread, &bsdf); + break; + case MRUMTL_BRDF_SPECULAR: + res = create_bsdf_specular(htrdr, brdf, ithread, &bsdf); + break; + default: FATAL("Unreachable code.\n"); break; + } + if(res != RES_OK) { + htrdr_log_err(htrdr, "%s: could not create the BSDF -- %s.\n", + FUNC_NAME, res_to_cstr(res)); + goto error; + } + +exit: + *out_bsdf = bsdf; + return res; +error: + if(bsdf) { SSF(bsdf_ref_put(bsdf)); bsdf = NULL; } + goto exit; +} + diff --git a/src/htrdr_materials.h b/src/htrdr_materials.h @@ -19,8 +19,12 @@ #include <rsys/rsys.h> +/* Forward declarations */ struct htrdr_materials; struct mrumtl; +struct s3d_hit; +struct ssf_bsdf; +struct ssp_rng; struct htrdr_mtl { const char* name; @@ -50,5 +54,14 @@ htrdr_materials_find_mtl const char* mtl_name, struct htrdr_mtl* mtl); +extern LOCAL_SYM res_T +htrdr_mtl_create_bsdf + (struct htrdr* htrdr, + const struct htrdr_mtl* mtl, + const size_t ithread, + const double wavelength, + struct ssp_rng* rng, + struct ssf_bsdf** bsdf); + #endif /* HTRDR_MATERIALS_H */