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