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 9a3eeb57fdb532847e1a6fab02fa76d3c26baed7
parent b6d9b307a4c735229076f321d9c8fdd9ad484dbe
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Thu, 10 Sep 2015 16:27:30 +0200

Add and test the s3d_scene_get_primitive function

Add the S3D_GET_PRIMITIVE session flag that allows to get a given
primitive onto the scene.

Diffstat:
Msrc/s3d.h | 15++++++++++++---
Msrc/s3d_mesh.c | 1-
Msrc/s3d_scene.c | 220+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Msrc/s3d_scene_c.h | 7+++++++
Msrc/test_s3d_cbox.h | 5+++++
Msrc/test_s3d_scene.c | 25++++++++++++++++++++-----
Msrc/test_s3d_trace_ray.c | 25++++++++++++++++++-------
7 files changed, 249 insertions(+), 49 deletions(-)

diff --git a/src/s3d.h b/src/s3d.h @@ -95,7 +95,7 @@ enum s3d_transform_space { * value. They can be used in conjunction with a dynamic array to map from s3d * geometry to application geometry */ struct s3d_primitive { - unsigned prim_id; /* Primitive identifer */ + unsigned prim_id; /* Primitive identifier */ unsigned geom_id; /* Geometry identifier */ unsigned inst_id; /* Instance identifier */ /* Internal data. Should not be accessed */ @@ -157,7 +157,8 @@ static const struct s3d_hit S3D_HIT_NULL = enum s3d_session_flag { S3D_TRACE = BIT(0), - S3D_SAMPLE = BIT(1) + S3D_SAMPLE = BIT(1), + S3D_GET_PRIMITIVE = BIT(2) }; /* Helper macro that defines whether or not the hit is valid, i.e. the ray @@ -300,10 +301,18 @@ s3d_scene_trace_rays S3D_API res_T s3d_scene_sample (struct s3d_scene* scn, - const float u, const float v, const float w, + const float u, const float v, const float w, /* in [0, 1) */ struct s3d_primitive* primitive, /* sampled primitive */ float uv[2]); +/* Retrieve a primitive from the scene. Can be called only if an S3D_SAMPLE + * session is active on `scn'*/ +S3D_API res_T +s3d_scene_get_primitive + (struct s3d_scene* scn, + const unsigned iprim, /* in [0, #prims) */ + struct s3d_primitive* prim); + /* Retrieve the number of scene primitives */ S3D_API res_T s3d_scene_primitives_count diff --git a/src/s3d_mesh.c b/src/s3d_mesh.c @@ -439,7 +439,6 @@ mesh_compute_volume(struct mesh* mesh, const char flip_surface) if(volume < 0.0 && volume > 3.e-6) volume = 0; - ASSERT(volume >= 0.0); return (float)(volume / 3.0); } diff --git a/src/s3d_scene.c b/src/s3d_scene.c @@ -366,8 +366,6 @@ scene_compute_cdf(struct s3d_scene* scn) 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: @@ -377,12 +375,12 @@ scene_compute_cdf(struct s3d_scene* scn) 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; } + fltui.ui = geom->irtc; + fltui.flt = area; if(len) { res = darray_fltui_push_back(&scn->cdf, &fltui); if(res != RES_OK) goto error; @@ -391,13 +389,75 @@ scene_compute_cdf(struct s3d_scene* scn) exit: return res; error: + darray_fltui_clear(&scn->cdf); goto exit; } static FINLINE bool operator < (const struct fltui& it, const float val) { - return it.flt < val; + return it.flt <= val; /* TODO commen the <= */ +} + +static res_T +scene_compute_nprims_cdf(struct s3d_scene* scn) +{ + struct list_node* node; + struct s3d_shape* shape; + struct geometry** pgeom; + struct geometry* geom; + size_t len; + unsigned nprims; + res_T res = RES_OK; + ASSERT(scn); + + darray_nprims_cdf_clear(&scn->nprims_cdf); + + nprims = 0; + 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 nprims_cdf cdf; + + if(!geom->is_enabled) continue; + + switch(geom->type) { + case GEOM_MESH: + len = mesh_get_ntris(geom->data.mesh); + nprims += (unsigned)len; + break; + case GEOM_INSTANCE: + res = scene_compute_nprims_cdf(geom->data.instance->scene); + if(res != RES_OK) goto error; + len = darray_nprims_cdf_size_get(&geom->data.instance->scene->nprims_cdf); + if(len) { + nprims += darray_nprims_cdf_cdata_get + (&geom->data.instance->scene->nprims_cdf)[len - 1].nprims; + } + break; + default: FATAL("Unreachable code\n"); break; + } + + cdf.nprims = nprims; + cdf.irtc = geom->irtc; + if(len) { + res = darray_nprims_cdf_push_back(&scn->nprims_cdf, &cdf); + if(res != RES_OK) goto error; + } + } +exit: + return res; +error: + darray_nprims_cdf_clear(&scn->nprims_cdf); + goto exit; +} + +static FINLINE bool +operator < (const struct nprims_cdf& it, const unsigned iprim) +{ + return it.nprims <= iprim; /* TODO comment the <= */ } static res_T @@ -442,17 +502,18 @@ scene_sync(struct s3d_scene* scn, const int session_mask) if(res != RES_OK) goto error; } - if((session_mask & S3D_SAMPLE) != 0) { res = scene_compute_cdf(scn); if(res != RES_OK) goto error; } - + if((session_mask & S3D_GET_PRIMITIVE) != 0) { + res = scene_compute_nprims_cdf(scn); + if(res != RES_OK) goto error; + } if((session_mask & S3D_TRACE) != 0 && scn->is_rtc_scn_outdated) { rtcCommit(scn->rtc_scn); scn->is_rtc_scn_outdated = 0; } - scn->session_mask = session_mask; exit: @@ -475,6 +536,7 @@ scene_release(ref_T* ref) htable_geom_release(&scn->cached_geoms); darray_geom_release(&scn->embree2geoms); darray_fltui_release(&scn->cdf); + darray_nprims_cdf_release(&scn->nprims_cdf); MEM_RM(dev->allocator, scn); S3D(device_ref_put(dev)); } @@ -502,6 +564,7 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn) htable_geom_init(dev->allocator, &scn->cached_geoms); darray_geom_init(dev->allocator, &scn->embree2geoms); darray_fltui_init(dev->allocator, &scn->cdf); + darray_nprims_cdf_init(dev->allocator, &scn->nprims_cdf); ref_init(&scn->ref); S3D(device_ref_get(dev)); scn->dev = dev; @@ -633,7 +696,9 @@ s3d_scene_begin_session(struct s3d_scene* scn, const int session_mask) { if(!scn) return RES_BAD_ARG; - if(!(session_mask&S3D_TRACE) && !(session_mask&S3D_SAMPLE)) + if(!(session_mask&S3D_TRACE) + && !(session_mask&S3D_SAMPLE) + && !(session_mask&S3D_GET_PRIMITIVE)) return RES_BAD_ARG; return scene_sync(scn, session_mask); } @@ -834,11 +899,12 @@ s3d_scene_sample geom = darray_geom_data_get(&scn->embree2geoms)[igeom]; ASSERT(geom); - if(geom->type != GEOM_INSTANCE) { + if(geom->type == GEOM_MESH) { primitive->inst__ = NULL; primitive->inst_id = S3D_INVALID_ID; } else { /* Find the sampled instantiated geometry */ + ASSERT(geom->type == GEOM_INSTANCE); primitive->inst__ = geom; primitive->inst_id = geom->name; if(darray_fltui_size_get(&geom->data.instance->scene->cdf) == 1) { @@ -882,13 +948,89 @@ error: } res_T -s3d_scene_primitives_count(struct s3d_scene* scn, size_t* prims_count) +s3d_scene_get_primitive + (struct s3d_scene* scn, const unsigned iprim, struct s3d_primitive* prim) { - struct list_node* node; - struct s3d_shape* shape; - struct geometry** pgeom; struct geometry* geom; - size_t inst_count; + const struct nprims_cdf* begin, *end, *found; + size_t nprims; + size_t igeom; + size_t i; + res_T res = RES_OK; + + if(!scn || !prim) { + res = RES_BAD_ARG; + goto error; + } + if((scn->session_mask & S3D_GET_PRIMITIVE) == 0) { + res = RES_BAD_OP; + goto error; + } + S3D(scene_primitives_count(scn, &nprims)); + if(iprim >= nprims) { + res = RES_BAD_ARG; + goto error; + } + + i = iprim; + if(darray_nprims_cdf_size_get(&scn->nprims_cdf) == 1) { + igeom = darray_nprims_cdf_cdata_get(&scn->nprims_cdf)[0].irtc; + } else { + begin = darray_nprims_cdf_cdata_get(&scn->nprims_cdf); + end = begin + darray_nprims_cdf_size_get(&scn->nprims_cdf); + found = std::lower_bound(begin, end, i); + ASSERT(found != end); + igeom = found->irtc; + if(found != begin) { + ASSERT(i >= found[-1].nprims); + i -= found[-1].nprims; + } + } + geom = darray_geom_data_get(&scn->embree2geoms)[igeom]; + ASSERT(geom); + + if(geom->type == GEOM_MESH) { + prim->inst__ = NULL; + prim->inst_id = S3D_INVALID_ID; + } else { + ASSERT(geom->type == GEOM_INSTANCE); + prim->inst__ = geom; + prim->inst_id = geom->name; + if(darray_nprims_cdf_size_get(&geom->data.instance->scene->nprims_cdf)==1) { + igeom = darray_nprims_cdf_cdata_get + (&geom->data.instance->scene->nprims_cdf)[0].irtc; + } else { + begin = darray_nprims_cdf_cdata_get + (&geom->data.instance->scene->nprims_cdf); + end = begin + darray_nprims_cdf_size_get + (&geom->data.instance->scene->nprims_cdf); + found = std::lower_bound(begin, end, i); + ASSERT(found != end); + igeom = found->irtc; + if(found != begin) { + ASSERT(i >= found[-1].nprims); + i -= found[-1].nprims; + } + } + geom = darray_geom_data_get + (&geom->data.instance->scene->embree2geoms)[igeom]; + ASSERT(geom); + } + ASSERT(geom->type == GEOM_MESH); + ASSERT(i < mesh_get_ntris(geom->data.mesh)); + prim->mesh__ = geom; + prim->geom_id = geom->name; + prim->prim_id = (unsigned)i; + +exit: + return res; +error: + goto exit; +} + +res_T +s3d_scene_primitives_count(struct s3d_scene* scn, size_t* prims_count) +{ res_T res = RES_OK; if(!scn || !prims_count) { @@ -899,28 +1041,40 @@ s3d_scene_primitives_count(struct s3d_scene* scn, size_t* prims_count) res = RES_BAD_OP; goto error; } + if((scn->session_mask & S3D_GET_PRIMITIVE) != 0) { + const size_t len = darray_nprims_cdf_size_get(&scn->nprims_cdf); + if(!len) { + *prims_count = 0; + } else { + *prims_count = darray_nprims_cdf_cdata_get(&scn->nprims_cdf)[len - 1].nprims; + } + } else { + struct list_node* node; + struct s3d_shape* shape; + struct geometry** pgeom; + struct geometry* geom; + size_t inst_count; + *prims_count = 0; + 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; - *prims_count = 0; - 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; - - if(!geom->is_enabled) continue; + if(!geom->is_enabled) continue; - switch(geom->type) { - case GEOM_MESH: - *prims_count += mesh_get_ntris(geom->data.mesh); - break; - case GEOM_INSTANCE: - S3D(scene_primitives_count(geom->data.instance->scene, &inst_count)); - *prims_count += inst_count; - break; - default: FATAL("Unreachable code\n"); break; + switch(geom->type) { + case GEOM_MESH: + *prims_count += mesh_get_ntris(geom->data.mesh); + break; + case GEOM_INSTANCE: + S3D(scene_primitives_count(geom->data.instance->scene, &inst_count)); + *prims_count += inst_count; + break; + default: FATAL("Unreachable code\n"); break; + } } } - exit: return res; error: diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h @@ -68,11 +68,18 @@ struct fltui { float flt; unsigned ui; }; #define DARRAY_DATA struct fltui #include <rsys/dynamic_array.h> +/* Generate the darray_geom_nprims array */ +struct nprims_cdf { unsigned nprims, irtc; }; +#define DARRAY_NAME nprims_cdf +#define DARRAY_DATA struct nprims_cdf +#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 */ + struct darray_nprims_cdf nprims_cdf; size_t instances_count; /* # instances in the scene */ diff --git a/src/test_s3d_cbox.h b/src/test_s3d_cbox.h @@ -54,6 +54,7 @@ static const float cbox_walls[] = { 0.f, 559.f, 548.f, 552.f, 559.f, 548.f }; +const unsigned cbox_walls_nverts = sizeof(cbox_walls) / sizeof(float[3]); const unsigned cbox_walls_ids[] = { 0, 1, 2, 2, 3, 0, /* Bottom */ @@ -62,6 +63,7 @@ const unsigned cbox_walls_ids[] = { 0, 3, 7, 7, 4, 0, /* Right */ 2, 3, 7, 7, 6, 2 /* Back */ }; +const unsigned cbox_walls_ntris = sizeof(cbox_walls_ids) / sizeof(unsigned[3]); static const struct cbox_desc cbox_walls_desc = { cbox_walls, cbox_walls_ids }; @@ -98,6 +100,9 @@ static const unsigned cbox_block_ids[] = { 0, 1, 5, 5, 4, 0 }; +const unsigned cbox_block_nverts = sizeof(cbox_short_block) / sizeof(float[3]); +const unsigned cbox_block_ntris = sizeof(cbox_block_ids) / sizeof(unsigned[3]); + /******************************************************************************* * Callbacks ******************************************************************************/ diff --git a/src/test_s3d_scene.c b/src/test_s3d_scene.c @@ -88,6 +88,7 @@ int main(int argc, char** argv) { struct mem_allocator allocator; + struct s3d_primitive prims[10]; struct s3d_device* dev; struct s3d_scene* scn; struct s3d_scene* scn2; @@ -96,8 +97,6 @@ main(int argc, char** argv) struct s3d_shape* shapes[4]; const size_t nshapes = sizeof(shapes)/sizeof(struct s3d_shape*); void* data = (void*)&cbox_walls_desc; - const unsigned cbox_ntris = sizeof(cbox_walls_ids) / sizeof(unsigned[3]); - const unsigned cbox_nverts = sizeof(cbox_walls) / sizeof(float[3]); size_t i; size_t nprims; float area, volume; @@ -226,8 +225,8 @@ main(int argc, char** argv) attribs[0].get = cbox_get_position; attribs[1] = S3D_VERTEX_DATA_NULL; CHECK(s3d_shape_create_mesh(dev, shapes + 0), RES_OK); - CHECK(s3d_mesh_setup_indexed_vertices - (shapes[0], cbox_ntris, cbox_get_ids, cbox_nverts, attribs, data), RES_OK); + CHECK(s3d_mesh_setup_indexed_vertices(shapes[0], cbox_walls_ntris, + cbox_get_ids, cbox_walls_nverts, attribs, data), RES_OK); CHECK(s3d_scene_attach_shape(scn, shapes[0]), RES_OK); CHECK(s3d_scene_begin_session(scn, S3D_TRACE), RES_OK); @@ -254,11 +253,27 @@ main(int argc, char** argv) CHECK(nprims, 10); CHECK(s3d_scene_end_session(scn2), RES_OK); - CHECK(s3d_scene_begin_session(scn2, S3D_SAMPLE), RES_OK); + CHECK(s3d_scene_begin_session(scn2, S3D_GET_PRIMITIVE), RES_OK); CHECK(s3d_scene_compute_area(scn2, &area), RES_OK); CHECK(eq_epsf(area, 1532296.f, 1.e-6f), 1); CHECK(s3d_scene_primitives_count(scn, &nprims), RES_OK); CHECK(nprims, 10); + + CHECK(s3d_scene_get_primitive(NULL, 11, NULL), RES_BAD_ARG); + CHECK(s3d_scene_get_primitive(scn2, 11, NULL), RES_BAD_ARG); + CHECK(s3d_scene_get_primitive(NULL, 0, NULL), RES_BAD_ARG); + CHECK(s3d_scene_get_primitive(scn2, 0, NULL), RES_BAD_ARG); + CHECK(s3d_scene_get_primitive(NULL, 11, prims + 0), RES_BAD_ARG); + CHECK(s3d_scene_get_primitive(scn2, 11, prims + 0), RES_BAD_ARG); + CHECK(s3d_scene_get_primitive(NULL, 0, prims + 0), RES_BAD_ARG); + + FOR_EACH(i, 0, nprims) { + size_t j; + CHECK(s3d_scene_get_primitive(scn2, (unsigned)i, prims + i), RES_OK); + CHECK(S3D_PRIMITIVE_EQ(prims + i, &S3D_PRIMITIVE_NULL), 0); + FOR_EACH(j, 0, i) + CHECK(S3D_PRIMITIVE_EQ(prims + i, prims + j), 0); + } CHECK(s3d_scene_end_session(scn2), RES_OK); attribs[0].type = S3D_FLOAT3; diff --git a/src/test_s3d_trace_ray.c b/src/test_s3d_trace_ray.c @@ -94,6 +94,7 @@ main(int argc, char** argv) struct s3d_shape* tall_block; struct s3d_shape* short_block; struct s3d_vertex_data attribs[4]; + struct s3d_primitive prims[30]; struct camera cam; struct cbox_desc desc; unsigned char* img = NULL; @@ -107,6 +108,7 @@ main(int argc, char** argv) unsigned walls_id; unsigned tall_block_id; unsigned short_block_id; + size_t i; mem_init_proxy_allocator(&allocator, &mem_default_allocator); @@ -123,8 +125,8 @@ main(int argc, char** argv) attribs[0].get = cbox_get_position; attribs[1] = S3D_VERTEX_DATA_NULL; - ntris = sizeof(cbox_walls_ids)/sizeof(unsigned[3]); - nverts = sizeof(cbox_walls)/sizeof(float[3]); + ntris = cbox_walls_ntris; + nverts = cbox_walls_nverts; desc.vertices = cbox_walls; desc.indices = cbox_walls_ids; CHECK(s3d_shape_create_mesh(dev, &walls), RES_OK); @@ -176,8 +178,8 @@ main(int argc, char** argv) CHECK(s3d_scene_clear(scn), RES_OK); /* Update the inst with the CBox tall block mesh */ - ntris = sizeof(cbox_block_ids)/sizeof(unsigned[3]); - nverts = sizeof(cbox_short_block)/sizeof(float[3]); + ntris = cbox_block_ntris; + nverts = cbox_block_nverts; desc.vertices = cbox_short_block; desc.indices = cbox_block_ids; CHECK(s3d_shape_create_mesh(dev, &tall_block), RES_OK); @@ -210,8 +212,8 @@ main(int argc, char** argv) /* Create the CBox walls */ desc.indices = cbox_walls_ids; desc.vertices = cbox_walls; - nverts = sizeof(cbox_walls)/sizeof(float[3]); - ntris = sizeof(cbox_walls_ids)/sizeof(unsigned[3]); + nverts = cbox_walls_nverts; + ntris = cbox_walls_ntris; CHECK(s3d_shape_create_mesh(dev, &walls), RES_OK); CHECK(s3d_shape_get_id(walls, &walls_id), RES_OK); CHECK(s3d_mesh_setup_indexed_vertices @@ -251,10 +253,19 @@ main(int argc, char** argv) CHECK(s3d_scene_attach_shape(scn, short_block), RES_OK); CHECK(s3d_scene_attach_shape(scn, tall_block), RES_OK); - CHECK(s3d_scene_begin_session(scn2, S3D_TRACE), RES_OK); + CHECK(s3d_scene_begin_session(scn2, S3D_TRACE|S3D_GET_PRIMITIVE), RES_OK); CHECK(s3d_scene_primitives_count(scn2, &nprims), RES_OK); CHECK(nprims, 30); + FOR_EACH(i, 0, nprims) { + size_t j; + CHECK(s3d_scene_get_primitive(scn2, (unsigned)i, prims + i), RES_OK); + CHECK(S3D_PRIMITIVE_EQ(prims + i, &S3D_PRIMITIVE_NULL), 0); + FOR_EACH(j, 0, i) { + CHECK(S3D_PRIMITIVE_EQ(prims + i, prims + j), 0); + } + } + camera_init(&cam); FOR_EACH(iy, 0, IMG_HEIGHT) { float pixel[2];