star-3d

Surface structuring for efficient 3D geometric queries
git clone git://git.meso-star.fr/star-3d.git
Log | Files | Refs | README | LICENSE

commit b33a8c751dc1ac008d96f7d6e6ff41bd1fe7cf78
parent b721aaa2cb44aab8efc5835d3cdec769e32f9651
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  9 Sep 2015 17:38:03 +0200

Implement the s3d_scene_sample function

Diffstat:
Msrc/s3d.h | 46++++++++--------------------------------------
Msrc/s3d_instance.c | 42------------------------------------------
Msrc/s3d_instance.h | 10+---------
Msrc/s3d_mesh.c | 16++++++++--------
Msrc/s3d_mesh.h | 8+++-----
Msrc/s3d_scene.c | 140++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Msrc/s3d_scene_c.h | 8+++++++-
7 files changed, 155 insertions(+), 115 deletions(-)

diff --git a/src/s3d.h b/src/s3d.h @@ -167,7 +167,6 @@ enum s3d_session_flag { /* Forward declaration of s3d opaque data types */ struct s3d_device; /* Entry point of the library */ -struct s3d_sampler; /* Random distribution of shape positions */ struct s3d_scene; /* Collection of shapes */ struct s3d_shape; /* Untyped geometry */ @@ -298,6 +297,14 @@ s3d_scene_trace_rays const float* ranges, /* List of 2D ray ranges. in [0, INF)^2 */ struct s3d_hit* hits); +/* TODO comment */ +S3D_API res_T +s3d_scene_sample + (struct s3d_scene* scene, + const float u, const float v, const float w, + struct s3d_primitive* primitive, /* sampled primitive */ + float uv[2]); + /******************************************************************************* * Shape API - A shape defines a geometry that can be attached to *one* scene. ******************************************************************************/ @@ -366,43 +373,6 @@ s3d_shape_compute_volume float* volume); /******************************************************************************* - * Sampler API - ******************************************************************************/ -S3D_API res_T -s3d_sampler_create - (struct s3d_shape* shape, - struct s3d_sampler** sampler); - -S3D_API res_T -s3d_sampler_ref_get - (struct s3d_sampler* sampler); - -S3D_API res_T -s3d_sampler_ref_put - (struct s3d_sampler* sampler); - -/* Synchronize the sampler geometry with the geometry of its attached shape. If - * a s3d_sampler_begin_sampling is already active on `sample' a RES_BAD_OP - * error is returned. On success no other begin samping can be invoked on - * `sampler' until s3d_sampler_end_sampling is called. A s3d_sampler_get - * operation can be invoked on `sampler' only between a - * s3d_sampler_begin_sampling and s3d_sampler_end_sampling call. */ -S3D_API res_T -s3d_sampler_begin_sampling - (struct s3d_sampler* sampler); - -S3D_API res_T -s3d_sampler_end_sampling - (struct s3d_sampler* sampler); - -S3D_API res_T -s3d_sampler_get - (struct s3d_sampler* sampler, - const float u, const float v, const float w, - struct s3d_primitive* primitive, /* sampled primitive */ - float uv[2]); - -/******************************************************************************* * Primitive API - Define a geometric primitive of a shape ******************************************************************************/ /* Retrieve the attribute of the shape primitive `iprim' at the barycentric diff --git a/src/s3d_instance.c b/src/s3d_instance.c @@ -50,7 +50,6 @@ instance_release(ref_T* ref) ASSERT(ref); inst = CONTAINER_OF(ref, struct instance, ref); scn = inst->scene; - darray_float_release(&inst->shape_2area_ucdf); MEM_RM(scn->dev->allocator, inst); S3D(scene_ref_put(scn)); } @@ -73,7 +72,6 @@ instance_create res = RES_MEM_ERR; goto error; } - darray_float_init(scn->dev->allocator, &inst->shape_2area_ucdf); f33_set_identity(inst->transform); /* rotation */ f3_splat(inst->transform + 9, 0.f); /* Translation */ inst->update_transform = 0; @@ -143,46 +141,6 @@ instance_compute_area(struct instance* inst) return area; } -res_T -instance_compute_shape_2area_ucdf - (struct instance* inst, const char use_cached_data) -{ - struct list_node* node; - size_t ntris; - float area = 0.f; - res_T res = RES_OK; - ASSERT(inst); - - /* TODO take into account the scale factor of the instance */ - LIST_FOR_EACH(node, &inst->scene->shapes) { - struct s3d_shape* shape = CONTAINER_OF - (node, struct s3d_shape, scene_attachment); - struct mesh* mesh; - ASSERT(shape->type == GEOM_MESH); /* One instancing level is supported */ - - if(!use_cached_data) { - mesh = shape->data.mesh; - } else { - struct geometry** pgeom; - pgeom = htable_geom_find(&inst->scene->cached_geoms, &shape); - ASSERT(pgeom); - mesh = (*pgeom)->data.mesh; - } - - res = mesh_compute_triangle_2area_ucdf(mesh); - if(res != RES_OK) goto error; - - ntris = mesh_get_ntris(mesh); - if(ntris) - area += darray_float_data_get(&mesh->triangle_2area_ucdf)[ntris-1]; - } -exit: - return res; -error: - darray_float_clear(&inst->shape_2area_ucdf); - goto exit; -} - float instance_compute_volume(struct instance* inst, const char flip_surface) { diff --git a/src/s3d_instance.h b/src/s3d_instance.h @@ -34,15 +34,13 @@ #define S3D_INSTANCE_H #include "s3d_geometry.h" -#include <rsys/dynamic_array_float.h> +#include <rsys/dynamic_array.h> #include <rsys/ref_count.h> struct instance { float transform[12]; /* local to world 3x4 column major matrix */ char update_transform; struct s3d_scene* scene; - /* Unormalized CDF of 2 times the instance shapes area */ - struct darray_float shape_2area_ucdf; ref_T ref; }; @@ -67,12 +65,6 @@ extern LOCAL_SYM float instance_compute_area (struct instance* inst); -/* Compute the *unormalized* CDF of 2 times the instantiated shapes area */ -extern LOCAL_SYM res_T -instance_compute_shape_2area_ucdf - (struct instance* inst, - const char use_session); /* Use session data */ - extern LOCAL_SYM float instance_compute_volume (struct instance* inst, diff --git a/src/s3d_mesh.c b/src/s3d_mesh.c @@ -239,7 +239,7 @@ mesh_release(ref_T* ref) mesh = CONTAINER_OF(ref, struct mesh, ref); mesh_clear(mesh); dev = mesh->dev; - darray_float_release(&mesh->triangle_2area_ucdf); + darray_float_release(&mesh->cdf); MEM_RM(dev->allocator, mesh); S3D(device_ref_put(dev)); } @@ -262,7 +262,7 @@ mesh_create(struct s3d_device* dev, struct mesh** out_mesh) ref_init(&mesh->ref); S3D(device_ref_get(dev)); mesh->dev = dev; - darray_float_init(dev->allocator, &mesh->triangle_2area_ucdf); + darray_float_init(dev->allocator, &mesh->cdf); exit: *out_mesh = mesh; @@ -306,7 +306,7 @@ mesh_clear(struct mesh* mesh) } mesh->resize_mask = 0; mesh->update_mask = 0; - darray_float_clear(&mesh->triangle_2area_ucdf); + darray_float_clear(&mesh->cdf); } size_t @@ -373,29 +373,29 @@ mesh_compute_area(struct mesh* mesh) } res_T -mesh_compute_triangle_2area_ucdf(struct mesh* mesh) +mesh_compute_cdf(struct mesh* mesh) { size_t itri, ntris; float area = 0.f; res_T res = RES_OK; ASSERT(mesh); - darray_float_clear(&mesh->triangle_2area_ucdf); + darray_float_clear(&mesh->cdf); ntris = mesh_get_ntris(mesh); if(!ntris) goto exit; - res = darray_float_resize(&mesh->triangle_2area_ucdf, ntris); + res = darray_float_resize(&mesh->cdf, ntris); if(res != RES_OK) goto error; FOR_EACH(itri, 0, ntris) { area += mesh_compute_triangle_2area(mesh, itri); - darray_float_data_get(&mesh->triangle_2area_ucdf)[itri] = area; + darray_float_data_get(&mesh->cdf)[itri] = area; } exit: return res; error: - darray_float_clear(&mesh->triangle_2area_ucdf); + darray_float_clear(&mesh->cdf); goto exit; } diff --git a/src/s3d_mesh.h b/src/s3d_mesh.h @@ -61,9 +61,7 @@ struct mesh { /* Triangular mesh */ struct index_buffer* indices; struct vertex_buffer* attribs[S3D_ATTRIBS_COUNT__]; enum s3d_type attribs_type[S3D_ATTRIBS_COUNT__]; - - /* Unormalized CDF of 2 times the triangles area */ - struct darray_float triangle_2area_ucdf; + struct darray_float cdf; int resize_mask; /* Combination of buffer_type */ int update_mask; /* Combination of buffer_type */ @@ -113,9 +111,9 @@ extern LOCAL_SYM float mesh_compute_area (struct mesh* mesh); -/* Compute the *unormalized* CDF of the mesh triangles */ +/* Compute mesh CDF */ extern LOCAL_SYM res_T -mesh_compute_triangle_2area_ucdf +mesh_compute_cdf (struct mesh* mesh); extern LOCAL_SYM float diff --git a/src/s3d_scene.c b/src/s3d_scene.c @@ -40,6 +40,8 @@ #include <rsys/mem_allocator.h> #include <rsys/mutex.h> +#include <algorithm> + /* Flag used to define session of enabled on instantiated scene */ #define S3D_SESSION_INSTANCE (BIT(sizeof(int)*8 - 1)) @@ -335,40 +337,52 @@ scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) } static res_T -scene_compute_2area_ucdf(struct s3d_scene* scn) +scene_compute_cdf(struct s3d_scene* scn) { struct list_node* node; struct s3d_shape* shape; struct geometry** pgeom; struct geometry* geom; - const float* ucdf; - size_t ucdf_len; + size_t len; + float area = 0.f; res_T res = RES_OK; ASSERT(scn); - scn->area = 0.f; + darray_fltui_clear(&scn->cdf); LIST_FOR_EACH(node, &scn->shapes) { shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment); pgeom = htable_geom_find(&scn->cached_geoms, &shape); ASSERT(pgeom != NULL); geom = *pgeom; + struct fltui fltui; switch(geom->type) { case GEOM_MESH: - res = mesh_compute_triangle_2area_ucdf(geom->data.mesh); - ucdf = darray_float_cdata_get(&geom->data.mesh->triangle_2area_ucdf); - ucdf_len = darray_float_size_get(&geom->data.mesh->triangle_2area_ucdf); + res = mesh_compute_cdf(geom->data.mesh); + if(res != RES_OK) goto error; + len = darray_float_size_get(&geom->data.mesh->cdf); + if(len) { + area += darray_float_cdata_get(&geom->data.mesh->cdf)[len - 1]; + fltui.ui = geom->irtc; + fltui.flt = area; + } break; case GEOM_INSTANCE: - res = instance_compute_shape_2area_ucdf(geom->data.instance, 1); - ucdf = darray_float_cdata_get(&geom->data.instance->shape_2area_ucdf); - ucdf_len = darray_float_size_get(&geom->data.instance->shape_2area_ucdf); + res = scene_compute_cdf(geom->data.instance->scene); + if(res != RES_OK) goto error; + len = darray_fltui_size_get(&geom->data.instance->scene->cdf); + if(len) { + area += darray_fltui_cdata_get + (&geom->data.instance->scene->cdf)[len - 1].flt; + fltui.ui = geom->irtc; + fltui.flt = area; + } break; default: FATAL("Unreachable code\n"); break; } + res = darray_fltui_push_back(&scn->cdf, &fltui); if(res != RES_OK) goto error; - if(ucdf_len) scn->area += ucdf[ucdf_len - 1]; } exit: return res; @@ -376,6 +390,12 @@ error: goto exit; } +static FINLINE bool +operator < (const struct fltui& it, const float val) +{ + return it.flt < val; +} + static res_T scene_sync(struct s3d_scene* scn, const int session_mask) { @@ -405,7 +425,7 @@ scene_sync(struct s3d_scene* scn, const int session_mask) } if((session_mask & S3D_SESSION_SAMPLE) != 0) { - res = scene_compute_2area_ucdf(scn); + res = scene_compute_cdf(scn); if(res != RES_OK) goto error; } @@ -435,6 +455,7 @@ scene_release(ref_T* ref) if(scn->rtc_scn) rtcDeleteScene(scn->rtc_scn); htable_geom_release(&scn->cached_geoms); darray_geom_release(&scn->embree2geoms); + darray_fltui_release(&scn->cdf); MEM_RM(dev->allocator, scn); S3D(device_ref_put(dev)); } @@ -461,6 +482,7 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn) list_init(&scn->shapes); htable_geom_init(dev->allocator, &scn->cached_geoms); darray_geom_init(dev->allocator, &scn->embree2geoms); + darray_fltui_init(dev->allocator, &scn->cdf); ref_init(&scn->ref); S3D(device_ref_get(dev)); scn->dev = dev; @@ -737,3 +759,97 @@ s3d_scene_trace_rays return res; } +res_T +s3d_scene_sample + (struct s3d_scene* scn, + const float u, + const float v, + const float w, + struct s3d_primitive* primitive, /* sampled primitive */ + float uv[2]) +{ + struct geometry* geom; + const struct fltui* fltui_begin, *fltui_end, *fltui_found; + const float* flt_begin, *flt_end, *flt_found; + size_t igeom; + double sqrt_v; + float f; + res_T res = RES_OK; + + if(!scn || !primitive || !uv) { + res = RES_BAD_ARG; + goto error; + } + /* Expecting canonic numbers */ + if(u < 0.f || u >= 1.f || v < 0.f || v >= 1.f || w < 0.f || w >= 1.f) { + res = RES_BAD_ARG; + goto error; + } + if((scn->session_mask & S3D_SESSION_SAMPLE) == 0) { + res = RES_BAD_OP; + goto error; + } + + /* Find the sampled geometry */ + if(darray_fltui_size_get(&scn->cdf) == 1) { + igeom = darray_fltui_cdata_get(&scn->cdf)[0].ui; + } else { + fltui_begin = darray_fltui_cdata_get(&scn->cdf); + fltui_end = fltui_begin + darray_fltui_size_get(&scn->cdf); + f = u * fltui_end[-1].flt; + fltui_found = std::lower_bound(fltui_begin, fltui_end, f); + ASSERT(fltui_found != fltui_end); + igeom = fltui_found->ui; + + if(fltui_found != fltui_begin) + f -= fltui_found[-1].flt; + } + geom = darray_geom_data_get(&scn->embree2geoms)[igeom]; + ASSERT(geom); + + if(geom->type != GEOM_INSTANCE) { + primitive->inst__ = NULL; + primitive->inst_id = S3D_INVALID_ID; + } else { + /* Find the sampled instantiated geometry */ + primitive->inst__ = geom; + primitive->inst_id = geom->name; + if(darray_fltui_size_get(&geom->data.instance->scene->cdf) == 1) { + igeom = darray_fltui_cdata_get(&geom->data.instance->scene->cdf)[0].ui; + } else { + fltui_begin = darray_fltui_cdata_get(&geom->data.instance->scene->cdf); + fltui_end = fltui_begin + darray_fltui_size_get(&geom->data.instance->scene->cdf); + fltui_found = std::lower_bound(fltui_begin, fltui_end, f); + ASSERT(fltui_found != fltui_end); + igeom = fltui_found->ui; + + if(fltui_found != fltui_begin) + f -= fltui_found[-1].flt; + } + geom = darray_geom_data_get + (&geom->data.instance->scene->embree2geoms)[igeom]; + ASSERT(geom); + } + ASSERT(geom->type == GEOM_MESH); + + /* Find the sampled triangle */ + primitive->mesh__ = geom; + primitive->geom_id = geom->name; + flt_begin = darray_float_cdata_get(&geom->data.mesh->cdf); + flt_end = flt_begin + darray_float_size_get(&geom->data.mesh->cdf); + flt_found = std::lower_bound(flt_begin, flt_end, f); + ASSERT(flt_found != flt_end); + + primitive->prim_id = (unsigned)(flt_found - flt_begin); + + /* Compute the sampled barycentric coordinate of the sampled primitive */ + sqrt_v = sqrt(v); + uv[0] = (float)(1.0 - sqrt_v); + uv[1] = (float)(w * sqrt_v); + +exit: + return res; +error: + goto exit; +} + diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h @@ -62,10 +62,17 @@ geom_ptr_init__(struct mem_allocator* alloc, struct geometry** geom) #define HTABLE_KEY struct s3d_shape* #include <rsys/hash_table.h> +/* Generate the darray_fltui dynamic array */ +struct fltui { float flt; unsigned ui; }; +#define DARRAY_NAME fltui +#define DARRAY_DATA struct fltui +#include <rsys/dynamic_array.h> + struct s3d_scene { struct list_node shapes; /* List of attached shapes */ struct htable_geom cached_geoms; /* Cached shape geometries */ struct darray_geom embree2geoms; /* Shape geometries index by embree id */ + struct darray_fltui cdf; /* Unormalized CDF */ size_t instances_count; /* # instances in the scene */ @@ -73,7 +80,6 @@ struct s3d_scene { char is_rtc_scn_outdated; /* Must the embree scene rebuild */ int session_mask; /* Combination of enum s3d_session_flag */ - float area; /* Overall scene surface area */ struct s3d_device* dev; ref_T ref;