htrdr

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

commit 0dfff9bfbe6cf8d6d8fc08187e25a20076e168de
parent 766c62934d517b974639b9db9c23c65cd5424c58
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Mon, 23 Jul 2018 16:00:30 +0200

First version of the "htrdr_compute_radiance_sw" function

Diffstat:
MREADME.md | 2++
Mcmake/CMakeLists.txt | 14+++++++++++---
Msrc/htrdr.c | 62+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/htrdr.h | 9+++++++--
Msrc/htrdr_args.c | 3+++
Msrc/htrdr_args.h | 6++++--
Msrc/htrdr_compute_radiance_sw.c | 138+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Msrc/htrdr_solve.h | 2+-
8 files changed, 167 insertions(+), 69 deletions(-)

diff --git a/README.md b/README.md @@ -12,6 +12,8 @@ on the [HTCP](https://gitlab.com/meso-star/htcp/), [HTMIE](https://gitlab.com/meso-star/htmie/), [RSys](https://gitlab.com/vaplv/rsys/), +[Star-3D](https://gitlab.com/meso-star/star-3d/), +[Star-3DAW](https://gitlab.com/meso-star/star-3daw/), [Star-SF](https://gitlab.com/meso-star/star-sf/), [Star-SP](https://gitlab.com/meso-star/stat-sp/) and [Star-VX](https://gitlab.com/meso-star/star-vx/) libraries and on the diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -25,6 +25,8 @@ option(NO_TEST "Do not build the tests" OFF) ################################################################################ find_package(RCMake 0.3 REQUIRED) find_package(RSys 0.6 REQUIRED) +find_package(Star3D 0.5 REQUIRED) +find_package(Star3DAW 0.3.1 REQUIRED) find_package(StarSF 0.6 REQUIRED) find_package(StarSP 0.8 REQUIRED) find_package(StarVX REQUIRED) @@ -38,8 +40,13 @@ include(rcmake_runtime) include_directories( ${RSys_INCLUDE_DIR} - ${SVX_INCLUDE_DIR} - ${HTCP_INCLUDE_DIR}) + ${Star3D_INCLUDE_DIR} + ${Star3DAW_INCLUDE_DIR} + ${StarSF_INCLUDE_DIR} + ${StarSP_INCLUDE_DIR} + ${StarVX_INCLUDE_DIR} + ${HTCP_INCLUDE_DIR} + ${HTMIE_INCLUDE_DIR}) ################################################################################ # Configure and define targets @@ -53,6 +60,7 @@ set(HTRDR_FILES_SRC htrdr.c htrdr_args.c htrdr_buffer.c + htrdr_compute_radiance_sw.c htrdr_main.c htrdr_rectangle.c htrdr_sky.c @@ -75,7 +83,7 @@ rcmake_prepend_path(HTRDR_FILES_INC ${HTRDR_SOURCE_DIR}) rcmake_prepend_path(HTRDR_FILES_DOC ${PROJECT_SOURCE_DIR}/../) add_executable(htrdr ${HTRDR_FILES_SRC} ${HTRDR_FILES_INC}) -target_link_libraries(htrdr HTCP HTMIE RSys StarSF StarSP StarVX) +target_link_libraries(htrdr HTCP HTMIE RSys Star3D Star3DAW StarSF StarSP StarVX) if(CMAKE_COMPILER_IS_GNUCC) target_link_libraries(htrdr m) diff --git a/src/htrdr.c b/src/htrdr.c @@ -26,6 +26,8 @@ #include <rsys/clock_time.h> #include <rsys/mem_allocator.h> +#include <star/s3d.h> +#include <star/s3daw.h> #include <star/ssf.h> #include <star/svx.h> @@ -161,6 +163,52 @@ dump_buffer(struct htrdr* htrdr) } } +static res_T +setup_geometry(struct htrdr* htrdr, const char* filename) +{ + struct s3d_scene* scn = NULL; + struct s3daw* s3daw = NULL; + res_T res = RES_OK; + ASSERT(htrdr); + + res = s3d_scene_create(htrdr->s3d, &scn); + if(res != RES_OK) { + htrdr_log_err(htrdr, "could not create the Star-3D scene.\n"); + goto error; + } + + if(filename) { + res = s3daw_create(&htrdr->logger, htrdr->allocator, NULL, NULL, htrdr->s3d, + htrdr->verbose, &s3daw); + if(res != RES_OK) { + htrdr_log_err(htrdr, "could not create the Star-3DAW device.\n"); + goto error; + } + res = s3daw_load(s3daw, filename); + if(res != RES_OK) { + htrdr_log_err(htrdr, "could not load the obj file `%s'.\n", filename); + goto error; + } + res = s3daw_attach_to_scene(s3daw, scn); + if(res != RES_OK) { + htrdr_log_err(htrdr, + "could not attach the loaded geometry to the Star-3D scene.\n"); + goto error; + } + } + + res = s3d_scene_view_create(scn, S3D_TRACE, &htrdr->s3d_scn_view); + if(res != RES_OK) { + htrdr_log_err(htrdr, "could not create the Star-3D scene view.\n"); + goto error; + } + +exit: + return res; +error: + goto exit; +} + /******************************************************************************* * Local functions ******************************************************************************/ @@ -193,6 +241,13 @@ htrdr_init goto error; } + res = s3d_device_create + (&htrdr->logger, htrdr->allocator, args->verbose, &htrdr->s3d); + if(res != RES_OK) { + htrdr_log_err(htrdr, "could not create the Star-3D device.\n"); + goto error; + } + if(!args->dump_vtk) { /* Legacy mode */ const size_t elmtsz = sizeof(double); const size_t pitch = elmtsz * args->image.definition[0]; @@ -237,7 +292,7 @@ htrdr_init res = ssf_phase_create(htrdr->allocator, &ssf_phase_hg, &htrdr->phase_hg); if(res != RES_OK) { - htrdr_log_err(htrdr, + htrdr_log_err(htrdr, "could not create the Henyey & Greenstein phase function.\n"); goto error; } @@ -250,6 +305,9 @@ htrdr_init goto error; } + res = setup_geometry(htrdr, args->filename_obj); + if(res != RES_OK) goto error; + exit: return res; error: @@ -264,6 +322,8 @@ htrdr_release(struct htrdr* htrdr) if(htrdr->bsdf) SSF(bsdf_ref_put(htrdr->bsdf)); if(htrdr->phase_hg) SSF(phase_ref_put(htrdr->phase_hg)); if(htrdr->phase_rayleigh) SSF(phase_ref_put(htrdr->phase_rayleigh)); + if(htrdr->s3d_scn_view) S3D(scene_view_ref_put(htrdr->s3d_scn_view)); + if(htrdr->s3d) S3D(device_ref_put(htrdr->s3d)); if(htrdr->svx) SVX(device_ref_put(htrdr->svx)); if(htrdr->sky) htrdr_sky_ref_put(htrdr->sky); if(htrdr->sun) htrdr_sun_ref_put(htrdr->sun); diff --git a/src/htrdr.h b/src/htrdr.h @@ -19,24 +19,29 @@ #include <rsys/logger.h> #include <rsys/ref_count.h> -/* Forward declaration */ +/* Forward declarations */ struct htrdr_args; struct htrdr_buffer; struct htrdr_sky; struct htrdr_rectangle; struct mem_allocator; +struct s3d_device; +struct s3d_scene; struct ssf_bsdf; struct ssf_phase; struct svx_device; struct htrdr { struct svx_device* svx; + struct s3d_device* s3d; + + struct s3d_scene_view* s3d_scn_view; struct htrdr_sky* sky; struct htrdr_sun* sun; /* Scattering functions */ - struct ssf_bsdf* bsdf; /* BSDF of the ground geometry */ + struct ssf_bsdf* bsdf; /* BSDF of the 3D geometry */ struct ssf_phase* phase_hg; /* Henyey & Greenstein phase function */ struct ssf_phase* phase_rayleigh; /* Rayleigh phase function */ diff --git a/src/htrdr_args.c b/src/htrdr_args.c @@ -40,6 +40,8 @@ print_help(const char* cmd) printf( " -f overwrite the OUTPUT file if it already exists.\n"); printf( +" -g FILENAME path of the OBJ geometry file.\n"); + printf( " -h display this help and exit.\n"); printf( " -I <image> define the image to compute.\n"); @@ -278,6 +280,7 @@ htrdr_args_init(struct htrdr_args* args, int argc, char** argv) case 'D': res = parse_sun_dir(args, optarg); break; case 'd': args->dump_vtk = 1; break; case 'f': args->force_overwriting = 1; break; + case 'g': args->filename_obj = optarg; break; case 'h': print_help(argv[0]); htrdr_args_release(args); diff --git a/src/htrdr_args.h b/src/htrdr_args.h @@ -19,8 +19,9 @@ #include <rsys/rsys.h> struct htrdr_args { - const char* filename_les; - const char* filename_mie; + const char* filename_les; /* Path toward the HTCP file */ + const char* filename_mie; /* Path toward the Mie properties */ + const char* filename_obj; /* Path toward the 3D geometry */ const char* output; struct { @@ -47,6 +48,7 @@ struct htrdr_args { #define HTRDR_ARGS_DEFAULT__ { \ NULL, /* LES filename */ \ NULL, /* Mie filename */ \ + NULL, /* Obj filename */ \ NULL, /* Output filename */ \ { \ {0, 0, 0}, /* plane position */ \ diff --git a/src/htrdr_compute_radiance_sw.c b/src/htrdr_compute_radiance_sw.c @@ -13,21 +13,31 @@ * 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_c.h" #include "htrdr_solve.h" #include "htrdr_sky.h" +#include "htrdr_sun.h" +#include <star/s3d.h> +#include <star/ssf.h> #include <star/ssp.h> +#include <star/svx.h> + +#include <rsys/double2.h> +#include <rsys/float2.h> +#include <rsys/float3.h> struct scattering_context { struct ssp_rng* rng; - const struct htrdr_sky* sky + const struct htrdr_sky* sky; double wavelength; double Ts; /* Sampled optical thickness */ double traversal_dst; /* Distance traversed along the ray */ }; static const struct scattering_context SCATTERING_CONTEXT_NULL = { - NULL, NULL, 0, 0, 0, 0, 0 + NULL, NULL, 0, 0, 0 }; struct transmissivity_context { @@ -57,32 +67,34 @@ scattering_hit_filter void* context) { struct scattering_context* ctx = context; - double dst; double ks_max; int pursue_traversal = 1; ASSERT(hit && ctx && !SVX_HIT_NONE(hit) && org && dir && range); (void)range; - ks_max = htrdr_sky_fetch_svx_voxel_property - (ctx->sky, HTRDR_Ks, HTRDR_SVX_MAX, ctx->wavelength, &hit->voxel); + ks_max = htrdr_sky_fetch_svx_voxel_property(ctx->sky, HTRDR_Ks, + HTRDR_SVX_MAX, HTRDR_ALL_COMPONENTS, ctx->wavelength, &hit->voxel); for(;;) { + double dst; + double T; + dst = hit->distance[1] - ctx->traversal_dst; T = dst * ks_max; /* Compute tau for the current leaf */ /* A collision occurs behind `dst' */ if(ctx->Ts > T) { ctx->Ts -= T; - ctx->traversal_dst = hit.distance[1]; + ctx->traversal_dst = hit->distance[1]; pursue_traversal = 1; break; /* A real/null collision occurs before `dst' */ - else { + } else { double pos[3]; - double proba_s; + double proba; double ks; - const float collision_dst = ctx->Ts / ks_max; + const double collision_dst = ctx->Ts / ks_max; /* Compute the traversed distance up to the challenged collision */ dst = ctx->traversal_dst + collision_dst; @@ -99,28 +111,27 @@ scattering_hit_filter (ctx->sky, HTRDR_Ks, HTRDR_ALL_COMPONENTS, ctx->wavelength, pos); /* Handle the case that ks_max is not *really* the max */ - proba_s = ks / ks_max; + proba = ks / ks_max; if(ssp_rng_canonical(ctx->rng) < proba) {/* Collide <=> real scattering */ pursue_traversal = 0; break; } else { /* Null collision */ - ctx->Ts = ssp_ran_exp(rng, 1); /* Sample a new optical thickness */ + ctx->Ts = ssp_ran_exp(ctx->rng, 1); /* Sample a new optical thickness */ } } } return pursue_traversal; } -static double -transmissivty_hit_filter +static int +transmissivity_hit_filter (const struct svx_hit* hit, const double org[3], const double dir[3], const double range[2], void* context) { - const double* vox_data = NULL; struct transmissivity_context* ctx = context; double dst; double k_max; @@ -138,12 +149,12 @@ transmissivty_hit_filter ctx->Tmin += dst * k_min; for(;;) { - Tdif = dst * (k_max-k_min); + const double Tdif = dst * (k_max-k_min); /* A collision occurs behind `dst' */ - if(ctx->Ts > ctx->Tdif) { + if(ctx->Ts > Tdif) { ctx->Ts -= Tdif; - ctx->traversal_dst = hit->range[1]; + ctx->traversal_dst = hit->distance[1]; pursue_traversal = 1; break; @@ -151,9 +162,8 @@ transmissivty_hit_filter } else { double x[3]; double k; - double dst; - double proba_kext; - double collision_dst = cts->Ts / (k_max - k_min); + double proba; + double collision_dst = ctx->Ts / (k_max - k_min); /* Compute the traversed distance up to the challenged collision */ dst = ctx->traversal_dst + collision_dst; @@ -176,7 +186,7 @@ transmissivty_hit_filter pursue_traversal = 0; break; } else { /* Null collision */ - ctx->Ts = ssp_ran_exp(rng, 1); /* Sample a new optical thickness */ + ctx->Ts = ssp_ran_exp(ctx->rng, 1); /* Sample a new optical thickness */ dst = hit->distance[1] - ctx->traversal_dst; } } @@ -197,9 +207,10 @@ transmissivity { struct s3d_hit s3d_hit; struct svx_hit svx_hit; + struct svx_tree* svx_tree; struct transmissivity_context transmissivity_ctx = TRANSMISSION_CONTEXT_NULL; - const struct s3d_hit s3d_hit_prev = hit_prev ? *hit_prev : S3D_HIT_NULL; + struct s3d_hit s3d_hit_prev = hit_prev ? *hit_prev : S3D_HIT_NULL; float ray_pos[3]; float ray_dir[3]; float ray_range[2]; @@ -210,23 +221,24 @@ transmissivity f3_set_d3(ray_pos, pos); f3_set_d3(ray_dir, dir); f2_set_d2(ray_range, range); - S3D(scene_view_trace(htrdr->s3d_scn, ray_pos, ray_dir, ray_range, + S3D(scene_view_trace_ray(htrdr->s3d_scn_view, ray_pos, ray_dir, ray_range, &s3d_hit_prev, &s3d_hit)); if(!S3D_HIT_NONE(&s3d_hit)) return 0; - transmissivity_ctx->rng = rng; - transmissivity_ctx->sky = htrdr->sky; - transmissivity_ctx->wavelength = wavelength; - transmissivity_ctx->Ts = ssp_ran_exp(rng, 1); /* Sample an optical thickness */ - transmissivity_ctx->prop = prop; + transmissivity_ctx.rng = rng; + transmissivity_ctx.sky = htrdr->sky; + transmissivity_ctx.wavelength = wavelength; + transmissivity_ctx.Ts = ssp_ran_exp(rng, 1); /* Sample an optical thickness */ + transmissivity_ctx.prop = prop; /* Compute the transmissivity */ - SVX(octree_trace_ray(htrdr->clouds, pos, dir, range, NULL, + svx_tree = htrdr_sky_get_svx_tree(htrdr->sky); + SVX(octree_trace_ray(svx_tree, pos, dir, range, NULL, transmissivity_hit_filter, &transmissivity_ctx, &svx_hit)); - if(SVX_HIT_NONE(svx_hit)) { - return transmissivity_ctx.Tmin ? exp(-ctx.Tmin) : 1.0; + if(SVX_HIT_NONE(&svx_hit)) { + return transmissivity_ctx.Tmin ? exp(-transmissivity_ctx.Tmin) : 1.0; } else { return 0; } @@ -247,6 +259,7 @@ htrdr_compute_radiance_sw struct s3d_hit s3d_hit = S3D_HIT_NULL; struct svx_hit svx_hit = SVX_HIT_NULL; struct s3d_hit s3d_hit_prev = S3D_HIT_NULL; + struct svx_tree* svx_tree = NULL; double pos[3]; double dir[3]; @@ -256,7 +269,7 @@ htrdr_compute_radiance_sw double R; double r; /* Random number */ - double wi[3]; /* -dir */ + double wo[3]; /* -dir */ double pdf; double sun_solid_angle; double Tr; /* Overall transmissivity */ @@ -271,28 +284,30 @@ htrdr_compute_radiance_sw float ray_range[2]; ASSERT(wavelength >= SW_WAVELENGTH_MIN && wavelength <= SW_WAVELENGTH_MAX); - ASSERT(htrdr && rng && pos && dir); + ASSERT(htrdr && rng && pos_in && dir_in); /* Fetch sun properties */ sun_solid_angle = htrdr_sun_get_solid_angle(htrdr->sun); L_sun = htrdr_sun_get_radiance(htrdr->sun, wavelength); + svx_tree = htrdr_sky_get_svx_tree(htrdr->sky); + d3_set(pos, pos_in); d3_set(dir, dir_in); /* Add the directly contribution of the sun */ - if(htrdr_sun_is_dir_in_solar_cone(sun, dir)) { + if(htrdr_sun_is_dir_in_solar_cone(htrdr->sun, dir)) { f3_set_d3(ray_pos, pos); f3_set_d3(ray_dir, dir); f2(ray_range, 0, FLT_MAX); - S3D(scene_view_trace - (htrdr->s3d_scn, ray_pos, ray_dir, ray_range, NULL, &s3d_hit)); + S3D(scene_view_trace_ray + (htrdr->s3d_scn_view, ray_pos, ray_dir, ray_range, NULL, &s3d_hit)); /* Add the direct contribution of the sun */ - if(!S3D_HIT_NONE(&s3d_hit)) { - d3(range, 0, FLT_MAX); + if(S3D_HIT_NONE(&s3d_hit)) { + d2(range, 0, FLT_MAX); Tr = transmissivity - (htrdr, rng, HTRDR_Kext, wavelength , pos, dir, range); + (htrdr, rng, HTRDR_Kext, wavelength , pos, dir, range, NULL); w = L_sun * Tr; } } @@ -307,20 +322,20 @@ htrdr_compute_radiance_sw f2(ray_range, 0, FLT_MAX); /* Find the first intersection with a surface */ - S3D(scene_view_trace(htrdr->s3d_scn, ray_pos, ray_dir, ray_range, + S3D(scene_view_trace_ray(htrdr->s3d_scn_view, ray_pos, ray_dir, ray_range, &s3d_hit_prev, &s3d_hit)); /* Sample an optical thicknes */ - scattering_ctx->Ts = ssp_ran_exp(rng, 1); + scattering_ctx.Ts = ssp_ran_exp(rng, 1); /* Setup the remaining scattering context fields */ - scattering_ctx->rng = rng; - scattering_ctx->sky = htrdr->sky; - scattering_ctx->wavelength = wavelength; + scattering_ctx.rng = rng; + scattering_ctx.sky = htrdr->sky; + scattering_ctx.wavelength = wavelength; /* Define if a scattering event occurs */ d2(range, 0, s3d_hit.distance); - SVX(octree_trace_ray(htrdr->clouds, pos, dir, range, NULL, + SVX(octree_trace_ray(svx_tree, pos, dir, range, NULL, scattering_hit_filter, &scattering_ctx, &svx_hit)); /* No scattering and no surface reflection. Stop the radiative random walk */ @@ -330,37 +345,38 @@ htrdr_compute_radiance_sw } /* Negative the incoming dir to match the convention of the SSF library */ - d3_minus(wi, dir); + d3_minus(wo, dir); /* Compute the new position */ - pos_next[0] = pos[0] + dir[0]*scattering_ctx->traversal_dst; - pos_next[1] = pos[1] + dir[1]*scattering_ctx->traversal_dst; - pos_next[2] = pos[2] + dir[2]*scattering_ctx->traversal_dst; + pos_next[0] = pos[0] + dir[0]*scattering_ctx.traversal_dst; + pos_next[1] = pos[1] + dir[1]*scattering_ctx.traversal_dst; + pos_next[2] = pos[2] + dir[2]*scattering_ctx.traversal_dst; /* Define the absorption transmissivity from the current position to the * next position */ - d2(range, 0, scattering_ctx->traversal_dst); + d2(range, 0, scattering_ctx.traversal_dst); Tr_abs = transmissivity - (htrdr, rng, HTRDR_Ka, wavelength, pos, dir, range); + (htrdr, rng, HTRDR_Ka, wavelength, pos, dir, range, &s3d_hit_prev); if(Tr_abs <= 0) break; /* Define the transmissivity from the new position to the sun */ d2(range, 0, FLT_MAX); - htrdr_sun_sample_dir(htrdr->sun, rng, pos_next, sun_dir); + htrdr_sun_sample_direction(htrdr->sun, rng, sun_dir); Tr = transmissivity - (htrdr, rng, HTRDR_Kext, wavelength, pos_next, sun_dir, range); + (htrdr, rng, HTRDR_Kext, wavelength, pos_next, sun_dir, range, &s3d_hit); /* Scattering at a surface */ if(SVX_HIT_NONE(&svx_hit)) { double reflectivity; - double R; + double N[3]; int type; + d3_normalize(N, d3_set_f3(N, s3d_hit.normal)); reflectivity = ssf_bsdf_sample - (htrdr->bsdf, rng, wi, s3d_hit.normal, dir_next, &type, &pdf); + (htrdr->bsdf, rng, wo, N, dir_next, &type, &pdf); if(ssp_rng_canonical(rng) > reflectivity) break; /* Russian roulette */ - R = ssf_bsdf_eval(htrdr->bsdf, wi, s3d_hit.normal, sun_dir); + R = ssf_bsdf_eval(htrdr->bsdf, wo, N, sun_dir); /* Scattering in the medium */ } else { @@ -376,14 +392,14 @@ htrdr_compute_radiance_sw ks = ks_particle + ks_gas; r = ssp_rng_canonical(rng); - if(r < ks_gaz / ks) { /* Gas scattering */ - FATAL("Gas scattering is not supported, yet.\n"); + if(r < ks_gas / ks) { /* Gas scattering */ + phase = htrdr->phase_rayleigh; } else { /* Cloud scattering */ phase = htrdr->phase_hg; } - ssf_phase_sample(phase, rng, wi, dir_next, &pdf); - R = ssf_phase_eval(phase, wi, sun_dir); + ssf_phase_sample(phase, rng, wo, dir_next, NULL); + R = ssf_phase_eval(phase, wo, sun_dir); } /* Update the MC weight */ @@ -393,6 +409,8 @@ htrdr_compute_radiance_sw /* Setup the next random walk state */ d3_set(pos, pos_next); d3_set(dir, dir_next); + + s3d_hit_prev = s3d_hit; } return w; } diff --git a/src/htrdr_solve.h b/src/htrdr_solve.h @@ -26,7 +26,7 @@ extern LOCAL_SYM res_T htrdr_solve_transmission_buffer (struct htrdr* htrdr); -extern LOCAL_SYM res_T +extern LOCAL_SYM double htrdr_compute_radiance_sw (struct htrdr* htrdr, struct ssp_rng* rng,