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 b721aaa2cb44aab8efc5835d3cdec769e32f9651
parent 9f0d3be7042c3d74306d64e9d1581e3bc607dee7
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed,  9 Sep 2015 15:37:31 +0200

Begin the implementation of the scene sampling

Compute the CDF of the scene surface area

Diffstat:
Msrc/s3d_instance.c | 64++++++++++++++++++++++++++++++++++++++++++++++------------------
Msrc/s3d_instance.h | 9+++++++++
Msrc/s3d_mesh.c | 67++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msrc/s3d_mesh.h | 9+++++++++
Msrc/s3d_scene.c | 67++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/s3d_scene_c.h | 1+
6 files changed, 177 insertions(+), 40 deletions(-)

diff --git a/src/s3d_instance.c b/src/s3d_instance.c @@ -50,6 +50,7 @@ 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)); } @@ -72,6 +73,7 @@ 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; @@ -135,19 +137,52 @@ instance_compute_area(struct instance* inst) LIST_FOR_EACH(node, &inst->scene->shapes) { struct s3d_shape* shape = CONTAINER_OF (node, struct s3d_shape, scene_attachment); - switch(shape->type) { - case GEOM_INSTANCE: - area += instance_compute_area(shape->data.instance); - break; - case GEOM_MESH: - area += mesh_compute_area(shape->data.mesh); - break; - default: FATAL("Unreachable code\n"); break; - } + ASSERT(shape->type == GEOM_MESH); /* One instancing level is supported */ + area += mesh_compute_area(shape->data.mesh); } 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) { @@ -160,15 +195,8 @@ instance_compute_volume(struct instance* inst, const char flip_surface) struct s3d_shape* shape = CONTAINER_OF (node, struct s3d_shape, scene_attachment); const char flip = flip_surface ^ shape->flip_surface; - switch(shape->type) { - case GEOM_INSTANCE: - volume += instance_compute_volume(shape->data.instance, flip); - break; - case GEOM_MESH: - volume += mesh_compute_volume(shape->data.mesh, flip); - break; - default: FATAL("Unreachable code\n"); break; - } + ASSERT(shape->type == GEOM_MESH); /* One instancing level is supported */ + volume += mesh_compute_volume(shape->data.mesh, flip); } return volume; } diff --git a/src/s3d_instance.h b/src/s3d_instance.h @@ -34,12 +34,15 @@ #define S3D_INSTANCE_H #include "s3d_geometry.h" +#include <rsys/dynamic_array_float.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; }; @@ -64,6 +67,12 @@ 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 @@ -207,6 +207,28 @@ mesh_setup_attribs } } +static FINLINE float +mesh_compute_triangle_2area(struct mesh* mesh, const size_t itri) +{ + const uint32_t* ids; + const float* pos; + const float* v0, *v1, *v2; + const size_t id = itri * 3/*#ids per faces*/; + float E0[3], E1[3], N[3]; + ASSERT(mesh && itri < mesh_get_ntris(mesh)); + + ids = mesh_get_ids(mesh); + pos = mesh_get_pos(mesh); + + v0 = pos + ids[id+0]*3/*#coords*/; + v1 = pos + ids[id+1]*3/*#coords*/; + v2 = pos + ids[id+2]*3/*#coords*/; + f3_sub(E0, v1, v0); + f3_sub(E1, v2, v0); + + return f3_len(f3_cross(N, E0, E1)); +} + static void mesh_release(ref_T* ref) { @@ -217,6 +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); MEM_RM(dev->allocator, mesh); S3D(device_ref_put(dev)); } @@ -239,6 +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); exit: *out_mesh = mesh; @@ -280,6 +304,9 @@ mesh_clear(struct mesh* mesh) mesh->attribs[iattr] = NULL; } } + mesh->resize_mask = 0; + mesh->update_mask = 0; + darray_float_clear(&mesh->triangle_2area_ucdf); } size_t @@ -333,8 +360,6 @@ mesh_get_attr(struct mesh* mesh, const enum s3d_attrib_usage usage) float mesh_compute_area(struct mesh* mesh) { - const uint32_t* ids; - const float* pos; size_t itri, ntris; float area = 0.f; ASSERT(mesh); @@ -342,20 +367,36 @@ mesh_compute_area(struct mesh* mesh) ntris = mesh_get_ntris(mesh); if(!ntris) return 0.f; - ids = mesh_get_ids(mesh); - pos = mesh_get_pos(mesh); + FOR_EACH(itri, 0, ntris) + area += mesh_compute_triangle_2area(mesh, itri); + return area * 0.5f; +} + +res_T +mesh_compute_triangle_2area_ucdf(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); + + ntris = mesh_get_ntris(mesh); + if(!ntris) goto exit; + + res = darray_float_resize(&mesh->triangle_2area_ucdf, ntris); + if(res != RES_OK) goto error; FOR_EACH(itri, 0, ntris) { - float E0[3], E1[3], N[3]; - const size_t id = itri * 3/*#ids per faces*/; - const float* v0 = pos + ids[id+0]*3/*#coords*/; - const float* v1 = pos + ids[id+1]*3/*#coords*/; - const float* v2 = pos + ids[id+2]*3/*#coords*/; - f3_sub(E0, v1, v0); - f3_sub(E1, v2, v0); - area += f3_len(f3_cross(N, E0, E1)) * 0.5f; + area += mesh_compute_triangle_2area(mesh, itri); + darray_float_data_get(&mesh->triangle_2area_ucdf)[itri] = area; } - return area; +exit: + return res; +error: + darray_float_clear(&mesh->triangle_2area_ucdf); + goto exit; } float diff --git a/src/s3d_mesh.h b/src/s3d_mesh.h @@ -61,6 +61,10 @@ 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; + int resize_mask; /* Combination of buffer_type */ int update_mask; /* Combination of buffer_type */ struct s3d_device* dev; @@ -109,6 +113,11 @@ extern LOCAL_SYM float mesh_compute_area (struct mesh* mesh); +/* Compute the *unormalized* CDF of the mesh triangles */ +extern LOCAL_SYM res_T +mesh_compute_triangle_2area_ucdf + (struct mesh* mesh); + extern LOCAL_SYM float mesh_compute_volume (struct mesh* mesh, diff --git a/src/s3d_scene.c b/src/s3d_scene.c @@ -132,8 +132,7 @@ scene_session_clear(struct s3d_scene* scn) static res_T scene_register_mesh (struct s3d_scene* scn, - struct s3d_shape* shape, - const int session_mask) + struct s3d_shape* shape) { struct geometry** pgeom = NULL; struct geometry* geom = NULL; @@ -169,11 +168,11 @@ scene_register_mesh goto exit; } - /* Define which Embree geometry buffer must be updated */ + /* Define which geometry buffers were updated */ upd_ids = geom->data.mesh->indices != shape->data.mesh->indices || ((shape->data.mesh->update_mask & INDEX_BUFFER) != 0); upd_pos = geom->data.mesh->attribs[S3D_POSITION] != shape->data.mesh->attribs[S3D_POSITION] - || ((shape->data.mesh->update_mask == VERTEX_BUFFER) != 0); + || ((shape->data.mesh->update_mask & VERTEX_BUFFER) != 0); /* Get a reference onto the shape mesh indices */ if(geom->data.mesh->indices != shape->data.mesh->indices) { @@ -313,6 +312,7 @@ scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) struct geometry** pgeom; ASSERT(scn && shape && !is_list_empty(&shape->scene_attachment)); ASSERT(shape->type == GEOM_MESH || shape->type == GEOM_INSTANCE); + ASSERT(scn->session_mask == S3D_SESSION_NONE); pgeom = htable_geom_find(&scn->cached_geoms, &shape); if(pgeom) { /* Remove the cached shape mesh */ @@ -335,9 +335,52 @@ scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) } static res_T +scene_compute_2area_ucdf(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; + res_T res = RES_OK; + ASSERT(scn); + + scn->area = 0.f; + + 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; + + 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); + 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); + break; + default: FATAL("Unreachable code\n"); break; + } + if(res != RES_OK) goto error; + if(ucdf_len) scn->area += ucdf[ucdf_len - 1]; + } +exit: + return res; +error: + goto exit; +} + +static res_T scene_sync(struct s3d_scene* scn, const int session_mask) { struct list_node* node; + struct s3d_shape* shape; res_T res = RES_OK; ASSERT(scn); @@ -347,24 +390,30 @@ scene_sync(struct s3d_scene* scn, const int session_mask) } LIST_FOR_EACH(node, &scn->shapes) { - struct s3d_shape* shape = CONTAINER_OF - (node, struct s3d_shape, scene_attachment); + shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment); switch(shape->type) { case GEOM_INSTANCE: res = scene_register_instance(scn, shape, session_mask); break; case GEOM_MESH: - res = scene_register_mesh(scn, shape, session_mask); + res = scene_register_mesh(scn, shape); break; default: FATAL("Unreachable code\n"); break; } if(res != RES_OK) goto error; } - if(scn->is_rtc_scn_outdated) { + + if((session_mask & S3D_SESSION_SAMPLE) != 0) { + res = scene_compute_2area_ucdf(scn); + if(res != RES_OK) goto error; + } + + if((session_mask & S3D_SESSION_TRACE) != 0 && scn->is_rtc_scn_outdated) { rtcCommit(scn->rtc_scn); scn->is_rtc_scn_outdated = 0; } + scn->session_mask = session_mask; exit: @@ -579,7 +628,7 @@ s3d_scene_trace_ray return RES_BAD_ARG; if(!f3_is_normalized(dir)) return RES_BAD_ARG; - if(scn->session_mask == S3D_SESSION_NONE) + if((scn->session_mask & S3D_SESSION_TRACE) == 0) return RES_BAD_OP; if(range[0] > range[1]) { *hit = S3D_HIT_NULL; diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h @@ -73,6 +73,7 @@ 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;