commit 1f84b7e24e79d5e5e884e1ed00fcd6ab6c0ecf45
parent 123b067eb1017904ecd82183760d6adc2d3da083
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date: Fri, 9 Sep 2016 18:14:20 +0200
Work in progress on solver; new test2 still failing
Diffstat:
8 files changed, 498 insertions(+), 196 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -149,6 +149,7 @@ if(NOT NO_TEST)
new_test(test_ssol_shape)
new_test(test_ssol_spectrum)
new_test(test_ssol_solver1)
+ new_test(test_ssol_solver2)
new_test(test_ssol_sun)
endif(NOT NO_TEST)
diff --git a/src/ssol.h b/src/ssol.h
@@ -424,11 +424,14 @@ ssol_instance_set_receiver
const char* name_front, /* May be NULL <=> Front faces are no more receivers */
const char* name_back); /* May be NULL <=> back faces are no more receivers */
+/* TODO: per face mask */
SSOL_API res_T
ssol_instance_set_target_mask
(struct ssol_instance* instance,
const uint32_t mask);
+/* TODO: add a dont_sample flag */
+
SSOL_API res_T
ssol_instance_is_attached
(struct ssol_instance* instance,
diff --git a/src/ssol_c.h b/src/ssol_c.h
@@ -42,5 +42,17 @@ hit_filter_function
void* realisation,
void* filter_data);
+#include <math.h>
+
+#ifndef NAN
+#define NAN (INF * 0.0)
+#endif
+#define ISNAN(x) (!((x) == (x)))
+#ifndef NDEBUG
+#define ASSERT_NAN(x, sz) {int i; for (i = 0; i < (sz); i++)ASSERT(!ISNAN((x)[i]));}
+#else
+#define ASSERT_NAN(x, sz)
+#endif
+
#endif /* SSOL_C_H */
diff --git a/src/ssol_scene.c b/src/ssol_scene.c
@@ -27,7 +27,7 @@
#include <rsys/list.h>
#include <rsys/mem_allocator.h>
#include <rsys/rsys.h>
-#include <rsys/double3.h>
+#include <rsys/double33.h>
/*******************************************************************************
* Helper functions
@@ -267,56 +267,92 @@ error:
******************************************************************************/
int
hit_filter_function
- (const struct s3d_hit* hit,
- const float org[3],
- const float dir[3],
- void* realisation,
- void* filter_data)
+(const struct s3d_hit* hit,
+ const float org[3],
+ const float dir[3],
+ void* realisation,
+ void* filter_data)
{
- struct ssol_instance* inst;
+ const struct ssol_instance* inst;
+ const struct ssol_shape* shape;
const struct str* receiver_name;
struct realisation* rs = realisation;
- struct ssol_material* mtl;
struct segment* seg;
struct segment* prev;
- int front_face = 0;
+ double dist;
(void) filter_data, (void) org, (void) dir;
ASSERT(rs);
- prev = previous_segment(rs);
seg = current_segment(rs);
+ prev = previous_segment(rs);
ASSERT(seg);
- /* TODO: need to detect self intersect at the instance level,
- * using front/back face to avoid false self intersect events */
- if(prev && S3D_PRIMITIVE_EQ(&hit->prim, &prev->hit.prim))
- return 1; /* Discard self intersection */
+ /* these components have been set */
+ ASSERT_NAN(seg->dir, 3);
+ ASSERT_NAN(seg->org, 3);
+ ASSERT(seg->self_instance);
+ NCHECK(seg->self_front, 99);
+ /* Discard self intersection; using raytracing normal */
inst = *htable_instance_find(&rs->data.scene->instances_rt, &hit->prim.inst_id);
-
- if (inst->object->shape->type == SHAPE_PUNCHED) {
+
+ int hit_front = f3_dot(hit->normal, dir) < 0;
+ if (seg->self_instance == inst && seg->self_front != hit_front) {
+ return 1;
+ }
+
+ shape = inst->object->shape;
+ seg->on_punched = (shape->type == SHAPE_PUNCHED);
+ switch (shape->type) {
+ case SHAPE_PUNCHED: {
/* hits on quadrics must be recomputed more accurately */
- /* FIXME: use world2local and local2world transform */
- int valid = punched_shape_intersect_local(inst->object->shape, seg->org,
- seg->dir, hit->distance, seg->hit_pos, seg->hit_normal, &seg->dist);
+ double org_local[3], dir_local[3];
+ const double* transform = inst->transform;
+ double tr[9];
+ d33_inverse(tr, transform);
+
+ /* get org in local coordinate */
+ if (prev && prev->on_punched) {
+ d3_set(org_local, prev->hit_pos_local);
+ }
+ else {
+ d3_set(org_local, seg->org);
+ d3_sub(org_local, org_local, transform + 9);
+ d33_muld3(org_local, tr, org_local);
+ }
+
+ /* get dir in local */
+ d33_muld3(dir_local, tr, seg->dir);
+ /* recompute hit */
+ int valid = punched_shape_intersect_local(shape, org_local, dir_local,
+ hit->distance, seg->hit_pos_local, seg->hit_normal, &dist);
if (!valid) return 1;
+ /* transform point to world */
+ d33_muld3(seg->hit_pos, transform, seg->hit_pos_local);
+ d3_add(seg->hit_pos, transform + 9, seg->hit_pos);
+ /* transform normal to world */
+ d33_invtrans(tr, transform);
+ d33_muld3(seg->hit_normal, tr, seg->hit_normal);
+ ASSERT(d3_dot(seg->hit_normal, d3_set_f3(tr, hit->normal)) > 0);
+ break;
}
- else {
- double* from = prev ? prev->hit_pos : rs->start.pos;
- ASSERT(inst->object->shape->type == SHAPE_MESH);
+ case SHAPE_MESH: {
d3_set_f3(seg->hit_normal, hit->normal);
- seg->dist = hit->distance;
/* use raytraced distance to fill hit_pos */
- d3_add(seg->hit_pos, from, d3_muld(seg->hit_pos, seg->dir, hit->distance));
+ d3_add(seg->hit_pos, seg->org, d3_muld(seg->hit_pos, seg->dir, hit->distance));
+ break;
+ }
+ default: FATAL("Unreachable code.\n"); break;
}
- front_face = d3_dot(seg->hit_normal, seg->dir) < 0;
+ seg->hit_front = d3_dot(seg->hit_normal, seg->dir) < 0;
+ ASSERT(hit_front == seg->hit_front);
- if(front_face) {
- mtl = inst->object->mtl_front;
+ if(seg->hit_front) {
+ seg->hit_material = inst->object->mtl_front;
receiver_name = &inst->receiver_front;
} else {
- mtl = inst->object->mtl_back;
+ seg->hit_material = inst->object->mtl_back;
receiver_name = &inst->receiver_back;
}
@@ -335,13 +371,13 @@ hit_filter_function
}
/* register success mask */
- if(front_face) {
+ if(seg->hit_front) {
rs->success_mask |= inst->target_mask;
}
- if(mtl->type == MATERIAL_VIRTUAL) {
+ if(seg->hit_material->type == MATERIAL_VIRTUAL) {
return 1; /* Discard virtual material */
}
- rs->data.instance = inst;
+ seg->hit_instance = inst;
return 0;
}
diff --git a/src/ssol_shape.c b/src/ssol_shape.c
@@ -763,6 +763,7 @@ punched_shape_intersect_local
{
ASSERT(shape && org && dir && hint >= 0 && pt && normal && dist);
ASSERT(shape->type == SHAPE_PUNCHED);
+ ASSERT(dir[0] || dir[1] || dir[2]);
/* hits on quadrics must be recomputed more accurately */
switch (shape->quadric.type) {
case SSOL_QUADRIC_PLANE: {
diff --git a/src/ssol_solver.c b/src/ssol_solver.c
@@ -44,13 +44,17 @@ static const char* END_TEXT[] = END_TEXT__;
static FINLINE void
solstice_trace_ray(struct realisation* rs)
{
- float org[3], dir[3];
+ float org[3], dir[3], range[2] = { 0, FLT_MAX };
struct segment* seg = current_segment(rs);
f3_set_d3(org, seg->org);
f3_set_d3(dir, seg->dir);
+ fprintf(rs->data.out_stream,
+ "trace (%g:%g:%g) (%g:%g:%g)\n",
+ SPLIT3(seg->org),
+ SPLIT3(seg->dir));
S3D(scene_view_trace_ray
- (rs->data.view_rt, org, dir, seg->range, rs, &seg->hit));
+ (rs->data.view_rt, org, dir, range, rs, &seg->hit));
/* the filter function recomputes intersections on quadrics and sets seg */
}
@@ -167,77 +171,163 @@ previous_segment(struct realisation* rs)
{
size_t idx;
ASSERT(rs);
- if (!rs->s_idx) return NULL;
+ if (rs->s_idx == 0) return NULL;
idx = rs->s_idx - 1;
ASSERT(idx < darray_segment_size_get(&rs->segments));
return darray_segment_data_get(&rs->segments) + idx;
}
struct segment*
-sun_segment(struct realisation* rs)
+current_segment(struct realisation* rs)
{
struct segment* seg;
ASSERT(rs);
- seg = darray_segment_data_get(&rs->segments);
+ ASSERT(rs->s_idx < darray_segment_size_get(&rs->segments));
+ seg = darray_segment_data_get(&rs->segments) + rs->s_idx;
ASSERT(seg);
return seg;
}
-struct segment*
-current_segment(struct realisation* rs)
+static void
+check_fst_segment(const struct segment* seg)
{
- struct segment* seg;
- ASSERT(rs);
- ASSERT(rs->s_idx < darray_segment_size_get(&rs->segments));
- seg = darray_segment_data_get(&rs->segments) + rs->s_idx;
ASSERT(seg);
- return seg;
+ ASSERT_NAN(seg->dir, 3);
+ /* hit is not checked and can be used only for debugging purpose */
+ NCHECK(seg->hit_front, 99);
+ ASSERT(seg->hit_instance);
+ ASSERT(seg->hit_material);
+ ASSERT_NAN(seg->hit_normal, 3);
+ ASSERT_NAN(seg->hit_pos, 3);
+ if (seg->on_punched) ASSERT_NAN(seg->hit_pos_local, 3);
+ NCHECK(seg->on_punched, 99);
+ ASSERT_NAN(seg->org, 3);
+ ASSERT(seg->weight > 0);
+}
+
+static void
+check_segment(const struct segment* seg)
+{
+ check_fst_segment(seg);
+ ASSERT(seg->self_instance);
+ NCHECK(seg->self_front, 99);
+ /* hit filter is supposed to work properly */
+ ASSERT(seg->self_instance != seg->hit_instance
+ || seg->self_front != seg->hit_front);
}
res_T
-next_segment(struct realisation* rs)
+setup_next_segment(struct realisation* rs)
{
res_T res = RES_OK;
+ const struct segment* prev;
+ const struct solver_data* data;
+ struct segment* seg;
ASSERT(rs);
- ++rs->s_idx;
- if (rs->s_idx >= darray_segment_size_get(&rs->segments)) {
+
+ if (++rs->s_idx >= darray_segment_size_get(&rs->segments)) {
res = darray_segment_resize(&rs->segments, rs->s_idx + 1);
if (res != RES_OK) return res;
}
- reset_segment(current_segment(rs));
- return RES_OK;
+ prev = previous_segment(rs);
+ seg = current_segment(rs);
+ data = &rs->data;
+ ASSERT(seg && prev && data);
+
+ if(rs->s_idx == 1)
+ check_fst_segment(prev);
+ else
+ check_segment(prev);
+ reset_segment(seg);
+ seg->self_instance = prev->hit_instance;
+ seg->self_front = prev->hit_front;
+ d3_set(seg->org, prev->hit_pos);
+
+ res = material_shade(prev->hit_material, &data->fragment, rs->freq, data->brdfs);
+ if (res != RES_OK) {
+ rs->end = TERM_ERR;
+ return res;
+ }
+
+ seg->weight = prev->weight
+ * brdf_composite_sample(
+ data->brdfs, data->rng, prev->dir, data->fragment.Ns, seg->dir);
+ return res;
}
void
reset_segment(struct segment* seg)
{
ASSERT(seg);
- seg->range[0] = 0;
- seg->range[1] = FLT_MAX;
+#ifndef NDEBUG
+ d3_splat(seg->dir, NAN);
+ seg->hit = S3D_HIT_NULL;
+ seg->hit_front = 99;
+ seg->hit_instance = NULL;
+ seg->hit_material = NULL;
+ d3_splat(seg->hit_normal, NAN);
+ d3_splat(seg->hit_pos, NAN);
+ d3_splat(seg->hit_pos_local, NAN);
+ seg->on_punched = 99;
+ d3_splat(seg->org, NAN);
+ seg->self_instance = NULL;
+ seg->self_front = 99;
+ seg->weight = NAN;
+#else
seg->hit = S3D_HIT_NULL;
+#endif
}
static void
reset_starting_point(struct starting_point* start)
{
ASSERT(start);
- start->primitive = S3D_PRIMITIVE_NULL;
+#ifndef NDEBUG
+ start->cos_sun = NAN;
+ start->front_exposed = 99;
+ start->instance = NULL;
+ start->material = NULL;
+ d3_splat(start->normal, NAN);
+ start->on_punched = 99;
+ d3_splat(start->pos, NAN);
+ d3_splat(start->pos_local, NAN);
+ start->sampl_primitive = S3D_PRIMITIVE_NULL;
+ d3_splat(start->sundir, NAN);
+ start->uv[0] = start->uv[1] = NAN;
+#else
+ start->sampl_primitive = S3D_PRIMITIVE_NULL;
+#endif
+}
+
+static void
+check_starting_point(const struct starting_point* start)
+{
+ ASSERT(start);
+ ASSERT(start->cos_sun > 0); /* normal is flipped facing in_dir */
+ NCHECK(start->front_exposed, 99);
+ ASSERT(start->instance);
+ ASSERT(start->material);
+ ASSERT_NAN(start->normal, 3);
+ NCHECK(start->on_punched, 99);
+ ASSERT_NAN(start->pos, 3);
+ if(start->on_punched) ASSERT_NAN(start->pos_local, 3);
+ ASSERT(!S3D_PRIMITIVE_EQ(&start->sampl_primitive, &S3D_PRIMITIVE_NULL));
+ ASSERT_NAN(start->sundir, 3);
+ ASSERT_NAN(start->uv, 2);
}
static void
reset_realisation(size_t cpt, struct realisation* rs)
{
rs->s_idx = 0;
- rs->s_idx = 0;
rs->end = TERM_NONE;
rs->mode = MODE_STD;
rs->rs_id = cpt;
rs->success_mask = 0;
reset_starting_point(&rs->start);
brdf_composite_clear(rs->data.brdfs);
- rs->data.instance = NULL;
- /* reset sun segment (always used) */
- reset_segment(sun_segment(rs));
+ /* reset first segment (always used) */
+ reset_segment(current_segment(rs));
}
static res_T
@@ -284,22 +374,6 @@ release_realisation(struct realisation* rs)
darray_segment_release(&rs->segments);
}
-static INLINE struct ssol_material*
-get_material_from_hit
- (struct ssol_scene* scene,
- const double dir[3],
- const struct s3d_hit* hit)
-{
- struct ssol_instance* inst;
- float dirf[3];
- int front_face;
- ASSERT(scene && hit);
- inst = *htable_instance_find(&scene->instances_rt, &hit->prim.inst_id);
- f3_set_d3(dirf, dir);
- front_face = f3_dot(dirf, hit->normal) < 0.f;
- return front_face ? inst->object->mtl_front : inst->object->mtl_back;
-}
-
/* partial setting of rs->start
* front_exposed, cos_sun will be set later
* material is set to NULL and will be set later
@@ -308,51 +382,66 @@ static void
sample_point_on_primary_mirror(struct realisation* rs)
{
struct s3d_attrib attrib;
- struct ssol_object* object;
+ struct ssol_shape* shape;
float r1, r2, r3;
struct solver_data* data;
struct s3d_primitive sampl_prim;
+ struct starting_point* start;
+ ASSERT(rs);
data = &rs->data;
ASSERT(data->rng && data->view_samp && data->scene);
+ start = &rs->start;
/* sample a point on a primary mirror's carving */
r1 = ssp_rng_canonical_float(data->rng);
r2 = ssp_rng_canonical_float(data->rng);
r3 = ssp_rng_canonical_float(data->rng);
- S3D(scene_view_sample(data->view_samp, r1, r2, r3, &sampl_prim, rs->start.uv));
- S3D(primitive_get_attrib(&sampl_prim, S3D_POSITION, rs->start.uv, &attrib));
+ S3D(scene_view_sample(data->view_samp, r1, r2, r3, &sampl_prim, start->uv));
+ S3D(primitive_get_attrib(&sampl_prim, S3D_POSITION, start->uv, &attrib));
CHECK(attrib.type, S3D_FLOAT3);
- d3_set_f3(rs->start.pos, attrib.value);
+ d3_set_f3(start->pos, attrib.value);
/* find the solstice shape and project the sampled point on the mirror */
- rs->start.instance = *htable_instance_find
+ start->instance = *htable_instance_find
(&data->scene->instances_samp, &sampl_prim.inst_id);
- object = rs->start.instance->object;
- switch (object->shape->type) {
- case SHAPE_MESH:
- /* no projection needed */
- /* set normal */
- S3D(primitive_get_attrib(&sampl_prim, S3D_GEOMETRY_NORMAL, rs->start.uv, &attrib));
- CHECK(attrib.type, S3D_FLOAT3);
- d3_set_f3(rs->start.normal, attrib.value);
- d3_normalize(rs->start.normal, rs->start.normal);
- /* to avoid self intersect */
- rs->start.primitive = sampl_prim; /* FIXME: cannot use a sampling primitive! */
- break;
- case SHAPE_PUNCHED:
- /* project the sampled point on the quadric */
- punched_shape_set_z_local(object->shape, rs->start.pos);
- /* compute exact normal */
- punched_shape_set_normal_local(object->shape, rs->start.pos, rs->start.normal);
- /* cannot self intersect as the sampled mesh is not raytraced */
- rs->start.primitive = S3D_PRIMITIVE_NULL;
- break;
- default: FATAL("Unreachable code.\n"); break;
+ start->sampl_primitive = sampl_prim;
+ shape = start->instance->object->shape;
+ start->on_punched = (shape->type == SHAPE_PUNCHED);
+ switch (shape->type) {
+ case SHAPE_MESH: {
+ /* no projection needed */
+ /* set normal */
+ S3D(primitive_get_attrib(&sampl_prim, S3D_GEOMETRY_NORMAL, start->uv, &attrib));
+ CHECK(attrib.type, S3D_FLOAT3);
+ d3_set_f3(start->normal, attrib.value);
+ d3_normalize(start->normal, start->normal);
+ break;
+ }
+ case SHAPE_PUNCHED: {
+ const double* transform = start->instance->transform;
+ double tr[9];
+ /* project the sampled point on the quadric */
+ d33_inverse(tr, transform);
+ d3_set(start->pos_local, start->pos);
+ d3_sub(start->pos_local, start->pos_local, transform + 9);
+ d33_muld3(start->pos_local, tr, start->pos_local);
+ punched_shape_set_z_local(shape, start->pos_local);
+ /* transform point to world */
+ d33_muld3(start->pos, transform, start->pos_local);
+ d3_add(start->pos, transform + 9, start->pos);
+ /* compute exact normal */
+ punched_shape_set_normal_local(shape, start->pos_local, start->normal);
+ /* transform normal to world */
+ d33_invtrans(tr, transform);
+ d33_muld3(start->normal, tr, start->normal);
+ break;
+ }
+ default: FATAL("Unreachable code.\n"); break;
}
/* TODO: transform everything to world coordinate */
/* will be defined later, depending on wich side sees the sun */
- rs->start.material = NULL;
+ start->material = NULL;
}
static void
@@ -376,48 +465,77 @@ sample_wavelength(struct realisation* rs)
static int
receive_sunlight(struct realisation* rs)
{
- struct segment* seg = sun_segment(rs);
+ struct segment* seg;
const struct str* receiver_name = NULL;
- const struct ssol_sun* sun = rs->data.scene->sun;
+ const struct ssol_sun* sun;
+ struct starting_point* start;
- ASSERT(d3_is_normalized(rs->start.sundir));
- ASSERT(d3_is_normalized(rs->start.normal));
- /* search for occlusions from starting point */
- d3_set(seg->dir, rs->start.sundir);
+ ASSERT(rs && rs->s_idx == 0);
+ seg = current_segment(rs);
+ sun = rs->data.scene->sun;
+ start = &rs->start;
+ ASSERT(d3_is_normalized(start->sundir));
+ ASSERT(d3_is_normalized(start->normal));
+
+ /* find which material/face is exposed to sun */
+ start->cos_sun = d3_dot(start->normal, start->sundir);
+ start->front_exposed = start->cos_sun < 0;
+ if (start->front_exposed) {
+ start->cos_sun *= -1;
+ start->material = start->instance->object->mtl_front;
+ }
+ else {
+ start->material = start->instance->object->mtl_back;
+ d3_muld(start->normal, start->normal, -1);
+ }
+ /* start must now be complete */
+ check_starting_point(start);
+
+ /* start filling seg from starting point */
+ /* seg is set to cast a ray from the sampled point to the sun */
+ d3_set(seg->dir, start->sundir);
d3_muld(seg->dir, seg->dir, -1);
- d3_set(seg->org, rs->start.pos);
- seg->hit.prim = rs->start.primitive;
- /* range as already been set */
- ASSERT(current_segment(rs) == sun_segment(rs));
+ d3_set(seg->org, start->pos);
+ seg->self_instance = start->instance;
+ seg->self_front = start->front_exposed;
+
+ /* search for occlusions from starting point */
+ ASSERT(rs->s_idx == 0); /* sun segment */
solstice_trace_ray(rs);
if (!S3D_HIT_NONE(&seg->hit)) {
rs->end = TERM_SHADOW;
return 0;
}
- /* find which material/face is exposed to sun */
- rs->start.cos_sun = d3_dot(rs->start.normal, rs->start.sundir);
- rs->start.front_exposed = rs->start.cos_sun < 0;
- if(rs->start.front_exposed) {
- rs->start.cos_sun *= -1;
- rs->start.material = rs->start.instance->object->mtl_front;
- }
- else {
- rs->start.material = rs->start.instance->object->mtl_back;
- d3_muld(rs->start.normal, rs->start.normal, -1);
- }
+ /* fill segment to allow standard propagation
+ * pretend the ray was cast in the opposite direction */
+ d3_set(seg->dir, start->sundir);
+ d3_sub(seg->org, seg->org, seg->dir);
+ /* hit_front will be set from the next impact (if any) */
+ /* hit_instance will be set from the next impact (if any) */
+ seg->hit_material = start->material;
+ d3_set(seg->hit_normal, start->normal);
+ d3_set(seg->hit_pos, start->pos);
+ d3_set(seg->hit_pos_local, start->pos_local);
+ seg->on_punched = start->on_punched;
+ seg->hit_instance = seg->self_instance;
+ seg->self_instance = NULL;
+ seg->hit_front = seg->self_front;
+ seg->self_front = 99;
seg->weight = sun->dni * rs->start.cos_sun;
+ ASSERT(seg->weight > 0);
/* fill fragment from starting point */
/* FIXME: is fragment->Ns orientation correct when has_normal && back_face??? */
- surface_fragment_setup(&rs->data.fragment, seg->org, rs->start.sundir,
- rs->start.normal, &rs->start.primitive, rs->start.uv);
+ surface_fragment_setup(&rs->data.fragment, seg->hit_pos, seg->dir,
+ /* FIXME: must provide a raytracing prim, not a sampling one! */
+ seg->hit_normal, &start->sampl_primitive, start->uv);
/* if the sampled instance is a receiver, register the sampled point */
- if(rs->start.front_exposed) {
- receiver_name = &rs->start.instance->receiver_front;
+ if(start->front_exposed) {
+ receiver_name = &start->instance->receiver_front;
} else {
- receiver_name = &rs->start.instance->receiver_back;
+ receiver_name = &start->instance->receiver_back;
}
if(!str_is_empty(receiver_name)) {
/* normal orientation has already been checked */
@@ -430,56 +548,15 @@ receive_sunlight(struct realisation* rs)
seg->weight,
SPLIT3(seg->hit_pos),
SPLIT3(seg->dir),
- SPLIT2(rs->start.uv));
+ SPLIT2(start->uv));
}
/* register success mask (normal orientation has already been checked) */
- rs->success_mask |= rs->start.instance->target_mask;
-
- /* restore self intersect information for further visibility test
- * (previous call to trace_ray overwrote prim) */
- seg->hit.prim = rs->start.primitive;
-
+ rs->success_mask |= start->instance->target_mask;
+
return 1;
}
-static res_T
-set_output_pos_and_dir(struct realisation* rs)
-{
- struct ssol_material* material;
- struct segment* seg = current_segment(rs);
- struct segment* prev = previous_segment(rs);
- struct ssol_scene* scene = rs->data.scene;
- double* dir;
- int fst_segment;
- res_T res = RES_OK;
-
- /* next_segment should have been called */
- ASSERT(prev);
-
- fst_segment = (prev == sun_segment(rs));
-
- if (fst_segment) {
- d3_set(seg->org, rs->start.pos);
- material = rs->start.material;
- } else {
- d3_set(seg->org, prev->hit_pos);
- material = get_material_from_hit(scene, prev->dir, &prev->hit);
- }
- CHECK(material->type, MATERIAL_MIRROR);
- res = material_shade(material, &rs->data.fragment, rs->freq, rs->data.brdfs);
- if (res != RES_OK) {
- rs->end = TERM_ERR;
- return res;
- }
-
- dir = fst_segment ? rs->start.sundir : prev->dir;
- seg->weight = prev->weight
- * brdf_composite_sample
- (rs->data.brdfs, rs->data.rng, dir, rs->data.fragment.Ns, seg->dir);
- return res;
-}
-
static void
propagate(struct realisation* rs)
{
@@ -491,12 +568,9 @@ propagate(struct realisation* rs)
rs->end = TERM_MISSING;
return;
}
- /* should not stop on a virtual surface */
- ASSERT(get_material_from_hit(rs->data.scene, seg->dir, &seg->hit)->type
- != MATERIAL_VIRTUAL);
- /* fill fragment from hit and loop */
- d3_add(seg->hit_pos, seg->org, d3_muld(seg->hit_pos, seg->dir, seg->dist));
+ /* fill fragment and loop */
+ check_segment(seg);
surface_fragment_setup(&rs->data.fragment, seg->hit_pos, seg->dir,
seg->hit_normal, &seg->hit.prim, seg->hit.uv);
}
@@ -532,24 +606,19 @@ ssol_solve
if (receive_sunlight(&rs)) {
/* start propagating from mirror */
do {
- if (RES_OK != next_segment(&rs)) {
+ if (RES_OK != setup_next_segment(&rs)) {
rs.end = TERM_ERR;
} else {
- /* set next segment and propagate */
- set_output_pos_and_dir(&rs);
propagate(&rs);
}
} while (rs.end == TERM_NONE);
}
/* propagation ended */
- if (rs.success_mask) {
- fprintf(output, "Realization %u succeeded: 0x%0x\n",
- (unsigned)r, rs.success_mask);
- } else {
- fprintf(output, "Realization %u failed: %s\n",
- (unsigned)r, END_TEXT[rs.end]);
- }
+ fprintf(output, "Realization %u success mask: 0x%0x\n",
+ (unsigned)r, rs.success_mask);
+ fprintf(output, "Realization %u end: %s\n\n",
+ (unsigned)r, END_TEXT[rs.end]);
}
exit:
diff --git a/src/ssol_solver_c.h b/src/ssol_solver_c.h
@@ -57,25 +57,32 @@ enum realisation_mode {
};
struct segment {
+ const struct ssol_instance* hit_instance;
+ const struct ssol_instance* self_instance;
+ const struct ssol_material* hit_material;
double weight;
- float range[2];
struct s3d_hit hit;
double org[3], dir[4];
double hit_pos[3];
+ double hit_pos_local[3]; /* in local coordinate, only set on punched shapes */
double hit_normal[3];
- double dist;
+ char hit_front;
+ char self_front;
+ char on_punched; /* is the hit on a punched shape? */
};
struct starting_point {
- struct ssol_instance* instance;
- struct ssol_material* material;
- struct s3d_primitive primitive;
+ const struct ssol_instance* instance;
+ const struct ssol_material* material;
+ struct s3d_primitive sampl_primitive;
double sundir[3];
double pos[3];
- double normal[3];
+ double pos_local[3]; /* in local coordinate, only set on quadrics */
+ double normal[3]; /* oriented to face the sun*/
double cos_sun;
float uv[2];
- int front_exposed;
+ char front_exposed;
+ char on_punched; /* is the point on a punched shape? */
};
#include <rsys/dynamic_array.h>
@@ -96,7 +103,6 @@ struct solver_data {
struct ssp_ranst_piecewise_linear* sun_spectrum_ran;
/* Tmp data used for propagation */
struct brdf_composite* brdfs;
- struct ssol_instance* instance;
struct surface_fragment fragment;
};
@@ -113,7 +119,7 @@ struct realisation {
};
#define SOLVER_DATA_NULL__ \
- {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, SURFACE_FRAGMENT_NULL__}
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
static const struct solver_data SOLVER_DATA_NULL = SOLVER_DATA_NULL__;
extern LOCAL_SYM res_T
@@ -126,13 +132,10 @@ extern LOCAL_SYM struct segment*
previous_segment(struct realisation* rs);
extern LOCAL_SYM struct segment*
-sun_segment(struct realisation* rs);
-
-extern LOCAL_SYM struct segment*
current_segment(struct realisation* rs);
extern LOCAL_SYM res_T
-next_segment(struct realisation* rs);
+setup_next_segment(struct realisation* rs);
extern LOCAL_SYM void
reset_segment(struct segment* seg);
diff --git a/src/test_ssol_solver2.c b/src/test_ssol_solver2.c
@@ -0,0 +1,177 @@
+/* Copyright (C) CNRS 2016
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "ssol.h"
+#include "test_ssol_utils.h"
+#include "test_ssol_geometries.h"
+#include "test_ssol_materials.h"
+#include "test_ssol_postprocess.h"
+
+#include "ssol_solver_c.h"
+
+#include <rsys/logger.h>
+#include <rsys/double33.h>
+
+#include <star/s3d.h>
+#include <star/ssp.h>
+
+/*******************************************************************************
+ * Test main program
+ ******************************************************************************/
+int
+main(int argc, char** argv)
+{
+ struct logger logger;
+ struct mem_allocator allocator;
+ struct ssol_device* dev;
+ struct ssp_rng* rng;
+ struct ssol_scene* scene;
+ struct ssol_shape* square;
+ struct ssol_vertex_data attribs[1];
+ struct ssol_shape* quad_square;
+ struct ssol_carving carving;
+ struct ssol_quadric quadric;
+ struct ssol_punched_surface punched;
+ struct ssol_material* m_mtl;
+ struct ssol_material* v_mtl;
+ struct ssol_mirror_shader shader;
+ struct ssol_object* m_object;
+ struct ssol_object* s_object;
+ struct ssol_object* t_object;
+ struct ssol_instance* heliostat;
+ struct ssol_instance* secondary;
+ struct ssol_instance* target;
+ struct ssol_sun* sun;
+ struct ssol_spectrum* spectrum;
+ double dir[3];
+ double frequencies[3] = { 1, 2, 3 };
+ double intensities[3] = { 1, 0.8, 1 };
+ double transform1[12]; /* 3x4 column major matrix */
+ double transform2[12]; /* 3x4 column major matrix */
+ double polygon[] = { -1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0 };
+ const size_t npolygon_verts = sizeof(polygon) / sizeof(double[2]);
+
+ (void) argc, (void) argv;
+
+ d33_splat(transform1, 0);
+ d3_splat(transform1 + 9, 0);
+ d33_rotation_pitch(transform1, PI); /* flip faces: invert normal */
+ transform1[9] = 2; /* +2 offset along X axis */
+ transform1[11] = 2; /* +2 offset along Z axis */
+
+ d33_set_identity(transform2);
+ d3_splat(transform2 + 9, 0);
+ transform2[9] = 4; /* +4 offset along X axis */
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ CHECK(logger_init(&allocator, &logger), RES_OK);
+ logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL);
+ logger_set_stream(&logger, LOG_ERROR, log_stream, NULL);
+ logger_set_stream(&logger, LOG_WARNING, log_stream, NULL);
+
+ CHECK(ssol_device_create
+ (&logger, &allocator, SSOL_NTHREADS_DEFAULT, 0, &dev), RES_OK);
+
+ CHECK(ssp_rng_create(&allocator, &ssp_rng_threefry, &rng), RES_OK);
+ CHECK(ssol_spectrum_create(dev, &spectrum), RES_OK);
+ CHECK(ssol_spectrum_setup(spectrum, frequencies, intensities, 3), RES_OK);
+ CHECK(ssol_sun_create_directional(dev, &sun), RES_OK);
+ CHECK(ssol_sun_set_direction(sun, d3(dir, 1, 0, -1)), RES_OK);
+ CHECK(ssol_sun_set_spectrum(sun, spectrum), RES_OK);
+ CHECK(ssol_sun_set_dni(sun, 1000), RES_OK);
+ CHECK(ssol_scene_create(dev, &scene), RES_OK);
+ CHECK(ssol_scene_attach_sun(scene, sun), RES_OK);
+
+ CHECK(ssol_solve(NULL, rng, 10, stdout), RES_BAD_ARG);
+ CHECK(ssol_solve(scene, NULL, 10, stdout), RES_BAD_ARG);
+ CHECK(ssol_solve(scene, rng, 0, stdout), RES_BAD_ARG);
+ CHECK(ssol_solve(scene, rng, 10, NULL), RES_BAD_ARG);
+ CHECK(ssol_solve(scene, rng, 10, stdout), RES_BAD_ARG); /* no geometry */
+
+ /* create scene content */
+
+ CHECK(ssol_shape_create_mesh(dev, &square), RES_OK);
+ attribs[0].usage = SSOL_POSITION;
+ attribs[0].get = get_position;
+ CHECK(ssol_mesh_setup(square, square_walls_ntris, get_ids,
+ square_walls_nverts, attribs, 1, (void*)&square_walls_desc), RES_OK);
+
+ CHECK(ssol_shape_create_punched_surface(dev, &quad_square), RES_OK);
+ carving.get = get_polygon_vertices;
+ carving.operation = SSOL_AND;
+ carving.nb_vertices = npolygon_verts;
+ carving.context = &polygon;
+ quadric.type = SSOL_QUADRIC_PLANE;
+ punched.nb_carvings = 1;
+ punched.quadric = &quadric;
+ punched.carvings = &carving;
+ CHECK(ssol_punched_surface_setup(quad_square, &punched), RES_OK);
+
+ CHECK(ssol_material_create_mirror(dev, &m_mtl), RES_OK);
+ shader.normal = get_shader_normal;
+ shader.reflectivity = get_shader_reflectivity;
+ shader.roughness = get_shader_roughness;
+ CHECK(ssol_mirror_set_shader(m_mtl, &shader), RES_OK);
+ CHECK(ssol_material_create_virtual(dev, &v_mtl), RES_OK);
+
+ CHECK(ssol_object_create(dev, square, m_mtl, m_mtl, &m_object), RES_OK);
+ CHECK(ssol_object_instantiate(m_object, &heliostat), RES_OK);
+ CHECK(ssol_instance_set_receiver(heliostat, "miroir", NULL), RES_OK);
+ CHECK(ssol_instance_set_target_mask(heliostat, 0x1), RES_OK);
+ CHECK(ssol_scene_attach_instance(scene, heliostat), RES_OK);
+
+ CHECK(ssol_object_create(dev, quad_square, m_mtl, m_mtl, &s_object), RES_OK);
+ CHECK(ssol_object_instantiate(s_object, &secondary), RES_OK);
+ CHECK(ssol_instance_set_receiver(secondary, "secondaire", NULL), RES_OK);
+ CHECK(ssol_instance_set_transform(secondary, transform1), RES_OK);
+ CHECK(ssol_instance_set_target_mask(secondary, 0x2), RES_OK);
+ CHECK(ssol_scene_attach_instance(scene, secondary), RES_OK);
+
+ CHECK(ssol_object_create(dev, square, v_mtl, v_mtl, &t_object), RES_OK);
+ CHECK(ssol_object_instantiate(t_object, &target), RES_OK);
+ CHECK(ssol_instance_set_transform(target, transform2), RES_OK);
+ CHECK(ssol_instance_set_receiver(target, "cible", NULL), RES_OK);
+ CHECK(ssol_instance_set_target_mask(target, 0x4), RES_OK);
+ CHECK(ssol_scene_attach_instance(scene, target), RES_OK);
+
+ CHECK(ssol_solve(scene, rng, 20, stdout), RES_OK);
+
+ /* free data */
+
+ CHECK(ssol_instance_ref_put(heliostat), RES_OK);
+ CHECK(ssol_instance_ref_put(secondary), RES_OK);
+ CHECK(ssol_instance_ref_put(target), RES_OK);
+ CHECK(ssol_object_ref_put(m_object), RES_OK);
+ CHECK(ssol_object_ref_put(s_object), RES_OK);
+ CHECK(ssol_object_ref_put(t_object), RES_OK);
+ CHECK(ssol_shape_ref_put(square), RES_OK);
+ CHECK(ssol_shape_ref_put(quad_square), RES_OK);
+ CHECK(ssol_material_ref_put(m_mtl), RES_OK);
+ CHECK(ssol_material_ref_put(v_mtl), RES_OK);
+ CHECK(ssol_device_ref_put(dev), RES_OK);
+ CHECK(ssol_scene_ref_put(scene), RES_OK);
+ CHECK(ssp_rng_ref_put(rng), RES_OK);
+ CHECK(ssol_spectrum_ref_put(spectrum), RES_OK);
+ CHECK(ssol_sun_ref_put(sun), RES_OK);
+
+ logger_release(&logger);
+
+ check_memory_allocator(&allocator);
+ mem_shutdown_proxy_allocator(&allocator);
+ CHECK(mem_allocated_size(), 0);
+
+ return 0;
+}