solstice-solver

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

commit 09b68b04987cae506b4f953b8d3887ba1d443e70
parent 3a2eb821c809f2210c337a3539bf304d7f6cb522
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 13 Oct 2016 12:39:54 +0200

Fix issues in the ssol_solver

Diffstat:
Msrc/ssol_c.h | 3++-
Msrc/ssol_scene.c | 18+++++++++++-------
Msrc/ssol_shape.c | 11++++++++---
Msrc/ssol_solver.c | 60++++++++++++++++++++++++++++++++++--------------------------
Msrc/test_ssol_solver4.c | 1+
5 files changed, 56 insertions(+), 37 deletions(-)

diff --git a/src/ssol_c.h b/src/ssol_c.h @@ -44,6 +44,7 @@ struct ray_data { struct ssol_instance* inst_from; /* Instance from which the ray starts */ enum ssol_side_flag side_from; /* Primitive side from which the ray starts */ int discard_virtual_materials; /* Define if virtual materials are not RT */ + float range_min; /* Output data */ double N[3]; @@ -51,7 +52,7 @@ struct ray_data { }; static const struct ray_data RAY_DATA_NULL = { - NULL, S3D_PRIMITIVE_NULL__, NULL, 0, 0, {NaN, NaN, NaN}, NaN + NULL, S3D_PRIMITIVE_NULL__, NULL, 0, 0, 0, {NaN, NaN, NaN}, NaN }; diff --git a/src/ssol_scene.c b/src/ssol_scene.c @@ -368,7 +368,7 @@ hit_filter_function struct ssol_material* mtl; struct ray_data* rdata = ray_data; const struct shaded_shape* sshape; - enum ssol_side_flag hit_side; + enum ssol_side_flag hit_side = 3; double pos[3], dir[3], N[3], dst = FLT_MAX; size_t id; (void)filter_data; @@ -386,6 +386,7 @@ hit_filter_function switch(sshape->shape->type) { case SHAPE_MESH: if(hit->distance <= 1.e-6 /* FIXME hack */ + || hit->distance <= rdata->range_min || S3D_PRIMITIVE_EQ(&hit->prim, &rdata->prim_from)) { /* Discard self intersection for mesh, i.e. when the intersected * primitive is the primitive from which the ray starts */ @@ -405,13 +406,16 @@ hit_filter_function if(dst >= FLT_MAX) { /* No projection is found => the ray does not intersect the quadric */ return 1; - } else if(inst == rdata->inst_from) { - /* If the intersected instance is the one from which the ray starts, - * ensure that the ray does not intersect the opposite side of the - * quadric */ + } else { hit_side = d3_dot(dir, N) < 0 ? SSOL_FRONT : SSOL_BACK; - if(hit_side != rdata->side_from) { - return 1; + if(inst == rdata->inst_from) { + /* If the intersected instance is the one from which the ray starts, + * ensure that the ray does not intersect the opposite side of the + * quadric */ + hit_side = d3_dot(dir, N) < 0 ? SSOL_FRONT : SSOL_BACK; + if(hit_side != rdata->side_from) { + return 1; + } } } break; diff --git a/src/ssol_shape.c b/src/ssol_shape.c @@ -683,14 +683,19 @@ quadric_parabol_intersect_local double* dist) /* in/out: */ { /* Define x^2 + y^2 - 4 focal z = 0 */ + double dst; const double a = dir[0] * dir[0] + dir[1] * dir[1]; const double b = 2 * org[0] * dir[0] + 2 * org[1] * dir[1] - 4 * quad->focal * dir[2]; const double c = org[0] * org[0] + org[1] * org[1] - 4 * quad->focal * org[2]; - const int sol = quadric_solve_second(a, b, c, hint, dist); + const int sol = quadric_solve_second(a, b, c, hint, &dst); + double tmp[3]; + if(!sol) return 0; - d3_add(pt, org, d3_muld(pt, dir, *dist)); - quadric_parabol_gradient_local(quad, pt, grad); + d3_add(tmp, org, d3_muld(tmp, dir, dst)); + quadric_parabol_gradient_local(quad, tmp, grad); + d3_set(pt, tmp); + *dist = dst; return 1; } diff --git a/src/ssol_solver.c b/src/ssol_solver.c @@ -897,7 +897,7 @@ ssol_solve struct ssol_instance* inst; const struct shaded_shape* sshape; struct ray_data ray_data = RAY_DATA_NULL; - double pos[3], dir[3], N[3], tmp[3], weight, cos_dir_N, wl; + double pos[3], dir[3], N[3], weight, cos_dir_N, wl; float posf[3], dirf[3], uv[2]; float range[2] = { 0, FLT_MAX }; size_t id; @@ -912,31 +912,32 @@ ssol_solve /* Retrieve the position of the sampled point */ S3D(primitive_get_attrib(&prim, S3D_POSITION, uv, &attr)); - f3_set(posf, attr.value); + d3_set_f3(pos, attr.value); /* Retrieve the sampled instance and shaded shape */ inst = *htable_instance_find(&scn->instances_samp, &prim.inst_id); id = *htable_shaded_shape_find(&inst->object->shaded_shapes_samp, &prim.geom_id); sshape = darray_shaded_shape_cdata_get(&inst->object->shaded_shapes)+id; - /* Fetch the current position and its associated normal */ - d3_set_f3(pos, posf); - switch(sshape->shape->type) { - case SHAPE_MESH: - S3D(primitive_get_attrib(&prim, S3D_GEOMETRY_NORMAL, uv, &attr)); - f3_normalize(attr.value, attr.value); - d3_set_f3(N, attr.value); - break; - case SHAPE_PUNCHED: - punched_shape_project_point(sshape->shape, inst->transform, pos, pos, N); - break; - default: FATAL("Unreachable code"); break; - } + /* Fetch the sampled position and its associated normal */ + S3D(primitive_get_attrib(&prim, S3D_GEOMETRY_NORMAL, uv, &attr)); + f3_normalize(attr.value, attr.value); + d3_set_f3(N, attr.value); /* Sample a sun direction */ ranst_sun_dir_get(ran_sun_dir, rng, dir); cos_dir_N = d3_dot(N, dir); + /* Initialise the Monte Carlo weight */ + weight = scn->sun->dni * sampled_area * fabs(cos_dir_N); + + /* For punched surface, retrieve the sampled position and normal onto the + * quadric surface */ + if(sshape->shape->type == SHAPE_PUNCHED) { + punched_shape_project_point(sshape->shape, inst->transform, pos, pos, N); + cos_dir_N = d3_dot(N, dir); + } + /* Initialise the ray data to avoid self intersection */ ray_data.scn = scn; ray_data.prim_from = prim; @@ -946,6 +947,7 @@ ssol_solve /* Trace a ray toward the sun to check if the sampled point is occluded */ f3_minus(dirf, f3_set_d3(dirf, dir)); + f3_set_d3(posf, pos); ray_data.dst = FLT_MAX; S3D(scene_view_trace_ray(view_rt, posf, dirf, range, &ray_data, &hit)); if(!S3D_HIT_NONE(&hit)) { /* First ray is occluded */ @@ -959,11 +961,10 @@ ssol_solve /* Sample a wavelength */ wl = ranst_sun_wl_get(ran_sun_wl, rng); - /* Initialise the integration weight */ - weight = scn->sun->dni * sampled_area * fabs(cos_dir_N); - for(;;) { struct ssol_material* mtl; + double tmp[3]; + float tmpf[3]; double pdf; uint32_t inst_id; int32_t receiver_id; @@ -974,6 +975,7 @@ ssol_solve is_receiver = inst->receiver_mask & SSOL_FRONT; SSOL(instance_get_id(inst, &inst_id)); receiver_id = (int32_t)inst_id; + ray_data.side_from = SSOL_FRONT; } else { /* Back face */ mtl = sshape->mtl_back; @@ -981,6 +983,7 @@ ssol_solve SSOL(instance_get_id(inst, &inst_id)); receiver_id = -(int32_t)inst_id; d3_minus(N, N); + ray_data.side_from = SSOL_BACK; } if(is_receiver) { @@ -1005,6 +1008,9 @@ ssol_solve } if(mtl->type == MATERIAL_VIRTUAL) { + /* Note that for Virtual materials, the ray parameters 'posf' & 'dirf' + * are not updated to ensure that it pursues its traversal without any + * accuracy issue */ range[0] = nextafterf(hit.distance, FLT_MAX); range[1] = FLT_MAX; } else { @@ -1024,20 +1030,22 @@ ssol_solve /* Sample the BSDF to find the next direction to trace */ weight *= ssf_bsdf_sample(bsdf, rng, dir, frag.Ns, dir, &pdf); + /* Setup new ray parameters */ range[0] = 0; range[1] = FLT_MAX; + f3_set_d3(posf, pos); + f3_set_d3(dirf, dir); } /* Trace the next ray */ ray_data.dst = FLT_MAX; - f3_set_d3(dirf, dir); - f3_set_d3(posf, pos); + ray_data.range_min = range[0]; S3D(scene_view_trace_ray(view_rt, posf, dirf, range, &ray_data, &hit)); if(S3D_HIT_NONE(&hit)) break; ++depth; - /* Take into account the atomosphere attenuation along the new ray */ + /* Take into account the atmosphere attenuation along the new ray */ if(scn->atmosphere) { weight *= compute_atmosphere_attenuation (scn->atmosphere, hit.distance, wl); @@ -1053,9 +1061,9 @@ ssol_solve case SHAPE_MESH: f3_normalize(hit.normal, hit.normal); d3_set_f3(N, hit.normal); - f3_mulf(dirf, dirf, hit.distance); - f3_add(posf, posf, dirf); - d3_set_f3(pos, posf); + f3_mulf(tmpf, dirf, hit.distance); + f3_add(tmpf, posf, tmpf); + d3_set_f3(pos, tmpf); break; case SHAPE_PUNCHED: d3_normalize(N, ray_data.N); @@ -1064,12 +1072,12 @@ ssol_solve break; default: FATAL("Unreachable code"); break; } - cos_dir_N = d3_dot(dir, N); /* Setup the ray data to avoid self intersection */ ray_data.prim_from = hit.prim; ray_data.inst_from = inst; - ray_data.side_from = cos_dir_N < 0 ? SSOL_FRONT : SSOL_BACK; + + cos_dir_N = d3_dot(dir, N); } if(!hit_a_receiver) { diff --git a/src/test_ssol_solver4.c b/src/test_ssol_solver4.c @@ -140,6 +140,7 @@ main(int argc, char** argv) CHECK(ssol_instance_sample(target1, 0), RES_OK); CHECK(ssol_scene_attach_instance(scene, target1), RES_OK); CHECK(ssol_object_instantiate(t_object, &target2), RES_OK); + transform[11] += 1.e-4; CHECK(ssol_instance_set_transform(target2, transform), RES_OK); CHECK(ssol_instance_set_receiver(target2, SSOL_FRONT), RES_OK); CHECK(ssol_instance_sample(target2, 0), RES_OK);