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