htrdr

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

commit 1428fc52dbc781ae5f698e4cc25fb688a4438011
parent 15fc38e1a53f458034471fb9e0e68caa82a80237
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 15 Apr 2021 16:24:45 +0200

htrdr_geometry_trace_ray function

Regroup input arguments in the
"struct htrdr_geometry_trace_ray_args" data structure. In addition, the
caller can also give its own filter function.

Diffstat:
Msrc/atmosphere/htrdr_atmosphere_ground.c | 20++++++++++++++++----
Msrc/core/htrdr_geometry.c | 83++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Msrc/core/htrdr_geometry.h | 27+++++++++++++++++++++++----
3 files changed, 100 insertions(+), 30 deletions(-)

diff --git a/src/atmosphere/htrdr_atmosphere_ground.c b/src/atmosphere/htrdr_atmosphere_ground.c @@ -57,11 +57,16 @@ trace_slab int* hit) { struct trace_slab_context* ctx = context; + struct htrdr_geometry_trace_ray_args rt_args = + HTRDR_GEOMETRY_TRACE_RAY_ARGS_NULL; res_T res = RES_OK; ASSERT(org && dir && range && context && hit); - res = htrdr_geometry_trace_ray - (ctx->geom, org, dir, range, ctx->hit_prev, ctx->hit); + d3_set(rt_args.ray_org, org); + d3_set(rt_args.ray_dir, dir); + d3_set(rt_args.ray_range, range); + rt_args.hit_from = ctx->hit_prev ? *ctx->hit_prev : S3D_HIT_NULL; + res = htrdr_geometry_trace_ray(ctx->geom, &rt_args, ctx->hit); if(res != RES_OK) return res; *hit = !S3D_HIT_NONE(ctx->hit); @@ -172,9 +177,16 @@ htrdr_atmosphere_ground_trace_ray } if(!ground->repeat) { - res = htrdr_geometry_trace_ray - (ground->geom, org, dir, range, prev_hit, hit); + struct htrdr_geometry_trace_ray_args rt_args = + HTRDR_GEOMETRY_TRACE_RAY_ARGS_NULL; + + d3_set(rt_args.ray_org, org); + d3_set(rt_args.ray_dir, dir); + d3_set(rt_args.ray_range, range); + if(prev_hit) rt_args.hit_from = *prev_hit; + res = htrdr_geometry_trace_ray(ground->geom, &rt_args, hit); if(res != RES_OK) goto error; + } else { struct trace_slab_context slab_ctx = TRACE_SLAB_CONTEXT_NULL; double low[3], upp[3]; diff --git a/src/core/htrdr_geometry.c b/src/core/htrdr_geometry.c @@ -61,9 +61,12 @@ static const struct mesh MESH_NULL; struct ray_context { float range[2]; - struct s3d_hit hit_prev; + struct s3d_hit hit_from; + + s3d_hit_filter_function_T user_filter; /* May be NULL */ + void* user_filter_data; /* May be NULL */ }; -#define RAY_CONTEXT_NULL__ {{0,INF}, S3D_HIT_NULL__} +#define RAY_CONTEXT_NULL__ {{0,INF}, S3D_HIT_NULL__, NULL, NULL} static const struct ray_context RAY_CONTEXT_NULL = RAY_CONTEXT_NULL__; struct htrdr_geometry { @@ -99,6 +102,44 @@ hit_on_edge(const struct s3d_hit* hit) || eq_epsf(w, 1.f, on_edge_eps); } +/* Return 1 if the submitted hit is actually a self hit, i.e. if the ray starts + * the primitive from which it starts */ +static INLINE int +self_hit + (const struct s3d_hit* hit, + const float ray_org[3], + const float ray_dir[3], + const float ray_range[2], + const struct s3d_hit* hit_from) +{ + ASSERT(hit && hit_from); + (void)ray_org, (void)ray_dir; + + /* Internally, Star-3D relies on Embree that, due to numerically inaccuracy, + * can find hits whose distances are not strictly included in the submitted + * ray range. Discard these hits. */ + if(hit->distance <= ray_range[0] || hit->distance >= ray_range[1]) + return 1; + + /* The hit primitive is the one from which the the ray starts. Discard these + * hits */ + if(S3D_PRIMITIVE_EQ(&hit->prim, &hit_from->prim)) + return 1; + + /* If the targeted point is near of the origin, check that it lies on an + * edge/vertex shared by the 2 primitives. In such situation, we assume that + * it is a self intersection and discard this hit */ + if(!S3D_HIT_NONE(hit_from) + && eq_epsf(hit->distance, 0, 1.e-1f) + && hit_on_edge(hit_from) + && hit_on_edge(hit)) { + return 1; + } + + /* No self hit */ + return 0; +} + static int geometry_filter (const struct s3d_hit* hit, @@ -108,20 +149,19 @@ geometry_filter void* filter_data) { const struct ray_context* ray_ctx = ray_data; - (void)ray_org, (void)ray_dir, (void)filter_data; + (void)filter_data; - if(!ray_ctx) return 0; + if(!ray_ctx) /* Nothing to do */ + return 0; - if(S3D_PRIMITIVE_EQ(&hit->prim, &ray_ctx->hit_prev.prim)) return 1; + if(self_hit(hit, ray_org, ray_dir, ray_ctx->range, &ray_ctx->hit_from)) + return 1; /* Discard this hit */ - if(!S3D_HIT_NONE(&ray_ctx->hit_prev) && eq_epsf(hit->distance, 0, 1.e-1f)) { - /* If the targeted point is near of the origin, check that it lies on an - * edge/vertex shared by the 2 primitives. */ - return hit_on_edge(&ray_ctx->hit_prev) && hit_on_edge(hit); - } + if(!ray_ctx->user_filter) /* That's all */ + return 0; - return hit->distance <= ray_ctx->range[0] - || hit->distance >= ray_ctx->range[1]; + return ray_ctx->user_filter /* Invoke user filtering */ + (hit, ray_org, ray_dir, ray_ctx->user_filter_data, filter_data); } static res_T @@ -611,22 +651,21 @@ htrdr_geometry_get_interface res_T htrdr_geometry_trace_ray (struct htrdr_geometry* geom, - const double org[3], - const double dir[3], /* Must be normalized */ - const double range[2], - const struct s3d_hit* prev_hit, + const struct htrdr_geometry_trace_ray_args* args, struct s3d_hit* hit) { struct ray_context ray_ctx = RAY_CONTEXT_NULL; float ray_org[3]; float ray_dir[3]; res_T res = RES_OK; - ASSERT(geom && org && dir && range && hit); - - f3_set_d3(ray_org, org); - f3_set_d3(ray_dir, dir); - f2_set_d2(ray_ctx.range, range); - ray_ctx.hit_prev = prev_hit ? *prev_hit : S3D_HIT_NULL; + ASSERT(geom && args && hit); + + f3_set_d3(ray_org, args->ray_org); + f3_set_d3(ray_dir, args->ray_dir); + f2_set_d2(ray_ctx.range, args->ray_range); + ray_ctx.hit_from = args->hit_from; + ray_ctx.user_filter = args->filter; + ray_ctx.user_filter_data = args->filter_context; res = s3d_scene_view_trace_ray (geom->view, ray_org, ray_dir, ray_ctx.range, &ray_ctx, hit); diff --git a/src/core/htrdr_geometry.h b/src/core/htrdr_geometry.h @@ -20,6 +20,8 @@ #include "core/htrdr.h" +#include <star/s3d.h> + /* Forware declarations */ struct htrdr; struct htrdr_geometry; @@ -28,6 +30,26 @@ struct htrdr_materials; struct s3d_hit; struct ssf_bsdf; +struct htrdr_geometry_trace_ray_args { + double ray_org[3]; + double ray_dir[3]; + double ray_range[2]; + struct s3d_hit hit_from; /* Hit from which the ray starts */ + s3d_hit_filter_function_T filter; /* NULL <=> no user defined filter */ + void* filter_context; +}; + +#define HTRDR_GEOMETRY_TRACE_RAY_ARGS_NULL__ { \ + {0,0,0}, /* Ray origin */ \ + {0,0,1}, /* Ray direction */ \ + {0,DBL_MAX}, /* Ray range */ \ + S3D_HIT_NULL, /* Hit from */ \ + NULL, /* User defined filter function */ \ + NULL /* User filter function */ \ +} +static const struct htrdr_geometry_trace_ray_args +HTRDR_GEOMETRY_TRACE_RAY_ARGS_NULL = HTRDR_GEOMETRY_TRACE_RAY_ARGS_NULL__; + BEGIN_DECLS HTRDR_CORE_API res_T @@ -65,10 +87,7 @@ htrdr_geometry_create_bsdf HTRDR_CORE_API res_T htrdr_geometry_trace_ray (struct htrdr_geometry* geom, - const double ray_origin[3], - const double ray_direction[3], /* Must be normalized */ - const double ray_range[2], - const struct s3d_hit* prev_hit,/* Previous hit. Avoid self hit. May be NULL*/ + const struct htrdr_geometry_trace_ray_args* args, struct s3d_hit* hit); HTRDR_CORE_API res_T