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:
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);