solstice-solver

Solver library of the solstice app
git clone git://git.meso-star.com/solstice-solver.git
Log | Files | Refs | README | LICENSE

commit 41e597424db9976fe1e0cf2dc394fffd63b7fa90
parent 839c10b49e0a6598407911145ff3a8b5d380b503
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 17 Mar 2017 17:08:03 +0100

Add the ssol_path_tracker API

When provided to the ssol_solve function, this structure enables the
tracking of the radiative paths. It is then use to configure the
tracking.

Diffstat:
Msrc/ssol.h | 26++++++++++++++++++++++++--
Msrc/ssol_estimator.c | 28+++++++++++++++++-----------
Msrc/ssol_estimator_c.h | 73++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/ssol_solver.c | 90++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Msrc/test_ssol_solver1.c | 3++-
5 files changed, 167 insertions(+), 53 deletions(-)

diff --git a/src/ssol.h b/src/ssol.h @@ -66,6 +66,12 @@ enum ssol_side_flag { SSOL_INVALID_SIDE = BIT(2) }; +enum ssol_path_type { + SSOL_PATH_MISSING, /* The path misses the receivers */ + SSOL_PATH_SHADOW, /* The path is occluded before the sampled geometry */ + SSOL_PATH_SUCCESS /* The path contributes to at least one receiver */ +}; + enum ssol_material_type { SSOL_MATERIAL_MATTE, SSOL_MATERIAL_MIRROR, @@ -298,9 +304,20 @@ struct ssol_instantiated_shaded_shape { static const struct ssol_instantiated_shaded_shape SSOL_INSTANTIATED_SHADED_SHAPE_NULL = SSOL_INSTANTIATED_SHADED_SHAPE_NULL__; +struct ssol_path_tracker { + /* Control the length of the path segment starting/ending from/to the + * infinite. A value less than zero means for default value */ + double length_inf_start; + double length_inf_end; +}; + +#define SSOL_PATH_TRACKER_DEFAULT__ {-1, -1} +static const struct ssol_path_tracker SSOL_PATH_TRACKER_DEFAULT = + SSOL_PATH_TRACKER_DEFAULT__; + struct ssol_path { /* Internal data */ - const void* vertices__; + const void* path__; }; struct ssol_path_vertex { @@ -1003,6 +1020,11 @@ ssol_path_get_vertex const size_t ivertex, struct ssol_path_vertex* vertex); +SSOL_API res_T +ssol_path_get_type + (const struct ssol_path* path, + enum ssol_path_type* type); + /******************************************************************************* * Per receiver MC estimations ******************************************************************************/ @@ -1033,7 +1055,7 @@ ssol_solve (struct ssol_scene* scn, struct ssp_rng* rng, const size_t realisations_count, - const int track_paths, /* Define if the radiative paths are recorded */ + const struct ssol_path_tracker* tracker, /* NULL<=>Do not record the paths */ FILE* output, /* May be NULL <=> does not ouput ssol_receiver_data */ struct ssol_estimator** estimator); diff --git a/src/ssol_estimator.c b/src/ssol_estimator.c @@ -221,17 +221,17 @@ ssol_estimator_get_tracked_path { if(!estimator || ipath >= darray_path_size_get(&estimator->paths) || !path) return RES_BAD_ARG; - path->vertices__ = darray_path_cdata_get(&estimator->paths) + ipath; + path->path__ = darray_path_cdata_get(&estimator->paths) + ipath; return RES_OK; } res_T ssol_path_get_vertices_count(const struct ssol_path* path, size_t* nvertices) { - const struct darray_path_vertex* vertices; + const struct path* p; if(!path || !nvertices) return RES_BAD_ARG; - vertices = path->vertices__; - *nvertices = darray_path_vertex_size_get(vertices); + p = path->path__; + *nvertices = darray_path_vertex_size_get(&p->vertices); return RES_OK; } @@ -241,14 +241,20 @@ ssol_path_get_vertex const size_t ivertex, struct ssol_path_vertex* vertex) { - const struct darray_path_vertex* vertices; - const struct path_vertex* vert; + const struct path* p; if(!path || !vertex) return RES_BAD_ARG; - vertices = path->vertices__; - if(ivertex >= darray_path_vertex_size_get(vertices)) return RES_BAD_ARG; - vert = darray_path_vertex_cdata_get(vertices) + ivertex; - d3_set(vertex->pos, vert->pos); - vertex->weight = vert->weight; + p = path->path__; + if(ivertex >= darray_path_vertex_size_get(&p->vertices)) return RES_BAD_ARG; + *vertex = darray_path_vertex_cdata_get(&p->vertices)[ivertex]; + return RES_OK; +} + +res_T +ssol_path_get_type(const struct ssol_path* path, enum ssol_path_type* type) +{ + ASSERT(path && type); + if(!path || !type) return RES_BAD_ARG; + *type = ((struct path*)path->path__)->type; return RES_OK; } diff --git a/src/ssol_estimator_c.h b/src/ssol_estimator_c.h @@ -379,21 +379,72 @@ error: /******************************************************************************* * Radiative path ******************************************************************************/ -struct path_vertex { - double pos[3]; - double weight; -}; - #define DARRAY_NAME path_vertex -#define DARRAY_DATA struct path_vertex +#define DARRAY_DATA struct ssol_path_vertex #include <rsys/dynamic_array.h> +struct path { + enum ssol_path_type type; + struct darray_path_vertex vertices; +}; + +static INLINE void +path_init(struct mem_allocator* allocator, struct path* path) +{ + ASSERT(path); + path->type = SSOL_PATH_MISSING; + darray_path_vertex_init(allocator, &path->vertices); +} + +static INLINE void +path_release(struct path* path) +{ + ASSERT(path); + darray_path_vertex_release(&path->vertices); +} + +static INLINE res_T +path_copy(struct path* dst, const struct path* src) +{ + ASSERT(dst && src); + dst->type = src->type; + return darray_path_vertex_copy(&dst->vertices, &src->vertices); +} + +static INLINE res_T +path_copy_and_release(struct path* dst, struct path* src) +{ + ASSERT(dst && src); + dst->type = src->type; + return darray_path_vertex_copy_and_release(&dst->vertices, &src->vertices); +} + +static INLINE res_T +path_copy_and_clear(struct path* dst, struct path* src) +{ + ASSERT(dst && src); + dst->type = src->type; + return darray_path_vertex_copy_and_clear(&dst->vertices, &src->vertices); +} + +static INLINE res_T +path_add_vertex(struct path* path, const double pos[3], const double weight) +{ + struct ssol_path_vertex vertex; + ASSERT(path && pos && weight >= 0); + vertex.pos[0] = pos[0]; + vertex.pos[1] = pos[1]; + vertex.pos[2] = pos[2]; + vertex.weight = weight; + return darray_path_vertex_push_back(&path->vertices, &vertex); +} + #define DARRAY_NAME path -#define DARRAY_DATA struct darray_path_vertex -#define DARRAY_FUNCTOR_INIT darray_path_vertex_init -#define DARRAY_FUNCTOR_RELEASE darray_path_vertex_release -#define DARRAY_FUNCTOR_COPY darray_path_vertex_copy -#define DARRAY_FUNCTOR_COPY_AND_RELEASE darray_path_vertex_copy_and_release +#define DARRAY_DATA struct path +#define DARRAY_FUNCTOR_INIT path_init +#define DARRAY_FUNCTOR_RELEASE path_release +#define DARRAY_FUNCTOR_COPY path_copy +#define DARRAY_FUNCTOR_COPY_AND_RELEASE path_copy_and_release #include <rsys/dynamic_array.h> /******************************************************************************* diff --git a/src/ssol_solver.c b/src/ssol_solver.c @@ -453,25 +453,24 @@ check_scene(const struct ssol_scene* scene, const char* caller) return RES_OK; } -static INLINE res_T -path_add_vertex - (struct darray_path_vertex* path, - const double pos[3], - const double weight) +/* Compute an empirical length of the path segment coming from/going to the + * infinite, wrt the scene bounding box */ +static INLINE double +compute_infinite_path_segment_extend(struct s3d_scene_view* view) { - struct path_vertex vertex; - ASSERT(path && pos && weight >= 0); - d3_set(vertex.pos, pos); - vertex.weight = weight; - return darray_path_vertex_push_back(path, &vertex); + float lower[3], upper[3], size[3]; + ASSERT(view); + S3D(scene_view_get_aabb(view, lower, upper)); + f3_sub(size, upper, lower); + return MMAX(size[0], MMAX(size[1], size[2])) * 0.75; } static INLINE res_T path_register_and_clear (struct darray_path* paths, - struct darray_path_vertex* path) + struct path* path) { - struct darray_path_vertex* dst; + struct path* dst_path; size_t ipath; res_T res = RES_OK; ASSERT(paths && path); @@ -480,8 +479,8 @@ path_register_and_clear res = darray_path_resize(paths, ipath + 1); if(res != RES_OK) return res; - dst = darray_path_data_get(paths) + ipath; - return darray_path_vertex_copy_and_clear(dst, path); + dst_path = darray_path_data_get(paths) + ipath; + return path_copy_and_clear(dst_path, path); } static res_T @@ -684,10 +683,10 @@ trace_radiative_path struct s3d_scene_view* view_rt, struct ranst_sun_dir* ran_sun_dir, struct ranst_sun_wl* ran_sun_wl, - const int track_paths, + const struct ssol_path_tracker* tracker, /* May be NULL */ FILE* output) /* May be NULL */ { - struct darray_path_vertex path; + struct path path; struct s3d_hit hit = S3D_HIT_NULL; struct point pt; float org[3], dir[3], range[2] = { 0, FLT_MAX }; @@ -696,16 +695,25 @@ trace_radiative_path res_T res = RES_OK; ASSERT(thread_ctx && scn && view_samp && view_rt && ran_sun_dir && ran_sun_wl); - if(track_paths) { - darray_path_vertex_init(scn->dev->allocator, &path); - } + if(tracker) path_init(scn->dev->allocator, &path); /* Find a new starting point of the radiative random walk */ res = point_init(&pt, sampled_area_proxy, scn, &thread_ctx->mc_samps, view_samp, view_rt, ran_sun_dir, ran_sun_wl, thread_ctx->rng, &is_lit); if(res != RES_OK) goto error; - if(track_paths) { + if(tracker) { + /* Add the first point of the starting segment */ + if(tracker->length_inf_start > 0) { + double pos[3], wi[3]; + d3_minus(wi, pt.dir); + d3_muld(wi, wi, tracker->length_inf_start); + d3_add(pos, pt.pos, wi); + res = path_add_vertex(&path, pos, scn->sun->dni); + if(res != RES_OK) goto error; + } + + /* Register the init position onto the sampled geometry */ res = path_add_vertex(&path, pt.pos, pt.weight); if(res != RES_OK) goto error; } @@ -715,6 +723,7 @@ trace_radiative_path pt.mc_samp->shadowed.sqr_weight += pt.weight; thread_ctx->shadowed.weight += pt.weight; thread_ctx->shadowed.sqr_weight += pt.weight * pt.weight; + if(tracker) path.type = SSOL_PATH_SHADOW; } else { int hit_a_receiver = 0; @@ -767,7 +776,17 @@ trace_radiative_path ray_data.range_min = range[0]; ray_data.dst = FLT_MAX; S3D(scene_view_trace_ray(view_rt, org, dir, range, &ray_data, &hit)); - if(S3D_HIT_NONE(&hit)) break; + if(S3D_HIT_NONE(&hit)) { + /* Add the point of the last path segment going to the infinite */ + if(tracker) { + double pos[3], wi[3]; + d3_set_f3(wi, dir); + d3_add(pos, pt.pos, d3_muld(wi, wi, tracker->length_inf_end)); + res = path_add_vertex(&path, pos, pt.weight); + if(res != RES_OK) goto error; + } + break; + } depth += mtl->type != SSOL_MATERIAL_VIRTUAL; @@ -783,7 +802,7 @@ trace_radiative_path /* Update the point */ point_update_from_hit(&pt, scn, org, dir, &hit, &ray_data); - if(track_paths) { + if(tracker) { res = path_add_vertex(&path, pt.pos, pt.weight); if(res != RES_OK) goto error; } @@ -792,15 +811,18 @@ trace_radiative_path thread_ctx->missing.weight += pt.weight; thread_ctx->missing.sqr_weight += pt.weight*pt.weight; } + if(tracker) { + path.type = hit_a_receiver ? SSOL_PATH_SUCCESS : SSOL_PATH_MISSING; + } } - if(track_paths) { + if(tracker) { res = path_register_and_clear(&thread_ctx->paths, &path); if(res != RES_OK) goto error; } exit: - if(track_paths) darray_path_vertex_release(&path); + if(tracker) path_release(&path); return res; error: goto exit; @@ -814,7 +836,7 @@ ssol_solve (struct ssol_scene* scn, struct ssp_rng* rng_state, const size_t realisations_count, - const int track_paths, + const struct ssol_path_tracker* path_tracker, FILE* output, struct ssol_estimator** out_estimator) { @@ -826,6 +848,7 @@ ssol_solve struct ranst_sun_wl* ran_sun_wl = NULL; struct darray_thread_ctx thread_ctxs; struct ssol_estimator* estimator = NULL; + struct ssol_path_tracker tracker; struct ssp_rng_proxy* rng_proxy = NULL; double sampled_area; double sampled_area_proxy; @@ -878,6 +901,17 @@ ssol_solve if(res != RES_OK) goto error; } + /* Setup the path tracker */ + if(path_tracker) { + tracker = *path_tracker; + if(tracker.length_inf_start < 0 || tracker.length_inf_end < 0) { + const double extend = compute_infinite_path_segment_extend(view_rt); + if(tracker.length_inf_start < 0) tracker.length_inf_start = extend; + if(tracker.length_inf_end < 0) tracker.length_inf_end = extend; + } + path_tracker = &tracker; + } + /* Launch the parallel MC estimation */ #pragma omp parallel for schedule(static) for(i = 0; i < nrealisations; ++i) { @@ -892,7 +926,7 @@ ssol_solve /* Execute a MC experiment */ res_local = trace_radiative_path((size_t)i, sampled_area_proxy, thread_ctx, - scn, view_samp, view_rt, ran_sun_dir, ran_sun_wl, track_paths, output); + scn, view_samp, view_rt, ran_sun_dir, ran_sun_wl, path_tracker, output); if(res_local != RES_OK) { ATOMIC_SET(&res, res_local); continue; @@ -962,7 +996,7 @@ ssol_solve } /* Merge per thread tracked paths */ - if(track_paths) { + if(path_tracker) { FOR_EACH(i, 0, nthreads) { struct thread_context* thread_ctx; size_t ipath, npaths; @@ -970,7 +1004,7 @@ ssol_solve thread_ctx = darray_thread_ctx_data_get(&thread_ctxs) + i; npaths = darray_path_size_get(&thread_ctx->paths); FOR_EACH(ipath, 0, npaths) { - struct darray_path_vertex* path; + struct path* path; path = darray_path_data_get(&thread_ctx->paths) + ipath; res = path_register_and_clear(&estimator->paths, path); if(res != RES_OK) goto error; diff --git a/src/test_ssol_solver1.c b/src/test_ssol_solver1.c @@ -164,7 +164,8 @@ main(int argc, char** argv) CHECK(ssol_instance_set_receiver(target, SSOL_FRONT, 0), RES_OK); CHECK(ssol_scene_attach_instance(scene, target), RES_OK); - CHECK(ssol_solve(scene, rng, 1, 1, NULL, &estimator), RES_OK); + CHECK(ssol_solve + (scene, rng, 1, &SSOL_PATH_TRACKER_DEFAULT, NULL, &estimator), RES_OK); CHECK(ssol_estimator_get_tracked_paths_count(NULL, NULL), RES_BAD_ARG); CHECK(ssol_estimator_get_tracked_paths_count(estimator, NULL), RES_BAD_ARG);