commit 474640c3ae386e16da0495bad4eccd09b4ddfe21
parent f5b5aa7d0494165fd3690c24b4a8b68a07f91366
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Thu, 4 Oct 2018 16:02:10 +0200
Fix htrdr_compute_radiance_sw
Attach filter function to the ground geometry to avoid "self hits".
Handle the case where the ground is not a plane below the sky. In this
case, the random walk can reach a surface that does not front face the
sun. Furthermore, the sun can be occluded by a surface at any scattering
position.
Diffstat:
3 files changed, 68 insertions(+), 12 deletions(-)
diff --git a/src/htrdr.c b/src/htrdr.c
@@ -164,6 +164,8 @@ setup_geometry(struct htrdr* htrdr, const char* filename)
}
if(filename) {
+ size_t ishape, nshapes;
+
res = s3daw_create(&htrdr->logger, htrdr->allocator, NULL, NULL, htrdr->s3d,
htrdr->verbose, &s3daw);
if(res != RES_OK) {
@@ -175,11 +177,23 @@ setup_geometry(struct htrdr* htrdr, const char* filename)
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,
+
+ 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, htrdr_ground_filter, NULL);
+ if(res != RES_OK) {
+ htrdr_log_err(htrdr,
+ "could not setup the hit filter function of the ground geometry.\n");
+ goto error;
+ }
+ res = s3d_scene_attach_shape(scn, shape);
+ if(res != RES_OK) {
+ htrdr_log_err(htrdr,
"could not attach the loaded geometry to the Star-3D scene.\n");
- goto error;
+ goto error;
+ }
}
}
diff --git a/src/htrdr_compute_radiance_sw.c b/src/htrdr_compute_radiance_sw.c
@@ -60,6 +60,21 @@ static const struct transmissivity_context TRANSMISSION_CONTEXT_NULL = {
/*******************************************************************************
* Helper functions
******************************************************************************/
+int
+htrdr_ground_filter
+ (const struct s3d_hit* hit,
+ const float ray_org[3],
+ const float ray_dir[3],
+ void* ray_data,
+ void* filter_data)
+{
+ const struct s3d_hit* hit_prev = ray_data;
+ (void)ray_org, (void)ray_dir, (void)filter_data;
+
+ if(!hit_prev) return 0;
+ return S3D_PRIMITIVE_EQ(&hit->prim, &hit_prev->prim);
+}
+
static int
scattering_hit_filter
(const struct svx_hit* hit,
@@ -308,7 +323,7 @@ htrdr_compute_radiance_sw
CHK(RES_OK == ssf_phase_create
(&htrdr->lifo_allocators[ithread], &ssf_phase_rayleigh, &phase_rayleigh));
- SSF(lambertian_reflection_setup(bsdf, 0.5));
+ SSF(lambertian_reflection_setup(bsdf, 0.8));
/* Setup the phase function for this spectral band & quadrature point */
g = htrdr_sky_fetch_particle_phase_function_asymmetry_parameter
@@ -348,6 +363,7 @@ htrdr_compute_radiance_sw
/* Radiative random walk */
for(;;) {
struct scattering_context scattering_ctx = SCATTERING_CONTEXT_NULL;
+ struct s3d_hit s3d_hit_tmp = S3D_HIT_NULL;
/* Setup the ray to trace */
f3_set_d3(ray_pos, pos);
@@ -395,11 +411,26 @@ htrdr_compute_radiance_sw
(htrdr, rng, HTRDR_Ka, iband, iquad, 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);
+ /* Sample a sun direction */
htrdr_sun_sample_direction(htrdr->sun, rng, sun_dir);
- Tr = transmissivity(htrdr, rng, HTRDR_Kext, iband, iquad, pos_next,
- sun_dir, range, &s3d_hit);
+ d2(range, 0, FLT_MAX);
+
+ s3d_hit_prev = SVX_HIT_NONE(&svx_hit) ? s3d_hit : S3D_HIT_NULL;
+
+ /* Check that the sun is visible from the new position */
+ f3_set_d3(ray_pos, pos_next);
+ f3_set_d3(ray_dir, sun_dir);
+ f2(ray_range, 0, FLT_MAX);
+ S3D(scene_view_trace_ray(htrdr->s3d_scn_view, ray_pos, ray_dir, ray_range,
+ &s3d_hit_prev, &s3d_hit_tmp));
+
+ /* Define the transmissivity from the new position to the sun */
+ if(!S3D_HIT_NONE(&s3d_hit_tmp)) {
+ Tr = 0;
+ } else {
+ Tr = transmissivity(htrdr, rng, HTRDR_Kext, iband, iquad, pos_next,
+ sun_dir, range, &s3d_hit_prev);
+ }
/* Scattering at a surface */
if(SVX_HIT_NONE(&svx_hit)) {
@@ -413,7 +444,11 @@ htrdr_compute_radiance_sw
(bsdf, rng, wo, N, dir_next, &type, &pdf);
if(ssp_rng_canonical(rng) > reflectivity) break; /* Russian roulette */
- R = ssf_bsdf_eval(bsdf, wo, N, sun_dir);
+ if(d3_dot(N, sun_dir) < 0) { /* Below the ground */
+ R = 0;
+ } else {
+ R = ssf_bsdf_eval(bsdf, wo, N, sun_dir);
+ }
/* Scattering in the medium */
} else {
@@ -446,8 +481,6 @@ 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;
}
SSF(bsdf_ref_put(bsdf));
SSF(phase_ref_put(phase_hg));
diff --git a/src/htrdr_solve.h b/src/htrdr_solve.h
@@ -31,6 +31,7 @@ static const struct htrdr_accum HTRDR_ACCUM_NULL = HTRDR_ACCUM_NULL__;
/* Forward declarations */
struct htrdr;
struct htrdr_camera;
+struct s3d_hit;
struct ssp_rng;
extern LOCAL_SYM double
@@ -50,4 +51,12 @@ htrdr_draw_radiance_sw
const size_t spp, /* #samples per pixel, i.e. #realisations */
struct htrdr_buffer* buf); /* Buffer of struct htrdr_accum[3] */
+extern LOCAL_SYM int
+htrdr_ground_filter
+ (const struct s3d_hit* hit,
+ const float ray_dorg[3],
+ const float ray_dir[3],
+ void* ray_data,
+ void* filter_data);
+
#endif /* HTRDR_SOLVE_H */