htrdr

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

commit 19160f8ba423fcc764a8dad777e3f65a352bbce1
parent 5201cd3cf44c3a2d459d41ab074b7c0a71735405
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri,  6 Mar 2020 16:07:26 +0100

Add support of the ground materials

Diffstat:
Mcmake/CMakeLists.txt | 10+++++-----
Adoc/ground | 5+++++
Msrc/htrdr.c | 11+++++++++--
Msrc/htrdr.h | 1+
Msrc/htrdr_args.c | 60++++++++++--------------------------------------------------
Msrc/htrdr_args.h.in | 7+++----
Msrc/htrdr_compute_radiance_sw.c | 12++++++++----
Msrc/htrdr_ground.c | 450++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/htrdr_ground.h | 31+++++++++++++++++++------------
Asrc/htrdr_interface.c | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/htrdr_interface.h | 45+++++++++++++++++++++++++++++++++++++++++++++
Msrc/htrdr_mtl.c | 2+-
Msrc/htrdr_mtl.h | 2+-
13 files changed, 609 insertions(+), 196 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -24,12 +24,12 @@ option(NO_TEST "Do not build the tests" OFF) ################################################################################ # Check dependencies ################################################################################ +find_package(AW 2.0 REQUIRED) find_package(HTSky REQUIRED) find_package(MruMtl REQUIRED) find_package(RCMake 0.3 REQUIRED) find_package(RSys 0.7 REQUIRED) find_package(Star3D 0.6 REQUIRED) -find_package(Star3DAW 0.3.1 REQUIRED) find_package(StarSF 0.6 REQUIRED) find_package(StarSP 0.8 REQUIRED) find_package(StarVX REQUIRED) @@ -43,10 +43,10 @@ include(rcmake_runtime) set(CMAKE_C_COMPILER ${MPI_C_COMPILER}) include_directories( + ${AW_INCLUDE_DIR} ${MruMtl_INCLUDE_DIR} ${RSys_INCLUDE_DIR} ${Star3D_INCLUDE_DIR} - ${Star3DAW_INCLUDE_DIR} ${StarSF_INCLUDE_DIR} ${StarSP_INCLUDE_DIR} ${StarVX_INCLUDE_DIR} @@ -67,8 +67,6 @@ set(HTRDR_ARGS_DEFAULT_CAMERA_POS "0,0,0") set(HTRDR_ARGS_DEFAULT_CAMERA_TGT "0,1,0") set(HTRDR_ARGS_DEFAULT_CAMERA_UP "0,0,1") set(HTRDR_ARGS_DEFAULT_CAMERA_FOV "70") -set(HTRDR_ARGS_DEFAULT_GROUND_BSDF "HTRDR_BSDF_DIFFUSE") -set(HTRDR_ARGS_DEFAULT_GROUND_REFLECTIVITY "0.5") set(HTRDR_ARGS_DEFAULT_IMG_WIDTH "320") set(HTRDR_ARGS_DEFAULT_IMG_HEIGHT "240") set(HTRDR_ARGS_DEFAULT_IMG_SPP "1") @@ -97,6 +95,7 @@ set(HTRDR_FILES_SRC htrdr_draw_radiance_sw.c htrdr_grid.c htrdr_ground.c + htrdr_interface.c htrdr_main.c htrdr_mtl.c htrdr_rectangle.c @@ -109,6 +108,7 @@ set(HTRDR_FILES_INC htrdr_camera.h htrdr_grid.h htrdr_ground.h + htrdr_interface.h htrdr_mtl.h htrdr_rectangle.h htrdr_slab.h @@ -126,7 +126,7 @@ rcmake_prepend_path(HTRDR_FILES_INC2 ${CMAKE_CURRENT_BINARY_DIR}) rcmake_prepend_path(HTRDR_FILES_DOC ${PROJECT_SOURCE_DIR}/../) add_executable(htrdr ${HTRDR_FILES_SRC} ${HTRDR_FILES_INC} ${HTRDR_FILES_INC2}) -target_link_libraries(htrdr HTSky MruMtl RSys Star3D Star3DAW StarSF StarSP) +target_link_libraries(htrdr AW HTSky MruMtl RSys Star3D StarSF StarSP) if(CMAKE_COMPILER_IS_GNUCC) target_link_libraries(htrdr m) diff --git a/doc/ground b/doc/ground @@ -0,0 +1,5 @@ +<materials-list> ::= <material> + [ <material> ... ] +<material> ::= <material-name> <mrumtl-path> +<material-name> ::= STRING +<mrumtl-path> ::= PATH diff --git a/src/htrdr.c b/src/htrdr.c @@ -22,6 +22,7 @@ #include "htrdr_buffer.h" #include "htrdr_camera.h" #include "htrdr_ground.h" +#include "htrdr_mtl.h" #include "htrdr_sun.h" #include "htrdr_solve.h" @@ -428,8 +429,14 @@ htrdr_init goto error; } - res = htrdr_ground_create(htrdr, args->filename_obj, args->ground_bsdf_type, - args->ground_reflectivity, args->repeat_ground, &htrdr->ground); + /* Materials are necessary only if a ground geometry is defined */ + if(args->filename_obj) { + res = htrdr_mtl_create(htrdr, args->filename_mtl, &htrdr->mtl); + if(res != RES_OK) goto error; + } + + res = htrdr_ground_create(htrdr, args->filename_obj, args->repeat_ground, + &htrdr->ground); if(res != RES_OK) goto error; proj_ratio = diff --git a/src/htrdr.h b/src/htrdr.h @@ -46,6 +46,7 @@ struct htrdr { struct s3d_device* s3d; struct htrdr_ground* ground; + struct htrdr_mtl* mtl; struct htrdr_sun* sun; struct htrdr_camera* cam; diff --git a/src/htrdr_args.c b/src/htrdr_args.c @@ -28,18 +28,6 @@ /******************************************************************************* * Helper functions ******************************************************************************/ -static const char* -bsdf_type_to_string(const enum htrdr_bsdf_type type) -{ - const char* str = "<none>"; - switch(type) { - case HTRDR_BSDF_DIFFUSE: str = "diffuse"; break; - case HTRDR_BSDF_SPECULAR: str = "specular"; break; - default: FATAL("Unreachable code.\n"); break; - } - return str; -} - static void print_help(const char* cmd) { @@ -51,10 +39,6 @@ print_help(const char* cmd) printf( " -a ATMOSPHERE gas optical properties of the atmosphere.\n"); printf( -" -b <diffuse|specular>\n" -" BSDF of the ground. Default value is %s.\n", - bsdf_type_to_string(HTRDR_ARGS_DEFAULT.ground_bsdf_type)); - printf( " -c CLOUDS properties of the clouds.\n"); printf( " -C <camera> define the rendering point of view.\n"); @@ -67,9 +51,6 @@ print_help(const char* cmd) printf( " -d dump octrees data to OUTPUT and exit.\n"); printf( -" -e REFLECT ground reflectivity in [0, 1]. Default value is %g.\n", - HTRDR_ARGS_DEFAULT.ground_reflectivity); - printf( " -f overwrite the OUTPUT file if it already exists.\n"); printf( " -g GROUND ground geometry.\n"); @@ -82,6 +63,8 @@ print_help(const char* cmd) printf( " -r infinitely repeat the clouds along the X and Y axis.\n"); printf( +" -M MATERIALS file listing the scene ground materials.\n"); + printf( " -m MIE file of Mie's data.\n"); printf( " -O CACHE name of the cache file used to store/restore the sky data.\n"); @@ -371,26 +354,6 @@ error: goto exit; } -static res_T -parse_bsdf_type(struct htrdr_args* args, const char* str) -{ - res_T res = RES_OK; - if(!strcmp(str, "diffuse")) { - args->ground_bsdf_type = HTRDR_BSDF_DIFFUSE; - } else if(!strcmp(str, "specular")) { - args->ground_bsdf_type = HTRDR_BSDF_SPECULAR; - } else { - fprintf(stderr, "Invalid BRDF type `%s'.\n", str); - res = RES_BAD_ARG; - goto error; - } - -exit: - return res; -error: - goto exit; -} - /******************************************************************************* * Local functions ******************************************************************************/ @@ -415,25 +378,16 @@ htrdr_args_init(struct htrdr_args* args, int argc, char** argv) } } - while((opt = getopt(argc, argv, "a:b:C:c:D:de:fg:hi:m:O:o:RrT:t:V:v")) != -1) { + while((opt = getopt(argc, argv, "a:C:c:D:dfg:hi:M:m:O:o:RrT:t:V:v")) != -1) { switch(opt) { case 'a': args->filename_gas = optarg; break; - case 'b': - res = parse_bsdf_type(args, optarg); - break; - case 'C': + case 'C': res = parse_multiple_parameters (args, optarg, parse_camera_parameter); break; case 'c': args->filename_les = optarg; break; case 'D': res = parse_sun_dir(args, optarg); break; case 'd': args->dump_vtk = 1; break; - case 'e': - res = cstr_to_double(optarg, &args->ground_reflectivity); - if(args->ground_reflectivity < 0 || args->ground_reflectivity > 1) { - res = RES_BAD_ARG; - } - break; case 'f': args->force_overwriting = 1; break; case 'g': args->filename_obj = optarg; break; case 'h': @@ -476,6 +430,12 @@ htrdr_args_init(struct htrdr_args* args, int argc, char** argv) res = RES_BAD_ARG; goto error; } + if(args->filename_obj && !args->filename_mtl) { + fprintf(stderr, + "Missing the path of the file listing the ground materials -- opton '-M'\n"); + res = RES_BAD_ARG; + goto error; + } if(args->filename_les && !args->filename_mie) { fprintf(stderr, "Missing the path toward the file of the Mie's data -- option '-m'\n"); diff --git a/src/htrdr_args.h.in b/src/htrdr_args.h.in @@ -21,11 +21,13 @@ #include <limits.h> #include <rsys/rsys.h> + struct htrdr_args { const char* filename_gas; /* Path of the gas file */ const char* filename_les; /* Path of the HTCP file */ const char* filename_mie; /* Path of the Mie properties */ const char* filename_obj; /* Path of the 3D geometry */ + const char* filename_mtl; /* Path of the materials */ const char* cache; const char* output; @@ -51,8 +53,6 @@ struct htrdr_args { double sun_azimuth; /* In degrees */ double sun_elevation; /* In degrees */ double optical_thickness; /* Threshold used during octree building */ - enum htrdr_bsdf_type ground_bsdf_type; - double ground_reflectivity; /* Reflectivity of the ground */ unsigned grid_max_definition[3]; /* Maximum definition of the grid */ unsigned nthreads; /* Hint on the number of threads to use */ @@ -69,6 +69,7 @@ struct htrdr_args { NULL, /* LES filename */ \ NULL, /* Mie filename */ \ NULL, /* Obj filename */ \ + NULL, /* Mtl filename */ \ NULL, /* Cache filename */ \ NULL, /* Output filename */ \ { \ @@ -88,8 +89,6 @@ struct htrdr_args { 0, /* Sun azimuth */ \ 90, /* Sun elevation */ \ @HTRDR_ARGS_DEFAULT_OPTICAL_THICKNESS_THRESHOLD@, /* Optical thickness */ \ - @HTRDR_ARGS_DEFAULT_GROUND_BSDF@, \ - @HTRDR_ARGS_DEFAULT_GROUND_REFLECTIVITY@, /* Ground reflectivity */ \ {UINT_MAX, UINT_MAX, UINT_MAX}, /* Maximum definition of the grid */ \ (unsigned)~0, /* #threads */ \ 0, /* Force overwriting */ \ diff --git a/src/htrdr_compute_radiance_sw.c b/src/htrdr_compute_radiance_sw.c @@ -16,6 +16,7 @@ #include "htrdr.h" #include "htrdr_c.h" +#include "htrdr_interface.h" #include "htrdr_ground.h" #include "htrdr_solve.h" #include "htrdr_sun.h" @@ -255,7 +256,6 @@ htrdr_compute_radiance_sw struct svx_hit svx_hit = SVX_HIT_NULL; struct ssf_phase* phase_hg = NULL; struct ssf_phase* phase_rayleigh = NULL; - struct ssf_bsdf* bsdf = NULL; double pos[3]; double dir[3]; @@ -290,9 +290,6 @@ htrdr_compute_radiance_sw (htrdr->sky, iband, iquad); SSF(phase_hg_setup(phase_hg, g)); - /* Fetch the ground BSDF */ - bsdf = htrdr_ground_get_bsdf(htrdr->ground); - /* Fetch sun properties. Arbitrarily use the wavelength at the center of the * band to retrieve the sun radiance of the current band. Note that the sun * spectral data are defined by bands that, actually are the same of the SW @@ -389,9 +386,16 @@ htrdr_compute_radiance_sw /* Scattering at a surface */ if(SVX_HIT_NONE(&svx_hit)) { + struct htrdr_interface interf = HTRDR_INTERFACE_NULL; + struct ssf_bsdf* bsdf = NULL; double N[3]; int type; + /* Fetch the hit interface and build its BSDF */ + htrdr_ground_get_interface(htrdr->ground, &s3d_hit, &interf); + HTRDR(interface_create_bsdf + (htrdr, &interf, ithread, wlen, pos_next, dir, &s3d_hit, &bsdf)); + d3_normalize(N, d3_set_f3(N, s3d_hit.normal)); if(d3_dot(N, wo) < 0) d3_minus(N, N); diff --git a/src/htrdr_ground.c b/src/htrdr_ground.c @@ -1,5 +1,5 @@ -/* Copyright (C) 2018, 2019, 2020 |Meso|Star> (contact@meso-star.com) - * Copyright (C) 2018, 2019 CNRS, Université Paul Sabatier +/* 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 @@ -15,19 +15,43 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "htrdr.h" +#include "htrdr_interface.h" #include "htrdr_ground.h" +#include "htrdr_mtl.h" #include "htrdr_slab.h" +#include <aw.h> #include <rsys/clock_time.h> #include <rsys/cstr.h> +#include <rsys/dynamic_array_double.h> +#include <rsys/dynamic_array_size_t.h> #include <rsys/double2.h> #include <rsys/double3.h> #include <rsys/float2.h> #include <rsys/float3.h> +#include <rsys/hash_table.h> #include <star/s3d.h> -#include <star/s3daw.h> -#include <star/ssf.h> +#include <star/smtl.h> + +/* Define the hash table that maps an Obj vertex id to its position into the + * vertex buffer */ +#define HTABLE_NAME vertex +#define HTABLE_KEY size_t /* Obj vertex id */ +#define HTABLE_DATA size_t +#include <rsys/hash_table.h> + +/* Define the hash table that maps the Star-3D shape id to its interface */ +#define HTABLE_NAME interface +#define HTABLE_KEY unsigned /* Star-3D shape id */ +#define HTABLE_DATA struct htrdr_interface +#include <rsys/hash_table.h> + +struct mesh { + const struct darray_double* positions; + const struct darray_size_t* indices; +}; +static const struct mesh MESH_NULL; struct ray_context { float range[2]; @@ -50,9 +74,10 @@ struct htrdr_ground { struct s3d_scene_view* view; float lower[3]; /* Ground lower bound */ float upper[3]; /* Ground upper bound */ - struct ssf_bsdf* bsdf; int repeat; /* Make the ground infinite in X and Y */ + struct htable_interface interfaces; /* Map a Star3D shape to its interface */ + struct htrdr* htrdr; ref_T ref; }; @@ -131,146 +156,341 @@ trace_ground } static res_T -setup_ground(struct htrdr_ground* ground, const char* obj_filename) +parse_shape_interface + (struct htrdr* htrdr, + const char* name, + struct htrdr_interface* interf) { - struct s3d_scene* scn = NULL; - struct s3daw* s3daw = NULL; - size_t nshapes; - size_t ishape; + struct str str; + char* mtl_name_front = NULL; + char* mtl_name_back = NULL; + char* tk_ctx = NULL; res_T res = RES_OK; - ASSERT(ground); + ASSERT(htrdr && name && interf); - if(!obj_filename) { - /* No geometry! Discard the creation of the scene view */ - htrdr_log_warn(ground->htrdr, - "%s: the scene does not have ground geometry.\n", - FUNC_NAME); - goto exit; - } + str_init(htrdr->allocator, &str); - res = s3daw_create(&ground->htrdr->logger, ground->htrdr->allocator, NULL, - NULL, ground->htrdr->s3d, ground->htrdr->verbose, &s3daw); + /* Locally copy the string to parse */ + res = str_set(&str, name); if(res != RES_OK) { - htrdr_log_err(ground->htrdr, - "%s: could not create the Star-3DAW device -- %s.\n", - FUNC_NAME, res_to_cstr(res)); + htrdr_log_err(htrdr, + "Could not locally copy the shape material string `%s' -- %s.\n", + name, res_to_cstr(res)); goto error; } - res = s3daw_load(s3daw, obj_filename); - if(res != RES_OK) { - htrdr_log_err(ground->htrdr, - "%s: could not load the obj file `%s' -- %s.\n", - FUNC_NAME, obj_filename, res_to_cstr(res)); + /* Parse the name of the front/back faces */ + mtl_name_front = strtok_r(str_get(&str), ":", &tk_ctx); + ASSERT(mtl_name_front); /* This can't be NULL */ + mtl_name_back = strtok_r(NULL, ":", &tk_ctx); + if(!mtl_name_back) { + htrdr_log_err(htrdr, + "The material name of the shape back faces are missing `%s'.\n", name); + res = RES_BAD_ARG; goto error; } - res = s3d_scene_create(ground->htrdr->s3d, &scn); - if(res != RES_OK) { - htrdr_log_err(ground->htrdr, - "%s: could not create the Star-3D scene of the ground -- %s.\n", - FUNC_NAME, res_to_cstr(res)); + /* Fetch the front/back materials */ + interf->mtl_front = htrdr_mtl_get(htrdr->mtl, mtl_name_front); + interf->mtl_back = htrdr_mtl_get(htrdr->mtl, mtl_name_back); + if(!interf->mtl_front && !interf->mtl_back) { + htrdr_log_err(htrdr, + "Invalid interface `%s:%s'. " + "The front and the back materials are both uknown.\n", + mtl_name_front, mtl_name_back); + res = RES_BAD_ARG; goto error; } +exit: + str_release(&str); + return res; +error: + interf->mtl_front = interf->mtl_back = NULL; + goto exit; +} - S3DAW(get_shapes_count(s3daw, &nshapes)); - FOR_EACH(ishape, 0, nshapes) { - struct s3d_shape* shape; - S3DAW(get_shape(s3daw, ishape, &shape)); - res = s3d_mesh_set_hit_filter_function(shape, ground_filter, NULL); - if(res != RES_OK) { - htrdr_log_err(ground->htrdr, - "%s: could not setup the hit filter function of the ground geometry " - "-- %s.\n", FUNC_NAME, res_to_cstr(res)); +static res_T +setup_mesh + (struct htrdr* htrdr, + const char* filename, + struct aw_obj* obj, + struct aw_obj_named_group* mtl, + struct darray_double* positions, + struct darray_size_t* indices, + struct htable_vertex* vertices) /* Scratch data structure */ +{ + size_t iface; + res_T res = RES_OK; + ASSERT(htrdr && filename && obj && mtl && positions && indices && vertices); + + darray_double_clear(positions); + darray_size_t_clear(indices); + htable_vertex_clear(vertices); + + FOR_EACH(iface, mtl->face_id, mtl->faces_count) { + struct aw_obj_face face; + size_t ivertex; + + AW(obj_get_face(obj, iface, &face)); + if(face.vertices_count != 3) { + htrdr_log_err(htrdr, + "The obj `%s' has non-triangulated polygons " + "while currently only triangular meshes are supported.\n", + filename); + res = RES_BAD_ARG; goto error; } - res = s3d_scene_attach_shape(scn, shape); - if(res != RES_OK) { - htrdr_log_err(ground->htrdr, - "%s: could not attach the ground geometry to its Star-3D scene -- %s.\n", - FUNC_NAME, res_to_cstr(res)); - goto error; + + FOR_EACH(ivertex, 0, face.vertices_count) { + struct aw_obj_vertex vertex; + size_t id; + size_t* pid; + + AW(obj_get_vertex(obj, face.vertex_id + ivertex, &vertex)); + pid = htable_vertex_find(vertices, &vertex.position_id); + if(pid) { + id = *pid; + } else { + struct aw_obj_vertex_data vdata; + + id = darray_double_size_get(positions) / 3; + + res = darray_double_resize(positions, id*3 + 3); + if(res != RES_OK) { + htrdr_log_err(htrdr, + "Could not locally copy the vertex position -- %s.\n", + res_to_cstr(res)); + goto error; + } + + AW(obj_get_vertex_data(obj, &vertex, &vdata)); + darray_double_data_get(positions)[id*3+0] = vdata.position[0]; + darray_double_data_get(positions)[id*3+1] = vdata.position[1]; + darray_double_data_get(positions)[id*3+2] = vdata.position[2]; + + res = htable_vertex_set(vertices, &vertex.position_id, &id); + if(res != RES_OK) { + htrdr_log_err(htrdr, + "Could not register the vertex position -- %s.\n", + res_to_cstr(res)); + goto error; + } + } + + res = darray_size_t_push_back(indices, &id); + if(res != RES_OK) { + htrdr_log_err(htrdr, + "Could not locally copy the face index -- %s\n", + res_to_cstr(res)); + goto error; + } } } +exit: + return res; +error: + darray_double_clear(positions); + darray_size_t_clear(indices); + htable_vertex_clear(vertices); + goto exit; +} + +static void +get_position(const unsigned ivert, float position[3], void* ctx) +{ + const struct mesh* mesh = ctx; + const double* pos = NULL; + ASSERT(mesh); + ASSERT(ivert < darray_double_size_get(mesh->positions) / 3); + pos = darray_double_cdata_get(mesh->positions) + ivert*3; + position[0] = (float)pos[0]; + position[1] = (float)pos[1]; + position[2] = (float)pos[2]; +} + +static void +get_indices(const unsigned itri, unsigned indices[3], void* ctx) +{ + const struct mesh* mesh = ctx; + const size_t* ids = NULL; + ASSERT(mesh); + ASSERT(itri < darray_size_t_size_get(mesh->indices) / 3); + ids = darray_size_t_cdata_get(mesh->indices) + itri*3; + indices[0] = (unsigned)ids[0]; + indices[1] = (unsigned)ids[1]; + indices[2] = (unsigned)ids[2]; +} + +static res_T +create_s3d_shape + (struct htrdr* htrdr, + const struct darray_double* positions, + const struct darray_size_t* indices, + struct s3d_shape** out_shape) +{ + struct s3d_shape* shape = NULL; + struct s3d_vertex_data vdata = S3D_VERTEX_DATA_NULL; + struct mesh mesh = MESH_NULL; + res_T res = RES_OK; + ASSERT(htrdr && positions && indices && out_shape); + ASSERT(darray_double_size_get(positions) != 0); + ASSERT(darray_size_t_size_get(indices) != 0); + ASSERT(darray_double_size_get(positions)%3 == 0); + ASSERT(darray_size_t_size_get(indices)%3 == 0); + + mesh.positions = positions; + mesh.indices = indices; - res = s3d_scene_view_create(scn, S3D_TRACE, &ground->view); + res = s3d_shape_create_mesh(htrdr->s3d, &shape); if(res != RES_OK) { - htrdr_log_err(ground->htrdr, - "%s: could not create the Star-3D scene view of the ground geometry " - "-- %s.\n", FUNC_NAME, res_to_cstr(res)); + htrdr_log_err(htrdr, "Error creating a Star-3D shape -- %s.\n", + res_to_cstr(res)); goto error; } - res = s3d_scene_view_get_aabb(ground->view, ground->lower, ground->upper); + vdata.usage = S3D_POSITION; + vdata.type = S3D_FLOAT3; + vdata.get = get_position; + + res = s3d_mesh_setup_indexed_vertices + (shape, (unsigned int)(darray_size_t_size_get(indices)/3), get_indices, + (unsigned int)(darray_double_size_get(positions)/3), &vdata, 1, &mesh); + if(res != RES_OK){ + htrdr_log_err(htrdr, "Could not setup the Star-3D shape -- %s.\n", + res_to_cstr(res)); + goto error; + } + + res = s3d_mesh_set_hit_filter_function(shape, ground_filter, NULL); if(res != RES_OK) { - htrdr_log_err(ground->htrdr, - "%s: could not get the ground bounding box -- %s.\n", - FUNC_NAME, res_to_cstr(res)); + htrdr_log_err(htrdr, + "Could not setup the Star-3D hit filter function of the ground geometry " + "-- %s.\n", res_to_cstr(res)); goto error; } exit: - if(s3daw) S3DAW(ref_put(s3daw)); - if(scn) S3D(scene_ref_put(scn)); + *out_shape = shape; return res; error: + if(shape) { + S3D(shape_ref_put(shape)); + shape = NULL; + } goto exit; } static res_T -setup_bsdf_diffuse(struct htrdr_ground* ground, const double reflectivity) +setup_ground(struct htrdr_ground* ground, const char* obj_filename) { + struct aw_obj_desc desc; + struct htable_vertex vertices; + struct darray_double positions; + struct darray_size_t indices; + struct aw_obj* obj = NULL; + struct s3d_shape* shape = NULL; + struct s3d_scene* scene = NULL; + size_t iusemtl; + res_T res = RES_OK; - ASSERT(ground); + ASSERT(obj_filename); - res = ssf_bsdf_create - (ground->htrdr->allocator, &ssf_lambertian_reflection, &ground->bsdf); - if(res != RES_OK) goto error; + htable_vertex_init(ground->htrdr->allocator, &vertices); + darray_double_init(ground->htrdr->allocator, &positions); + darray_size_t_init(ground->htrdr->allocator, &indices); + + res = aw_obj_create(&ground->htrdr->logger, ground->htrdr->allocator, + ground->htrdr->verbose, &obj); + if(res != RES_OK) { + htrdr_log_err(ground->htrdr, "Could not create the obj loader -- %s.\n", + res_to_cstr(res)); + goto error; + } + + res = s3d_scene_create(ground->htrdr->s3d, &scene); + if(res != RES_OK) { + htrdr_log_err(ground->htrdr, "Could not create the Star-3D scene -- %s.\n", + res_to_cstr(res)); + goto error; + } - res = ssf_lambertian_reflection_setup(ground->bsdf, reflectivity); + /* Load the geometry data */ + res = aw_obj_load(obj, obj_filename); if(res != RES_OK) goto error; -exit: - return res; -error: - htrdr_log_err(ground->htrdr, - "Could not setup the ground diffuse BSDF with a reflectivity of %g -- %s.\n", - reflectivity, res_to_cstr(res)); - if(ground->bsdf) { - SSF(bsdf_ref_put(ground->bsdf)); - ground->bsdf = NULL; + /* Fetch the descriptor of the loaded geometry */ + AW(obj_get_desc(obj, &desc)); + + if(desc.usemtls_count == 0) { + htrdr_log_err(ground->htrdr, "The obj `%s' has no material.\n", obj_filename); + res = RES_BAD_ARG; + goto error; } - goto exit; -} -static res_T -setup_bsdf_specular(struct htrdr_ground* ground, const double reflectivity) -{ - struct ssf_fresnel* fresnel = NULL; - res_T res = RES_OK; - ASSERT(ground); + /* Setup the geometry */ + FOR_EACH(iusemtl, 0, desc.usemtls_count) { + struct aw_obj_named_group mtl; + struct htrdr_interface interf; + unsigned ishape; - res = ssf_bsdf_create - (ground->htrdr->allocator, &ssf_specular_reflection, &ground->bsdf); - if(res != RES_OK) goto error; - res = ssf_fresnel_create - (ground->htrdr->allocator, &ssf_fresnel_constant, &fresnel); - if(res != RES_OK) goto error; - res = ssf_fresnel_constant_setup(fresnel, reflectivity); - if(res != RES_OK) goto error; - res = ssf_specular_reflection_setup(ground->bsdf, fresnel); - if(res != RES_OK) goto error; + AW(obj_get_mtl(obj, iusemtl , &mtl)); + + res = parse_shape_interface(ground->htrdr, mtl.name, &interf); + if(res != RES_OK) goto error; + + res = setup_mesh + (ground->htrdr, obj_filename, obj, &mtl, &positions, &indices, &vertices); + if(res != RES_OK) goto error; + + res = create_s3d_shape(ground->htrdr, &positions, &indices, &shape); + if(res != RES_OK) goto error; + + S3D(shape_get_id(shape, &ishape)); + res = htable_interface_set(&ground->interfaces, &ishape, &interf); + if(res != RES_OK) { + htrdr_log_err(ground->htrdr, + "Could not map the Star-3D shape to its Star-Materials -- %s.\n", + res_to_cstr(res)); + goto error; + } + + res = s3d_scene_attach_shape(scene, shape); + if(res != RES_OK) { + htrdr_log_err(ground->htrdr, + "Could not attach a Star-3D shape to the Star-3D scene -- %s.\n", + res_to_cstr(res)); + goto error; + } + + S3D(shape_ref_put(shape)); + shape = NULL; + } + + res = s3d_scene_view_create(scene, S3D_GET_PRIMITIVE|S3D_TRACE, &ground->view); + if(res != RES_OK) { + htrdr_log_err(ground->htrdr, + "Could not create the Star-3D scene view -- %s.\n", + res_to_cstr(res)); + goto error; + } + + res = s3d_scene_view_get_aabb(ground->view, ground->lower, ground->upper); + if(res != RES_OK) { + htrdr_log_err(ground->htrdr, + "Could not get the bounding box of the geometry -- %s.\n", + res_to_cstr(res)); + goto error; + } exit: + if(obj) AW(obj_ref_put(obj)); + if(shape) S3D(shape_ref_put(shape)); + if(scene) S3D(scene_ref_put(scene)); + htable_vertex_release(&vertices); + darray_double_release(&positions); + darray_size_t_release(&indices); return res; error: - htrdr_log_err(ground->htrdr, - "Could not setup the ground specular BSDF with a reflectivity of %g -- %s.\n", - reflectivity, res_to_cstr(res)); - if(ground->bsdf) { - SSF(bsdf_ref_put(ground->bsdf)); - ground->bsdf = NULL; - } goto exit; } @@ -281,7 +501,7 @@ release_ground(ref_T* ref) ASSERT(ref); ground = CONTAINER_OF(ref, struct htrdr_ground, ref); if(ground->view) S3D(scene_view_ref_put(ground->view)); - if(ground->bsdf) SSF(bsdf_ref_put(ground->bsdf)); + htable_interface_release(&ground->interfaces); MEM_RM(ground->htrdr->allocator, ground); } @@ -292,8 +512,6 @@ res_T htrdr_ground_create (struct htrdr* htrdr, const char* obj_filename, /* May be NULL */ - const enum htrdr_bsdf_type bsdf_type, - const double reflectivity, const int repeat_ground, /* Infinitely repeat the ground in X and Y */ struct htrdr_ground** out_ground) { @@ -302,7 +520,6 @@ htrdr_ground_create struct time t0, t1; res_T res = RES_OK; ASSERT(htrdr && out_ground); - ASSERT(reflectivity >= 0 || reflectivity <= 1); ground = MEM_CALLOC(htrdr->allocator, 1, sizeof(*ground)); if(!ground) { @@ -317,18 +534,9 @@ htrdr_ground_create ground->repeat = repeat_ground; f3_splat(ground->lower, (float)INF); f3_splat(ground->upper,-(float)INF); + htable_interface_init(ground->htrdr->allocator, &ground->interfaces); - switch(bsdf_type) { - case HTRDR_BSDF_DIFFUSE: - res = setup_bsdf_diffuse(ground, reflectivity); - break; - case HTRDR_BSDF_SPECULAR: - res = setup_bsdf_specular(ground, reflectivity); - break; - default: FATAL("Unreachable code\n"); - - } - if(res != RES_OK) goto error; + if(!obj_filename) goto exit; time_current(&t0); res = setup_ground(ground, obj_filename); @@ -362,11 +570,19 @@ htrdr_ground_ref_put(struct htrdr_ground* ground) ref_put(&ground->ref, release_ground); } -struct ssf_bsdf* -htrdr_ground_get_bsdf(const struct htrdr_ground* ground) +void +htrdr_ground_get_interface + (struct htrdr_ground* ground, + const struct s3d_hit* hit, + struct htrdr_interface* out_interface) { - ASSERT(ground); - return ground->bsdf; + struct htrdr_interface* interf = NULL; + ASSERT(ground && hit && out_interface); + + interf = htable_interface_find(&ground->interfaces, &hit->prim.geom_id); + ASSERT(interf); + + *out_interface = *interf; } res_T diff --git a/src/htrdr_ground.h b/src/htrdr_ground.h @@ -1,5 +1,5 @@ -/* Copyright (C) 2018, 2019, 2020 |Meso|Star> (contact@meso-star.com) - * Copyright (C) 2018, 2019 CNRS, Université Paul Sabatier +/* 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 @@ -19,14 +19,10 @@ #include <rsys/rsys.h> -enum htrdr_bsdf_type { - HTRDR_BSDF_DIFFUSE, - HTRDR_BSDF_SPECULAR -}; - /* Forward declarations */ struct htrdr; struct htrdr_ground; +struct htrdr_interface; struct s3d_hit; struct ssf_bsdf; @@ -34,8 +30,6 @@ extern LOCAL_SYM res_T htrdr_ground_create (struct htrdr* htrdr, const char* obj_filename, /* May be NULL <=> No ground geometry */ - const enum htrdr_bsdf_type bsdf_type, - const double reflectivity, /* In [0, 1] */ const int repeat_ground, /* Infinitely repeat the ground in X and Y */ struct htrdr_ground** ground); @@ -47,9 +41,22 @@ extern LOCAL_SYM void htrdr_ground_ref_put (struct htrdr_ground* ground); -extern LOCAL_SYM struct ssf_bsdf* -htrdr_ground_get_bsdf - (const struct htrdr_ground* ground); +extern LOCAL_SYM void +htrdr_ground_get_interface + (struct htrdr_ground* ground, + const struct s3d_hit* hit, + struct htrdr_interface* interface); + +extern LOCAL_SYM res_T +htrdr_ground_create_bsdf + (struct htrdr_ground* ground, + const size_t ithread, + const double wavelength, + const double pos[3], + const double dir[3], /* Incoming ray */ + const struct s3d_hit* hit, + struct htrdr_interface* interf, /* NULL <=> do not return the interface */ + struct ssf_bsdf** bsdf); extern LOCAL_SYM res_T htrdr_ground_trace_ray diff --git a/src/htrdr_interface.c b/src/htrdr_interface.c @@ -0,0 +1,169 @@ +/* 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 <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; +} + +/******************************************************************************* + * 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 s3d_hit* hit, + struct ssf_bsdf** out_bsdf) +{ + struct ssf_bsdf* bsdf = NULL; + const struct mrumtl_brdf* brdf = NULL; + const struct mrumtl* mat = NULL; + double N[3]; + res_T res = RES_OK; + ASSERT(htrdr && pos && hit && out_bsdf); + ASSERT(interf && interf->mtl_front && interf->mtl_back); + + ASSERT(htrdr && interf && pos && dir && hit && out_bsdf); + ASSERT(d3_is_normalized(dir)); + + /* Check incoming ray */ + d3_normalize(N, d3_set_f3(N, hit->normal)); + if(d3_dot(N, dir) < 0) { + mat = interf->mtl_front; + } else { + mat = interf->mtl_back; + } + if(!mat) { + htrdr_log_err(htrdr, "%s: the hit surface has no material.\n", FUNC_NAME); + res = RES_BAD_ARG; + goto error; + } + + res = mrumtl_fetch_brdf(mat, wavelength, &brdf); + if(res != RES_OK) { + htrdr_log_err(htrdr, + "%s: error retreiving 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_interface.h b/src/htrdr_interface.h @@ -0,0 +1,45 @@ +/* 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/>. */ + +#ifndef HTRDR_INTERFACE_H +#define HTRDR_INTERFACE_H + +#include <star/ssf.h> + +/* Forward declaration of external data type */ +struct mrumtl; +struct s3d_hit; +struct ssf_bsdf; + +struct htrdr_interface { + const struct mrumtl* mtl_front; + const struct mrumtl* mtl_back; +}; +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 s3d_hit* hit, + struct ssf_bsdf** bsdf); + +#endif /* HTRDR_INTERFACE_H */ + diff --git a/src/htrdr_mtl.c b/src/htrdr_mtl.c @@ -182,7 +182,7 @@ mtl_release(ref_T* ref) * Local symbol ******************************************************************************/ res_T -htrdr_mtl_load +htrdr_mtl_create (struct htrdr* htrdr, const char* filename, struct htrdr_mtl** out_mtl) diff --git a/src/htrdr_mtl.h b/src/htrdr_mtl.h @@ -21,7 +21,7 @@ struct htrdr_mtl; struct mrumtl; extern LOCAL_SYM res_T -htrdr_mtl_load +htrdr_mtl_create (struct htrdr* htrdr, const char* filename, struct htrdr_mtl** mtl);