solstice-solver

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

commit cdd78511c058bdf8f8cb030ca84517e0cf67f9cf
parent 83d90029a9bd49c1938ad5e7c3e64fbb57f928a1
Author: Christophe Coustet <christophe.coustet@meso-star.com>
Date:   Fri, 22 Jul 2016 17:17:24 +0200

Additions to the solver.

Diffstat:
Msrc/ssol.h | 2+-
Msrc/ssol_material.c | 73+++++++++++++++++++++++++++++++++----------------------------------------
Msrc/ssol_material_c.h | 8+++++---
Msrc/ssol_scene.c | 47++++++++++++++++++++++++++++++++++++++++++-----
Msrc/ssol_scene_c.h | 18++++++++++++++++++
Msrc/ssol_solver.c | 431+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/ssol_solver_c.h | 13+++++++------
Msrc/ssol_sun_c.h | 6++++++
Msrc/test_ssol_solver.c | 32++++++++++++++++++++++++++++++++
9 files changed, 499 insertions(+), 131 deletions(-)

diff --git a/src/ssol.h b/src/ssol.h @@ -510,7 +510,7 @@ ssol_sun_set_buie_param ******************************************************************************/ SSOL_API res_T ssol_solve - (const struct ssol_scene* scn, + (struct ssol_scene* scn, struct ssp_rng* rng, const size_t realisations_count, FILE* output); diff --git a/src/ssol_material.c b/src/ssol_material.c @@ -21,6 +21,7 @@ #include "ssol_device_c.h" #include <rsys/double3.h> +#include <rsys/double2.h> #include <rsys/float3.h> #include <rsys/float33.h> #include <rsys/ref_count.h> @@ -190,72 +191,64 @@ ssol_material_create_virtual ******************************************************************************/ void surface_fragment_setup - (struct surface_fragment* fragment, - const float ray_org[3], - const float ray_dir[3], - const struct s3d_hit* hit) +(struct surface_fragment* fragment, + const float pos[3], + const float dir[3], + const float normal[3], + const struct s3d_primitive* primitive, + const float uv[2]) { struct s3d_attrib attr; - double len; char has_texcoord, has_normal; - ASSERT(fragment && ray_org && ray_dir && hit); + ASSERT(fragment && pos && dir && primitive && uv); /* Setup the incoming direction */ - fragment->dir[0] = ray_dir[0]; - fragment->dir[1] = ray_dir[1]; - fragment->dir[2] = ray_dir[2]; + d3_set_f3(fragment->dir, dir); /* Setup the surface position */ - fragment->pos[0] = ray_org[0] + ray_dir[0] * hit->distance; - fragment->pos[1] = ray_org[1] + ray_dir[1] * hit->distance; - fragment->pos[2] = ray_org[2] + ray_dir[2] * hit->distance; + d3_set_f3(fragment->pos, pos); /* Normalize the geometry normal */ - len = sqrt(f3_len(hit->normal)); - fragment->Ng[0] = hit->normal[0] / len; - fragment->Ng[1] = hit->normal[1] / len; - fragment->Ng[2] = hit->normal[2] / len; + d3_set_f3(fragment->Ng, normal); + d3_normalize(fragment->Ng, fragment->Ng); /* Retrieve the tex coord */ - S3D(primitive_has_attrib(&hit->prim, SSOL_TO_S3D_TEXCOORD, &has_texcoord)); - if(!has_texcoord) { - fragment->uv[0] = hit->uv[0]; - fragment->uv[1] = hit->uv[1]; - } else { - S3D(primitive_get_attrib(&hit->prim, SSOL_TO_S3D_TEXCOORD, hit->uv, &attr)); + S3D(primitive_has_attrib(primitive, SSOL_TO_S3D_TEXCOORD, &has_texcoord)); + if (!has_texcoord) { + d2_set_f2(fragment->uv, uv); + } + else { + S3D(primitive_get_attrib(primitive, SSOL_TO_S3D_TEXCOORD, uv, &attr)); ASSERT(attr.type == S3D_FLOAT2); - fragment->uv[0] = attr.value[0]; - fragment->uv[1] = attr.value[1]; + d2_set_f2(fragment->uv, attr.value); } /* Retrieve and normalize the shading normal in world space */ - S3D(primitive_has_attrib(&hit->prim, SSOL_TO_S3D_NORMAL, &has_normal)); - if(!has_normal) { + S3D(primitive_has_attrib(primitive, SSOL_TO_S3D_NORMAL, &has_normal)); + if (!has_normal) { d3_set(fragment->Ns, fragment->Ng); - } else { + } + else { float transform[12]; float vec[3]; - S3D(primitive_get_attrib(&hit->prim, SSOL_TO_S3D_NORMAL, hit->uv, &attr)); + S3D(primitive_get_attrib(primitive, SSOL_TO_S3D_NORMAL, uv, &attr)); ASSERT(attr.type == S3D_FLOAT3); - S3D(primitive_get_transform(&hit->prim, transform)); + S3D(primitive_get_transform(primitive, transform)); /* Check that transform is not "identity" */ - if(!f3_eq(transform + 0, f3(vec, 1.f, 0.f, 0.f)) - && !f3_eq(transform + 3, f3(vec, 0.f, 1.f, 0.f)) - && !f3_eq(transform + 6, f3(vec, 0.f, 0.f, 1.f))) { + if (!f3_eq(transform + 0, f3(vec, 1.f, 0.f, 0.f)) + && !f3_eq(transform + 3, f3(vec, 0.f, 1.f, 0.f)) + && !f3_eq(transform + 6, f3(vec, 0.f, 0.f, 1.f))) { /* Transform the normal in world space, i.e. multiply it by the inverse - * transpose of the "object to world" primitive matrix. Since the affine - * part of the 3x4 transformation matrix does not influence the normal - * transformation, use the linear part only. */ + * transpose of the "object to world" primitive matrix. Since the affine + * part of the 3x4 transformation matrix does not influence the normal + * transformation, use the linear part only. */ f33_invtrans(transform, transform); f33_mulf3(attr.value, transform, attr.value); } - - len = sqrt(f3_len(attr.value)); - fragment->Ns[0] = attr.value[0] / len; - fragment->Ns[1] = attr.value[1] / len; - fragment->Ns[2] = attr.value[2] / len; + d3_set_f3(fragment->Ns, attr.value); + d3_normalize(fragment->Ns, fragment->Ns); } } diff --git a/src/ssol_material_c.h b/src/ssol_material_c.h @@ -58,9 +58,11 @@ material_get_type(const struct ssol_material* mtl) extern LOCAL_SYM void surface_fragment_setup (struct surface_fragment* fragment, - const float ray_org[3], - const float ray_dir[3], - const struct s3d_hit* hit); + const float pos[3], + const float dir[3], + const float normal[3], + const struct s3d_primitive* primitive, + const float uv[2]); extern LOCAL_SYM res_T material_shade diff --git a/src/ssol_scene.c b/src/ssol_scene.c @@ -27,6 +27,7 @@ #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> #include <rsys/rsys.h> +#include <rsys/float3.h> /* Define the htable_instance data structure */ #define HTABLE_NAME instance @@ -38,6 +39,7 @@ struct ssol_scene { struct htable_instance instances; struct s3d_scene* s3d_scn; + struct s3d_scene* s3d_sampling_scn; struct ssol_sun* sun; struct ssol_device* dev; @@ -56,7 +58,8 @@ scene_release(ref_T* ref) dev = scene->dev; ASSERT(dev && dev->allocator); SSOL(scene_clear(scene)); - if(scene->s3d_scn) S3D(scene_ref_put(scene->s3d_scn)); + if (scene->s3d_scn) S3D(scene_ref_put(scene->s3d_scn)); + if (scene->s3d_sampling_scn) S3D(scene_ref_put(scene->s3d_sampling_scn)); if(scene->sun) SSOL(sun_ref_put(scene->sun)); htable_instance_release(&scene->instances); MEM_RM(dev->allocator, scene); @@ -89,7 +92,10 @@ ssol_scene_create ref_init(&scene->ref); res = s3d_scene_create(dev->s3d, &scene->s3d_scn); - if(res != RES_OK) goto error; + if (res != RES_OK) goto error; + + res = s3d_scene_create(dev->s3d, &scene->s3d_sampling_scn); + if (res != RES_OK) goto error; exit: if (out_scene) *out_scene = scene; @@ -233,6 +239,13 @@ scene_get_s3d_scene(const struct ssol_scene* scn) return scn->s3d_scn; } +struct s3d_scene* +scene_get_s3d_sampling_scn(const struct ssol_scene* scn) +{ + ASSERT(scn); + return scn->s3d_sampling_scn; +} + struct ssol_object_instance* scene_get_object_instance_from_s3d_hit (struct ssol_scene* scn, @@ -256,7 +269,7 @@ hit_filter_function void* ray_data, void* filter_data) { - struct ray_data* rdata; + struct ray_data* rdata = ray_data; struct ssol_object_instance* instance; struct ssol_material* material; const char* receiver_name; @@ -265,7 +278,6 @@ hit_filter_function if(!ray_data) return 0; - rdata = ray_data; if(S3D_PRIMITIVE_EQ(&hit->prim, &rdata->prim_from)) return 1; /* Discard self intersection */ @@ -275,7 +287,9 @@ hit_filter_function receiver_name = object_instance_get_receiver_name(instance); if(receiver_name) { struct surface_fragment frag; - surface_fragment_setup(&frag, org, dir, hit); + float tmp[3]; + f3_set(tmp, f3_add(tmp, org, f3_mulf(tmp, dir, hit->distance))); + surface_fragment_setup(&frag, tmp, dir, hit->normal, &hit->prim, hit->uv); fprintf(rdata->stream, "%s %u %u %g %g (%g:%g:%g) (%g:%g:%g) (%g:%g)\n", receiver_name, rdata->path_id, @@ -295,3 +309,26 @@ hit_filter_function return 0; } +struct ssol_sun* +scene_get_sun + (struct ssol_scene* scn) +{ + ASSERT(scn); + return scn->sun; +} + +struct ssol_device* + scene_get_device + (struct ssol_scene* scn) +{ + ASSERT(scn); + return scn->dev; +} + +struct htable_instance* + scene_get_instances + (struct ssol_scene* scn) +{ + ASSERT(scn); + return &scn->instances; +} diff --git a/src/ssol_scene_c.h b/src/ssol_scene_c.h @@ -22,15 +22,33 @@ struct s3d_hit; struct s3d_scene; struct ssol_object_instance; struct ssol_scene; +struct ssol_sun; +struct ssol_device; extern LOCAL_SYM struct s3d_scene* scene_get_s3d_scene (const struct ssol_scene* scn); +extern LOCAL_SYM struct s3d_scene* +scene_get_s3d_sampling_scn +(const struct ssol_scene* scn); + extern LOCAL_SYM struct ssol_object_instance* scene_get_object_instance_from_s3d_hit (struct ssol_scene* scn, const struct s3d_hit* hit); +extern LOCAL_SYM struct ssol_sun* +scene_get_sun + (struct ssol_scene* scn); + +extern LOCAL_SYM struct ssol_device* +scene_get_device + (struct ssol_scene* scn); + +extern LOCAL_SYM struct htable_instance* +scene_get_instances + (struct ssol_scene* scn); + #endif /* SSOL_SCENE_C_H */ diff --git a/src/ssol_solver.c b/src/ssol_solver.c @@ -20,15 +20,60 @@ #include "ssol_shape_c.h" #include "ssol_object_c.h" #include "ssol_sun_c.h" +#include "ssol_material_c.h" #include "ssol_spectrum_c.h" #include "ssol_object_instance_c.h" +#include "ssol_brdf_composite.h" #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> #include <rsys/rsys.h> +#include <rsys/double3.h> +#include <rsys/double44.h> #include <star/ssp.h> +enum realization_termination { + TERM_NONE, + TERM_SHADOW, + TERM_MISSING, + TERM_BLOCKED, + TERM_ERR, + + TERM_COUNT__ +}; + +enum realization_mode { + MODE_NONE, + MODE_STD, + MODE_ROULETTE, + + MODE_COUNT__ +}; + +struct segment { + double weight; + float range[2]; + struct s3d_hit hit; + /* TODO: use double? */ + float org[3], dir[4]; + float hit_pos[3]; +}; + +#include <rsys/dynamic_array.h> +#define DARRAY_DATA struct segment +#define DARRAY_NAME segment +#include <rsys/dynamic_array.h> + +struct realisation { + enum realization_termination end; + enum realization_mode mode; + struct darray_segment segments; + struct segment sun_segment; + double freq, final_weight; + size_t s_idx; +}; + /******************************************************************************* * Helper functions ******************************************************************************/ @@ -79,35 +124,6 @@ mat_3x4_to_4x4(const double* from, double* to) } } -static void -mat_4x4_mul(const double* a, const double* b, double* to) -{ - int r, c, k; - ASSERT(a && b && to); - - for (c = 0; c < 4; c++) { - for (r = 0; r < 4; r++) { - to[r * 4 + c] = 0; - for (k = 0; k < 4; k++) { - to[r * 4 + c] += a[r * 4 + k] * b[k * 4 + c]; - } - } - } -} - -static void -mat_4x4_transp(const double* from, double* to) -{ - int r, c, idx_f = 0, idx_t = 0; - ASSERT(from && to); - - for (c = 0; c < 4; c++) { - for (r = 0; r < 4; r++) { - to[15 - idx_t++] = from[idx_f++]; - } - } -} - static INLINE int is_instance_punched (const struct ssol_object_instance* instance) @@ -116,8 +132,6 @@ is_instance_punched return instance->object->shape->type == SHAPE_PUNCHED; } -/* FIXME Dead code. Remove it? */ -#if 0 static const struct ssol_quadric* get_quadric (const struct ssol_object_instance* instance) { @@ -129,7 +143,7 @@ static struct s3d_scene* get_3dscene(const struct ssol_object_instance* instance) { ASSERT(instance); - return instance->object->shape->scene; + return instance->object->s3d_scn; } static const double* @@ -139,28 +153,6 @@ get_transform(const struct ssol_object_instance* instance) return instance->transform; } -static res_T -init_solver_data - (struct solver_data* data, - struct ssol_device* dev) -{ - res_T res = RES_OK; - if (!data || !dev) return RES_BAD_ARG; - - data->dev = dev; - darray_quadric_init(dev->allocator, &data->quadrics); - darray_3dshape_init(dev->allocator, &data->shapes); - res = ssp_ranst_piecewise_linear_create(dev->allocator, &data->sun_spectrum_ran); - if (res != RES_OK) return res; - res = ssol_ranst_sun_dir_create(dev->allocator, &data->sun_dir_ran); - if (res != RES_OK) { - SSP(ranst_piecewise_linear_ref_put(data->sun_spectrum_ran)); - return res; - } - return res; -} -#endif - /******************************************************************************* * Local functions ******************************************************************************/ @@ -170,22 +162,29 @@ set_sun_distributions struct solver_data* data) { struct ssol_spectrum* spectrum; + struct ssol_device* dev; const double* frequencies; const double* intensities; res_T res = RES_OK; size_t sz; if (!sun || !data) return RES_BAD_ARG; - ASSERT(data->dev && data->dev->allocator); + ASSERT(data->scene); + dev = scene_get_device(data->scene); + ASSERT(dev && dev->allocator); /* first set the spectrum distribution */ + res = ssp_ranst_piecewise_linear_create(dev->allocator, &data->sun_spectrum_ran); + if (res != RES_OK) goto error; spectrum = sun->spectrum; frequencies = darray_double_cdata_get(&spectrum->frequencies); intensities = darray_double_cdata_get(&spectrum->intensities); sz = darray_double_size_get(&spectrum->frequencies); res = ssp_ranst_piecewise_linear_setup (data->sun_spectrum_ran, frequencies, intensities, sz); - if (res != RES_OK) return res; + if (res != RES_OK) goto error; /* then the direction distribution */ + res = ranst_sun_dir_create(dev->allocator, &data->sun_dir_ran); + if (res != RES_OK) goto error; switch (sun->type) { case SUN_DIRECTIONAL: res = ranst_sun_dir_dirac_setup(data->sun_dir_ran, sun->direction); @@ -203,7 +202,18 @@ set_sun_distributions FATAL("Unreachable code \n"); } +exit: return res; +error: + if (data->sun_spectrum_ran) { + SSP(ranst_piecewise_linear_ref_put(data->sun_spectrum_ran)); + data->sun_spectrum_ran = NULL; + } + if (data->sun_dir_ran) { + ASSERT(ranst_sun_dir_ref_put(data->sun_dir_ran) == RES_OK); + data->sun_dir_ran = NULL; + } + goto exit; } /* Implementation notes: @@ -281,34 +291,48 @@ quadric_transform /* transform */ quadric_to_mat4x4(tr, quadric44); mat_3x4_to_4x4(transform, transform44); - mat_4x4_transp(transform44, transp); - mat_4x4_mul(transp, quadric44, tmp); - mat_4x4_mul(tmp, transform44, quadric44); + d44_transpose(transp, transform44); + d44_muld44(tmp, transp, quadric44); + d44_muld44(quadric44, tmp, transform44); mat4x4_to_quadric(quadric44, tr); return RES_OK; } #if 0 res_T -process_instances - (const struct ssol_scene* scene, - struct solver_data* data) +process_instances(struct solver_data* data) { - struct list_node* node; + struct ssol_scene* scene; + struct ssol_device* dev; + struct htable_instance* instances; + size_t i_count; + struct htable_instance_iterator it, end; int i; float tr[12]; res_T res = RES_OK; - if (!scene || !data) - return RES_BAD_ARG; - darray_3dshape_reserve(&data->shapes, scene->instances_count); + if (!data) return RES_BAD_ARG; + scene = data->scene; + ASSERT(scene); + dev = scene_get_device(scene); + ASSERT(dev && dev->allocator); + darray_quadric_init(dev->allocator, &data->quadrics); + darray_3dshape_init(dev->allocator, &data->shapes); + instances = scene_get_instances(scene); + i_count = htable_instance_size_get(instances); + res = darray_3dshape_reserve(&data->shapes, i_count); + if (res != RES_OK) goto error; /* create the main scene */ - res = s3d_scene_create(0, &data->scene); + res = s3d_scene_create(0, &data->scene3d); if (res != RES_OK) goto error; - LIST_FOR_EACH(node, &scene->instances) { - struct ssol_object_instance* instance = CONTAINER_OF - (node, struct ssol_object_instance, scene_attachment); + htable_instance_end(instances, &end); + for (htable_instance_begin(instances, &it); + htable_instance_iterator_eq(&it, &end); + htable_instance_iterator_next(&it)) + { + struct ssol_object_instance* instance + = *htable_instance_iterator_data_get(&it); struct s3d_scene* scene3D; struct s3d_shape* shape3D; const double* transform = get_transform(instance); @@ -316,20 +340,22 @@ process_instances const struct ssol_quadric* quadric = get_quadric(instance); struct ssol_quadric transformed; quadric_transform(quadric, transform, &transformed); - darray_quadric_push_back(&data->quadrics, &transformed); + res = darray_quadric_push_back(&data->quadrics, &transformed); + if (res != RES_OK) goto error; } /* instantiate each s3d_scene as a s3d_shape */ scene3D = get_3dscene(instance); res = s3d_scene_instantiate(scene3D, &shape3D); if (res != RES_OK) goto error; /* apply transform */ - FOR_EACH(i, 0, 12) tr[i] = (float)transform[i]; + FOR_EACH(i, 0, 12) tr[i] = (float) transform[i]; res = s3d_instance_set_transform(shape3D, tr); if (res != RES_OK) goto error; - darray_3dshape_push_back(&data->shapes, &shape3D); + res = darray_3dshape_push_back(&data->shapes, &shape3D); + if (res != RES_OK) goto error; /* and attach it to the main scene */ - res = s3d_scene_attach_shape(data->scene, shape3D); + res = s3d_scene_attach_shape(data->scene3d, shape3D); if (res != RES_OK) goto error; } @@ -338,8 +364,261 @@ exit: error: darray_quadric_release(&data->quadrics); darray_3dshape_release(&data->shapes); - S3D(scene_clear(data->scene)); - S3D(scene_ref_put(data->scene)); + if (data->scene3d) { + S3D(scene_clear(data->scene3d)); + S3D(scene_ref_put(data->scene3d)); + data->scene3d = NULL; + } goto exit; } #endif + +static res_T +init_solver_data + (struct ssol_scene* scene, + struct solver_data* data) +{ + res_T res = RES_OK; + const struct ssol_sun* sun; + struct s3d_scene* scene3d; + if (!data || !scene) return RES_BAD_ARG; + + sun = scene_get_sun(scene); + ASSERT(sun); + data->scene = scene; + /* create geometry-related data */ + /* res = process_instances(data); */ + if (res != RES_OK) goto error; + /* create sun distributions */ + res = set_sun_distributions(sun, data); + if (res != RES_OK) goto error; + scene3d = scene_get_s3d_scene(scene); + S3D(scene_begin_session(scene3d, S3D_TRACE)); + +exit: + return res; +error: + goto exit; +} + +struct segment* +current_segment(struct realisation* rz) +{ + ASSERT(rz); + ASSERT(rz->s_idx < darray_segment_size_get(&rz->segments)); + return darray_segment_data_get(&rz->segments) + rz->s_idx; +} + +res_T +next_segment(struct realisation* rz) +{ + ASSERT(rz); + ++rz->s_idx; + if (rz->s_idx >= darray_segment_size_get(&rz->segments)) + return darray_segment_resize(&rz->segments, rz->s_idx + 1); + return RES_OK; +} + +void +reset_realization(struct realisation* rz) +{ + ASSERT(rz); + rz->s_idx = 0; + rz->s_idx = 0; + rz->end = TERM_NONE; + rz->mode = MODE_STD; +} + +res_T +init_realization(struct mem_allocator* allocator, struct realisation* rz) +{ + ASSERT(rz); + darray_segment_init(allocator, &rz->segments); + /* set a first size; will grow up with time if needed */ + return darray_segment_resize(&rz->segments, 16); +} + +void +clear_realization(struct realisation* rz) +{ + ASSERT(rz); + darray_segment_clear(&rz->segments); +} + +/* TODO: move to Star3D */ +INLINE void s3d_invalidate_hit(struct s3d_hit* hit) { + ASSERT(hit); + hit->distance = FLT_MAX; +} + +void +reset_segment(struct segment* seg) +{ + ASSERT(seg); + seg->range[0] = 0; + seg->range[1] = FLT_MAX; + s3d_invalidate_hit(&seg->hit); +} + +struct ssol_material* +get_material_from_hit(struct ssol_scene* scene, struct s3d_hit* hit) { + struct ssol_object_instance* instance; + struct ssol_object* object; + struct ssol_material* material; + ASSERT(scene && hit); + instance = scene_get_object_instance_from_s3d_hit(scene, hit); + ASSERT(instance); + object = object_instance_get_object(instance); + ASSERT(object); + material = object_get_material(object); + ASSERT(material); + return material; +} + +res_T +ssol_solve + (struct ssol_scene* scene, + struct ssp_rng* rng, + const size_t realisations_count, + FILE* output) +{ + struct solver_data data; + struct s3d_scene* s3d_scn = NULL; + struct s3d_scene* s3d_sampling_scn = NULL; + struct brdf_composite* brdfs = NULL; + struct s3d_primitive primitive; + struct s3d_attrib attrib; + float uv[2]; + const struct ssol_sun* sun = NULL; + struct realisation rz; + size_t r; + double _dir[3]; + res_T res = RES_OK; + + struct ssol_device* device = NULL; + + if (!scene || !rng || !output || !realisations_count) + return RES_BAD_ARG; + + /* init realization */ + device = scene_get_device(scene); + ASSERT(device && device->allocator); + res = init_realization(device->allocator, &rz); + if (res != RES_OK) goto error; + + res = brdf_composite_create(device, &brdfs); + if (res != RES_OK) goto error; + + /* init scene representation data */ + res = init_solver_data(scene, &data); + if (res != RES_OK) goto error; + + s3d_scn = scene_get_s3d_scene(scene); + s3d_sampling_scn = scene_get_s3d_sampling_scn(scene); + sun = scene_get_sun(scene); + rz.sun_segment.weight = ssol_sun_get_dni(sun); + for (r = 0; r < realisations_count; r++) { + struct segment* prev = NULL; + struct segment* seg = &rz.sun_segment; + struct surface_fragment fragment; + float r1, r2, r3; + float sundir[3]; + float normal[3]; + /* reset realization */ + reset_realization(&rz); + + /* sample a point on the reflectors */ + r1 = ssp_rng_canonical_float(rng); + r2 = ssp_rng_canonical_float(rng); + r3 = ssp_rng_canonical_float(rng); + S3D(scene_sample(s3d_sampling_scn, r1, r2, r3, &primitive, uv)); + S3D(primitive_get_attrib(&primitive, S3D_POSITION, uv, &attrib)); + CHECK(attrib.type, S3D_FLOAT3); + + /* sample an input dir from the sun */ + ranst_sun_dir_get(data.sun_dir_ran, rng, _dir); + + /* setup sun segment in the reverse direction to detect shadows */ + reset_segment(seg); + f3_set(seg->org, attrib.value); + f3_set_d3(sundir, _dir); + f3_mulf(seg->dir, sundir, -1); + CHECK(f3_is_normalized(seg->dir), 1); + + /* sample a frequency */ + rz.freq = ssp_ranst_piecewise_linear_get(data.sun_spectrum_ran, rng); + + /* check if the point receives sunlight */ + /* TODO: need only an occlusion test */ + S3D(scene_trace_ray(s3d_scn, seg->org, seg->dir, seg->range, NULL, &seg->hit)); + if (!S3D_HIT_NONE(&seg->hit)) { + rz.final_weight = 0; + rz.end = TERM_SHADOW; + } + + /* fill fragment from starting point */ + S3D(primitive_get_attrib(&primitive, S3D_GEOMETRY_NORMAL, uv, &attrib)); + CHECK(attrib.type, S3D_FLOAT3); + f3_set(normal, attrib.value); + surface_fragment_setup(&fragment, seg->org, sundir, normal, &primitive, uv); + + /* start propagating from rz.sun_segment.hit_pos */ + while (rz.end == TERM_NONE) { + struct ssol_material* material; + float tmp[3]; + + prev = seg; + seg = current_segment(&rz); + reset_segment(seg); + + /* the current segment starts at prev->hit_pos */ + f3_set(seg->org, prev->hit_pos); + + /* compute the output direction from the material */ + material = get_material_from_hit(scene, &prev->hit); + CHECK(material_get_type(material), MATERIAL_MIRROR); + res = material_shade(material, &fragment, rz.freq, brdfs); + if (res != RES_OK) { + rz.end = TERM_ERR; + goto error; + } + f3_set_d3(tmp, fragment.Ns); + seg->weight = prev->weight * + brdf_composite_sample(brdfs, rng, prev->dir, tmp, seg->dir); + + /* then check if the ray hits something */ + S3D(scene_trace_ray(s3d_scn, seg->org, seg->dir, seg->range, NULL, &seg->hit)); + if (S3D_HIT_NONE(&seg->hit)) { + rz.final_weight = 0; + rz.end = TERM_MISSING; + continue; + } + /* should not stop on a virtual surface */ + ASSERT(material_get_type(get_material_from_hit(scene, &seg->hit)) + != MATERIAL_VIRTUAL); + + /* fill fragment from hit and loop */ + f3_set(tmp, f3_add(tmp, seg->org, f3_mulf(tmp, seg->dir, seg->hit.distance))); + surface_fragment_setup(&fragment, tmp, seg->dir, seg->hit.normal, &seg->hit.prim, seg->hit.uv); + + /* continue propagation with next segment */ + res = next_segment(&rz); + if (res != RES_OK) { + rz.end = TERM_ERR; + goto error; + } + } + rz.final_weight = seg->weight; + + fprintf(output, "%d %g %g\n", rz.end, rz.final_weight, rz.freq); + continue; + } + + exit: + /* TODO: release data */ + S3D(scene_end_session(s3d_scn)); + clear_realization(&rz); + return res; +error: + goto exit; +} diff --git a/src/ssol_solver_c.h b/src/ssol_solver_c.h @@ -33,27 +33,28 @@ #include <rsys/dynamic_array.h> struct solver_data { - struct ssol_device* dev; + struct ssol_scene* scene; /* data comming from instances of the scene */ struct darray_quadric quadrics; struct darray_3dshape shapes; /* the 3D scene used for raytracing */ - struct s3d_scene *scene; + struct s3d_scene* scene3d; /* the random distributions for sun sampling */ struct ranst_sun_dir* sun_dir_ran; struct ssp_ranst_piecewise_linear* sun_spectrum_ran; }; +/* TODO: refcount management for data */ + extern LOCAL_SYM res_T set_sun_distributions -(const struct ssol_sun* sun, - struct solver_data* data); + (const struct ssol_sun* sun, + struct solver_data* data); #if 0 extern LOCAL_SYM res_T process_instances - (const struct ssol_scene* scene, - struct solver_data* data); + (struct solver_data* data); #endif /* transform a single quadric in world space */ diff --git a/src/ssol_sun_c.h b/src/ssol_sun_c.h @@ -48,4 +48,10 @@ struct ssol_sun { ref_T ref; }; +extern INLINE double +ssol_sun_get_dni(const struct ssol_sun* sun) { + ASSERT(sun); + return sun->dni; +} + #endif /* SSOL_SUN_C_H */ diff --git a/src/test_ssol_solver.c b/src/test_ssol_solver.c @@ -19,6 +19,9 @@ #include "ssol_solver_c.h" #include <rsys/logger.h> +#include <rsys/double3.h> + +#include <star/ssp.h> /******************************************************************************* * test main program @@ -29,6 +32,13 @@ 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_sun* sun; + struct ssol_spectrum* spectrum; + double dir[3]; + double frequencies[3] = { 1, 2, 3 }; + double intensities[3] = { 1, 0.8, 1 }; (void) argc, (void) argv; mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -40,8 +50,30 @@ main(int argc, char** argv) 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, 0, 0, -10)), 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); + + /* TODO: create a scene */ + + 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_OK); CHECK(ssol_device_ref_put(dev), RES_OK); + CHECK(ssol_scene_clear(scene), RES_OK); + CHECK(ssp_rng_ref_put(rng), RES_OK); + CHECK(ssol_spectrum_ref_put(spectrum), RES_OK); + CHECK(ssol_scene_detach_sun(scene, sun), RES_OK); + CHECK(ssol_sun_ref_put(sun), RES_OK); logger_release(&logger);